Scaled down and converted images before sending them to AI models (#1101)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-10-22 10:57:04 +02:00
1 parent 1c8632bbe0
commit ba99bf6fae
33 files changed
+1550 -264

No files matched your search

@@ -59,18 +59,16 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, n
Text = text,
},
// Anthropic-specific image sub-content:
async attachment => new SubContentImage
// Anthropic-specific image sub-content, which takes the base64 and its type apart:
image => new SubContentImage
{
Source = new SubContentBase64Image
{
Data = await attachment.TryAsBase64(token: token) is (true, var base64Content)
? base64Content
: string.Empty,
MediaType = attachment.DetermineMimeType(),
Data = image.Base64,
MediaType = image.MimeType,
}
}
},
token
);
//
@@ -113,15 +113,14 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
{
Text = text,
},
async attachment => new SubContentImageUrlNested
image => new SubContentImageUrlNested
{
ImageUrl = new SubContentImageUrlData
{
Url = await attachment.TryAsBase64(token: token) is (true, var base64Content)
? $"data:{attachment.DetermineMimeType()};base64,{base64Content}"
: string.Empty,
Url = image.ToDataUrl(),
},
});
},
token);
return new ChatCompletionAPIRequest
{
@@ -192,12 +191,11 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
{
Text = text,
},
async attachment => new SubContentInputImage
image => new SubContentInputImage
{
ImageUrl = await attachment.TryAsBase64(token: token) is (true, var base64Content)
? $"data:{attachment.DetermineMimeType()};base64,{base64Content}"
: string.Empty,
});
ImageUrl = image.ToDataUrl(),
},
token);
var baseInput = new List<object> { systemPrompt };
baseInput.AddRange(messages);
@@ -36,6 +36,29 @@ public static class HostExtensions
_ => "embeddings",
};
/// <summary>
/// The largest image file, in bytes, which the engine accepts in a chat request, where we know of one.
/// </summary>
/// <remarks>
/// Like the limit of a cloud provider, see LLMProvidersExtensions.GetMaxImageSizeBytes, this
/// belongs to the API of the engine, not to the model. What we actually send is asked through
/// IImageSourceExtensions.MaxImageSizeBytesFor.
/// </remarks>
/// <param name="host">The engine.</param>
/// <returns>The size limit of one image file, or null when the engine states none we know of.</returns>
public static long? GetMaxImageSizeBytes(this Host host) => host switch
{
//
// llmman answers a chat request larger than 2 MiB with 413: its route /v1/chat/completions
// keeps the default limit of its web framework, read on 2026-10-22 at
// https://github.com/llmmanorg/llmman/blob/main/src/cmd/serve.rs. An image of 1 MiB takes
// about 1.33 MiB as base64, which leaves room for the text of the conversation:
//
Host.LLMMAN => 1_048_576,
_ => null,
};
public static bool IsChatSupported(this Host host)
{
switch (host)