diff --git a/app/MindWork AI Studio/Agents/AgentDataSourceSelection.cs b/app/MindWork AI Studio/Agents/AgentDataSourceSelection.cs index 778fafb9..f7947462 100644 --- a/app/MindWork AI Studio/Agents/AgentDataSourceSelection.cs +++ b/app/MindWork AI Studio/Agents/AgentDataSourceSelection.cs @@ -159,7 +159,9 @@ public sealed class AgentDataSourceSelection (ILogger ContentText text => text.Text, // Image prompts may be empty, e.g., when the image is too large: - ContentImage image => await image.AsBase64(token), + ContentImage image => await image.TryAsBase64(token) is (success: true, { } base64Image) + ? base64Image + : string.Empty, // Other content types are not supported yet: _ => string.Empty, diff --git a/app/MindWork AI Studio/Agents/AgentRetrievalContextValidation.cs b/app/MindWork AI Studio/Agents/AgentRetrievalContextValidation.cs index 7496301f..ee2437d9 100644 --- a/app/MindWork AI Studio/Agents/AgentRetrievalContextValidation.cs +++ b/app/MindWork AI Studio/Agents/AgentRetrievalContextValidation.cs @@ -219,7 +219,9 @@ public sealed class AgentRetrievalContextValidation (ILogger text.Text, // Image prompts may be empty, e.g., when the image is too large: - ContentImage image => await image.AsBase64(token), + ContentImage image => await image.TryAsBase64(token) is (success: true, { } base64Image) + ? base64Image + : string.Empty, // Other content types are not supported yet: _ => string.Empty, diff --git a/app/MindWork AI Studio/Chat/ChatThread.cs b/app/MindWork AI Studio/Chat/ChatThread.cs index da01b153..134c555f 100644 --- a/app/MindWork AI Studio/Chat/ChatThread.cs +++ b/app/MindWork AI Studio/Chat/ChatThread.cs @@ -238,7 +238,7 @@ public sealed record ChatThread { var (contentData, contentType) = block.Content switch { - ContentImage image => (await image.AsBase64(token), Tools.ERIClient.DataModel.ContentType.IMAGE), + ContentImage image => (await image.TryAsBase64(token) is (success: true, { } base64Image) ? base64Image : string.Empty, Tools.ERIClient.DataModel.ContentType.IMAGE), ContentText text => (text.Text, Tools.ERIClient.DataModel.ContentType.TEXT), _ => (string.Empty, Tools.ERIClient.DataModel.ContentType.UNKNOWN), diff --git a/app/MindWork AI Studio/Chat/IImageSourceExtensions.cs b/app/MindWork AI Studio/Chat/IImageSourceExtensions.cs index 7ad62a8e..62631c68 100644 --- a/app/MindWork AI Studio/Chat/IImageSourceExtensions.cs +++ b/app/MindWork AI Studio/Chat/IImageSourceExtensions.cs @@ -12,21 +12,25 @@ public static class IImageSourceExtensions /// /// The images are directly converted to base64 strings. The maximum /// size of the image is around 10 MB. If the image is larger, the method - /// returns an empty string. - /// + /// returns an empty string.
+ ///
/// As of now, this method does no sort of image processing. LLMs usually /// do not work with arbitrary image sizes. In the future, we might have - /// to resize the images before sending them to the model. + /// to resize the images before sending them to the model.
+ ///
+ /// Note as well that this method returns just the base64 string without + /// any data URI prefix (like "data:image/png;base64,"). The caller has + /// to take care of that if needed. ///
/// The image source. /// The cancellation token. /// The image content as a base64 string; might be empty. - public static async Task AsBase64(this IImageSource image, CancellationToken token = default) + public static async Task<(bool success, string base64Content)> TryAsBase64(this IImageSource image, CancellationToken token = default) { switch (image.SourceType) { case ContentImageSource.BASE64: - return image.Source; + return (success: true, image.Source); case ContentImageSource.URL: { @@ -39,14 +43,15 @@ public static class IImageSourceExtensions if(lengthBytes > 10_000_000) { await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.ImageNotSupported, TB("The image at the URL is too large (>10 MB). Skipping the image."))); - return string.Empty; + return (success: false, string.Empty); } var bytes = await response.Content.ReadAsByteArrayAsync(token); - return Convert.ToBase64String(bytes); + return (success: true, Convert.ToBase64String(bytes)); } - return string.Empty; + await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.ImageNotSupported, TB("Failed to download the image from the URL. Skipping the image."))); + return (success: false, string.Empty); } case ContentImageSource.LOCAL_PATH: @@ -57,17 +62,18 @@ public static class IImageSourceExtensions if(length > 10_000_000) { await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.ImageNotSupported, TB("The local image file is too large (>10 MB). Skipping the image."))); - return string.Empty; + return (success: false, string.Empty); } var bytes = await File.ReadAllBytesAsync(image.Source, token); - return Convert.ToBase64String(bytes); + return (success: true, Convert.ToBase64String(bytes)); } - return string.Empty; + await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.ImageNotSupported, TB("The local image file does not exist. Skipping the image."))); + return (success: false, string.Empty); default: - return string.Empty; + return (success: false, string.Empty); } } } \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/DataModel/DataSourceERI_V1.cs b/app/MindWork AI Studio/Settings/DataModel/DataSourceERI_V1.cs index cc836bcf..cbc3839c 100644 --- a/app/MindWork AI Studio/Settings/DataModel/DataSourceERI_V1.cs +++ b/app/MindWork AI Studio/Settings/DataModel/DataSourceERI_V1.cs @@ -74,7 +74,9 @@ public readonly record struct DataSourceERI_V1 : IERIDataSource LatestUserPrompt = lastUserPrompt switch { ContentText text => text.Text, - ContentImage image => await image.AsBase64(token), + ContentImage image => await image.TryAsBase64(token) is (success: true, { } base64Image) + ? base64Image + : string.Empty, _ => string.Empty }, diff --git a/app/MindWork AI Studio/Tools/RAG/IRetrievalContextExtensions.cs b/app/MindWork AI Studio/Tools/RAG/IRetrievalContextExtensions.cs index ee5e6cb5..74ff4e58 100644 --- a/app/MindWork AI Studio/Tools/RAG/IRetrievalContextExtensions.cs +++ b/app/MindWork AI Studio/Tools/RAG/IRetrievalContextExtensions.cs @@ -81,7 +81,9 @@ public static class IRetrievalContextExtensions sb.AppendLine(); sb.AppendLine("Matched image content as base64-encoded data:"); sb.AppendLine("````"); - sb.AppendLine(await imageContext.AsBase64(token)); + sb.AppendLine(await imageContext.TryAsBase64(token) is (success: true, { } base64Image) + ? base64Image + : string.Empty); sb.AppendLine("````"); break;