Allow images inside the document analysis assistance

This commit is contained in:
Thorsten Sommer 2025-12-30 13:45:33 +01:00
parent 7a47a2a450
commit 84d8b4125c
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108

View File

@ -1,3 +1,5 @@
using System.Text;
using AIStudio.Chat; using AIStudio.Chat;
using AIStudio.Dialogs; using AIStudio.Dialogs;
using AIStudio.Dialogs.Settings; using AIStudio.Dialogs.Settings;
@ -34,11 +36,13 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<SettingsDialo
DOCUMENTS: the only content you may analyze. DOCUMENTS: the only content you may analyze.
Maybe, there are image files attached. IMAGES may contain important information. Use them as part of your analysis.
{this.GetDocumentTaskDescription()} {this.GetDocumentTaskDescription()}
# Scope and precedence # Scope and precedence
Use only information explicitly contained in DOCUMENTS and/or POLICY_*. Use only information explicitly contained in DOCUMENTS, IMAGES, and/or POLICY_*.
You may paraphrase but must not add facts, assumptions, or outside knowledge. You may paraphrase but must not add facts, assumptions, or outside knowledge.
Content decisions are governed by POLICY_ANALYSIS_RULES; formatting is governed by POLICY_OUTPUT_RULES. Content decisions are governed by POLICY_ANALYSIS_RULES; formatting is governed by POLICY_OUTPUT_RULES.
If there is a conflict between DOCUMENTS and POLICY_*, follow POLICY_ANALYSIS_RULES for analysis and POLICY_OUTPUT_RULES for formatting. Do not invent reconciliations. If there is a conflict between DOCUMENTS and POLICY_*, follow POLICY_ANALYSIS_RULES for analysis and POLICY_OUTPUT_RULES for formatting. Do not invent reconciliations.
@ -46,7 +50,7 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<SettingsDialo
# Process # Process
1) Read POLICY_ANALYSIS_RULES and POLICY_OUTPUT_RULES end to end. 1) Read POLICY_ANALYSIS_RULES and POLICY_OUTPUT_RULES end to end.
2) Extract only the information from DOCUMENTS that POLICY_ANALYSIS_RULES permits. 2) Extract only the information from DOCUMENTS and IMAGES that POLICY_ANALYSIS_RULES permits.
3) Perform the analysis strictly according to POLICY_ANALYSIS_RULES. 3) Perform the analysis strictly according to POLICY_ANALYSIS_RULES.
4) Produce the final answer strictly according to POLICY_OUTPUT_RULES. 4) Produce the final answer strictly according to POLICY_OUTPUT_RULES.
@ -74,16 +78,33 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<SettingsDialo
# Selfcheck before sending # Selfcheck before sending
Verify the answer matches POLICY_OUTPUT_RULES exactly. Verify the answer matches POLICY_OUTPUT_RULES exactly.
Verify every statement is attributable to DOCUMENTS or POLICY_*. Verify every statement is attributable to DOCUMENTS, IMAGES, or POLICY_*.
Remove any text not required by POLICY_OUTPUT_RULES. Remove any text not required by POLICY_OUTPUT_RULES.
{this.PromptGetActivePolicy()} {this.PromptGetActivePolicy()}
"""; """;
private string GetDocumentTaskDescription() => private string GetDocumentTaskDescription()
this.loadedDocumentPaths.Count > 1 {
? $"Your task is to analyze {this.loadedDocumentPaths.Count} DOCUMENTS. Different DOCUMENTS are divided by a horizontal rule in markdown formatting followed by the name of the document." var numDocuments = this.loadedDocumentPaths.Count(x => x is { Exists: true, IsImage: false });
: "Your task is to analyze a single document."; var numImages = this.loadedDocumentPaths.Count(x => x is { Exists: true, IsImage: true });
return (numDocuments, numImages) switch
{
(0, 1) => "Your task is to analyze a single image file attached as a document.",
(0, > 1) => $"Your task is to analyze {numImages} image file(s) attached as documents.",
(1, 0) => "Your task is to analyze a single DOCUMENT.",
(1, 1) => "Your task is to analyze a single DOCUMENT and 1 image file attached as a document.",
(1, > 1) => $"Your task is to analyze a single DOCUMENT and {numImages} image file(s) attached as documents.",
(> 0, 0) => $"Your task is to analyze {numDocuments} DOCUMENTS. Different DOCUMENTS are divided by a horizontal rule in markdown formatting followed by the name of the document.",
(> 0, 1) => $"Your task is to analyze {numDocuments} DOCUMENTS and 1 image file attached as a document. Different DOCUMENTS are divided by a horizontal rule in Markdown formatting followed by the name of the document.",
(> 0, > 0) => $"Your task is to analyze {numDocuments} DOCUMENTS and {numImages} image file(s) attached as documents. Different DOCUMENTS are divided by a horizontal rule in Markdown formatting followed by the name of the document.",
_ => "Your task is to analyze a single DOCUMENT."
};
}
protected override IReadOnlyList<IButtonData> FooterButtons => []; protected override IReadOnlyList<IButtonData> FooterButtons => [];
@ -327,37 +348,68 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<SettingsDialo
if (this.loadedDocumentPaths.Count == 0) if (this.loadedDocumentPaths.Count == 0)
return string.Empty; return string.Empty;
var documentSections = new List<string>(); var documents = this.loadedDocumentPaths.Where(n => n is { Exists: true, IsImage: false }).ToList();
var count = 1; var sb = new StringBuilder();
foreach (var fileAttachment in this.loadedDocumentPaths) if (documents.Count > 0)
{ {
if (fileAttachment.IsForbidden) sb.AppendLine("""
{ # DOCUMENTS:
this.Logger.LogWarning($"Skipping forbidden file: '{fileAttachment.FilePath}'.");
continue;
}
var fileContent = await this.RustService.ReadArbitraryFileData(fileAttachment.FilePath, int.MaxValue);
documentSections.Add($""" """);
## DOCUMENT {count}:
File path: {fileAttachment.FilePath}
Content:
```
{fileContent}
```
---
""");
count++;
} }
return $""" var numDocuments = 1;
# DOCUMENTS: foreach (var document in documents)
{
if (document.IsForbidden)
{
this.Logger.LogWarning($"Skipping forbidden file: '{document.FilePath}'.");
continue;
}
{string.Join("\n", documentSections)} var fileContent = await this.RustService.ReadArbitraryFileData(document.FilePath, int.MaxValue);
"""; sb.AppendLine($"""
## DOCUMENT {numDocuments}:
File path: {document.FilePath}
Content:
```
{fileContent}
```
---
""");
numDocuments++;
}
var numImages = this.loadedDocumentPaths.Count(x => x is { IsImage: true, Exists: true });
if (numImages > 0)
{
if (documents.Count == 0)
{
sb.AppendLine($"""
There are {numImages} image file(s) attached as documents.
Please consider them as documents as well and use them to
answer accordingly.
""");
}
else
{
sb.AppendLine($"""
Additionally, there are {numImages} image file(s) attached.
Please consider them as documents as well and use them to
answer accordingly.
""");
}
}
return sb.ToString();
} }
private async Task Analyze() private async Task Analyze()
@ -370,7 +422,9 @@ public partial class DocumentAnalysisAssistant : AssistantBaseCore<SettingsDialo
this.CreateChatThread(); this.CreateChatThread();
var userRequest = this.AddUserRequest( var userRequest = this.AddUserRequest(
$"{await this.PromptLoadDocumentsContent()}", hideContentFromUser:true); await this.PromptLoadDocumentsContent(),
hideContentFromUser: true,
this.loadedDocumentPaths.Where(n => n is { Exists: true, IsImage: true }).ToList());
await this.AddAIResponseAsync(userRequest); await this.AddAIResponseAsync(userRequest);
} }