Fixed slide images reaching the AI as raw Base64 data

This commit is contained in:
Thorsten Sommer 2026-08-10 19:58:39 +02:00
parent ea5efca69d
commit e739468a85
Signed by untrusted user who does not match committer: tsommer
GPG Key ID: 371BBA77A02C0108
4 changed files with 43 additions and 17 deletions

View File

@ -133,6 +133,31 @@ public static class ContentStreamSseHandler
return base64Image;
}
/// <summary>
/// Assembles the collected segments of an image into a Markdown image.
/// </summary>
/// <remarks>
/// Handing the naked Base64 data to the AI says nothing: it is neither readable text nor an
/// image it could look at. Only the data URI makes it one, so every reader must embed its
/// images this way.
/// </remarks>
/// <param name="id">The ID of the image to assemble.</param>
/// <param name="mediaType">The media type the runtime reported, if any.</param>
/// <returns>The Markdown image, or null when no data was collected for that ID.</returns>
public static string? BuildImageMarkdown(string id, string? mediaType)
{
var base64Image = BuildImage(id);
if (string.IsNullOrWhiteSpace(base64Image))
return null;
//
// Both readers compress their images, and that compression produces JPEG. A runtime which
// does not report the media type therefore delivered JPEG as well.
//
var imageMediaType = string.IsNullOrWhiteSpace(mediaType) ? "image/jpeg" : mediaType;
return $"![Image](data:{imageMediaType};base64,{base64Image})";
}
public static string? Clear(string streamId)
{
if (string.IsNullOrWhiteSpace(streamId))

View File

@ -31,12 +31,11 @@ public sealed class DocumentManager
if (ContentStreamSseHandler.ProcessImageSegment(image.Id, image))
{
var base64 = ContentStreamSseHandler.BuildImage(image.Id);
if (!string.IsNullOrWhiteSpace(base64))
var markdownImage = ContentStreamSseHandler.BuildImageMarkdown(image.Id, image.MediaType);
if (markdownImage is not null)
{
var mediaType = string.IsNullOrWhiteSpace(image.MediaType) ? "image/jpeg" : image.MediaType;
this.currentPageContent.AppendLine();
this.currentPageContent.AppendLine($"![Image](data:{mediaType};base64,{base64})");
this.currentPageContent.AppendLine(markdownImage);
}
}

View File

@ -1,8 +1,10 @@
using System.Text;
namespace AIStudio.Tools;
public sealed class SlideImageContent(string base64Image) : ISlideContent
/// <summary>
/// An image of a slide, ready to be appended to the slide's Markdown.
/// </summary>
/// <param name="markdownImage">The image as a Markdown image with an embedded data URI.</param>
public sealed class SlideImageContent(string markdownImage) : ISlideContent
{
public StringBuilder Base64Image => new(base64Image);
public string MarkdownImage => markdownImage;
}

View File

@ -52,9 +52,9 @@ public sealed class SlideManager
//
if (addImage)
{
var img = ContentStreamSseHandler.BuildImage(image!.Id!);
var slideImage = new SlideImageContent(img);
createdSlide.Content.Add(slideImage);
var markdownImage = ContentStreamSseHandler.BuildImageMarkdown(image!.Id!, image.MediaType);
if (markdownImage is not null)
createdSlide.Content.Add(new SlideImageContent(markdownImage));
}
this.slides[slideNumber] = createdSlide;
@ -75,9 +75,9 @@ public sealed class SlideManager
// Add any image content?
if (addImage)
{
var img = ContentStreamSseHandler.BuildImage(image!.Id!);
var slideImage = new SlideImageContent(img);
slide.Content.Add(slideImage);
var markdownImage = ContentStreamSseHandler.BuildImageMarkdown(image!.Id!, image.MediaType);
if (markdownImage is not null)
slide.Content.Add(new SlideImageContent(markdownImage));
}
}
}
@ -96,7 +96,7 @@ public sealed class SlideManager
foreach (var image in slide.Content.OfType<SlideImageContent>())
{
content.AppendLine(image.Base64Image.ToString());
content.AppendLine(image.MarkdownImage);
content.AppendLine();
}
}