mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-02-12 02:01:36 +00:00
Added file attachment support to chat templates (#614)
Some checks failed
Build and Release / Read metadata (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis updater) (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage deb updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage deb updater) (push) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
Some checks failed
Build and Release / Read metadata (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis updater) (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage deb updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis updater) (push) Has been cancelled
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage deb updater) (push) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
This commit is contained in:
parent
3b76b06d5d
commit
47975870b4
@ -103,7 +103,7 @@ else
|
||||
@T("Documents for the analysis")
|
||||
</MudText>
|
||||
|
||||
<AttachDocuments Name="Document Analysis Files" @bind-DocumentPaths="@this.loadedDocumentPaths" CatchAllDocuments="true" UseSmallForm="false" Provider="@this.providerSettings"/>
|
||||
<AttachDocuments Name="Document Analysis Files" Layer="@DropLayers.ASSISTANTS" @bind-DocumentPaths="@this.loadedDocumentPaths" CatchAllDocuments="true" UseSmallForm="false" Provider="@this.providerSettings"/>
|
||||
|
||||
</ExpansionPanel>
|
||||
</MudExpansionPanels>
|
||||
|
||||
@ -2443,6 +2443,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T2147062613"] = "Profile
|
||||
-- Add messages of an example conversation (user prompt followed by assistant prompt) to demonstrate the desired interaction pattern. These examples help the AI understand your expectations by showing it the correct format, style, and content of responses before it receives actual user inputs.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T2292424657"] = "Add messages of an example conversation (user prompt followed by assistant prompt) to demonstrate the desired interaction pattern. These examples help the AI understand your expectations by showing it the correct format, style, and content of responses before it receives actual user inputs."
|
||||
|
||||
-- File Attachments
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T2294745309"] = "File Attachments"
|
||||
|
||||
-- Role
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T2418769465"] = "Role"
|
||||
|
||||
@ -2482,6 +2485,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3016903701"] = "The nam
|
||||
-- Image content
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3094908719"] = "Image content"
|
||||
|
||||
-- You can attach files that will be automatically included when using this chat template. These files will be added to the first message sent in any chat using this template.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3108503534"] = "You can attach files that will be automatically included when using this chat template. These files will be added to the first message sent in any chat using this template."
|
||||
|
||||
-- Are you unsure which system prompt to use? You might start with the default system prompt that AI Studio uses for all chats.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3127437308"] = "Are you unsure which system prompt to use? You might start with the default system prompt that AI Studio uses for all chats."
|
||||
|
||||
@ -5194,6 +5200,9 @@ UI_TEXT_CONTENT["AISTUDIO::PROVIDER::LLMPROVIDERSEXTENSIONS::T3424652889"] = "Un
|
||||
-- no model selected
|
||||
UI_TEXT_CONTENT["AISTUDIO::PROVIDER::MODEL::T2234274832"] = "no model selected"
|
||||
|
||||
-- Use no chat template
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CHATTEMPLATE::T4258819635"] = "Use no chat template"
|
||||
|
||||
-- Navigation never expands, but there are tooltips
|
||||
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::CONFIGURATIONSELECTDATAFACTORY::T1095779033"] = "Navigation never expands, but there are tooltips"
|
||||
|
||||
|
||||
@ -17,6 +17,18 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
|
||||
[Parameter]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// On which layer to register the drop area. Higher layers have priority over lower layers.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public int Layer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When true, pause catching dropped files. Default is false.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool PauseCatchingDrops { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public HashSet<FileAttachment> DocumentPaths { get; set; } = [];
|
||||
@ -36,6 +48,15 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
[Parameter]
|
||||
public bool UseSmallForm { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// When true, validate media file types before attaching. Default is true. That means that
|
||||
/// the user cannot attach unsupported media file types when the provider or model does not
|
||||
/// support them. Set it to false in order to disable this validation. This is useful for places
|
||||
/// where the user might want to prepare a template.
|
||||
/// </summary>
|
||||
[Parameter]
|
||||
public bool ValidateMediaFileTypes { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
public AIStudio.Settings.Provider? Provider { get; set; }
|
||||
|
||||
@ -54,6 +75,7 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
private const Placement TOOLBAR_TOOLTIP_PLACEMENT = Placement.Top;
|
||||
private static readonly string DROP_FILES_HERE_TEXT = TB("Drop files here to attach them.");
|
||||
|
||||
private uint numDropAreasAboveThis;
|
||||
private bool isComponentHovered;
|
||||
private bool isDraggingOver;
|
||||
|
||||
@ -61,7 +83,10 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
this.ApplyFilters([], [ Event.TAURI_EVENT_RECEIVED ]);
|
||||
this.ApplyFilters([], [ Event.TAURI_EVENT_RECEIVED, Event.REGISTER_FILE_DROP_AREA, Event.UNREGISTER_FILE_DROP_AREA ]);
|
||||
|
||||
// Register this drop area:
|
||||
await this.MessageBus.SendMessage(this, Event.REGISTER_FILE_DROP_AREA, this.Layer);
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
@ -69,7 +94,35 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
{
|
||||
switch (triggeredEvent)
|
||||
{
|
||||
case Event.REGISTER_FILE_DROP_AREA when sendingComponent != this:
|
||||
{
|
||||
if(data is int layer && layer > this.Layer)
|
||||
{
|
||||
this.numDropAreasAboveThis++;
|
||||
this.PauseCatchingDrops = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Event.UNREGISTER_FILE_DROP_AREA when sendingComponent != this:
|
||||
{
|
||||
if(data is int layer && layer > this.Layer)
|
||||
{
|
||||
if(this.numDropAreasAboveThis > 0)
|
||||
this.numDropAreasAboveThis--;
|
||||
|
||||
if(this.numDropAreasAboveThis is 0)
|
||||
this.PauseCatchingDrops = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Event.TAURI_EVENT_RECEIVED when data is TauriEvent { EventType: TauriEventType.FILE_DROP_HOVERED }:
|
||||
if(this.PauseCatchingDrops)
|
||||
return;
|
||||
|
||||
if(!this.isComponentHovered && !this.CatchAllDocuments)
|
||||
{
|
||||
this.Logger.LogDebug("Attach documents component '{Name}' is not hovered, ignoring file drop hovered event.", this.Name);
|
||||
@ -82,11 +135,17 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
break;
|
||||
|
||||
case Event.TAURI_EVENT_RECEIVED when data is TauriEvent { EventType: TauriEventType.FILE_DROP_CANCELED }:
|
||||
if(this.PauseCatchingDrops)
|
||||
return;
|
||||
|
||||
this.isDraggingOver = false;
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
|
||||
case Event.TAURI_EVENT_RECEIVED when data is TauriEvent { EventType: TauriEventType.WINDOW_NOT_FOCUSED }:
|
||||
if(this.PauseCatchingDrops)
|
||||
return;
|
||||
|
||||
this.isDraggingOver = false;
|
||||
this.isComponentHovered = false;
|
||||
this.ClearDragClass();
|
||||
@ -94,6 +153,9 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
break;
|
||||
|
||||
case Event.TAURI_EVENT_RECEIVED when data is TauriEvent { EventType: TauriEventType.FILE_DROP_DROPPED, Payload: var paths }:
|
||||
if(this.PauseCatchingDrops)
|
||||
return;
|
||||
|
||||
if(!this.isComponentHovered && !this.CatchAllDocuments)
|
||||
{
|
||||
this.Logger.LogDebug("Attach documents component '{Name}' is not hovered, ignoring file drop dropped event.", this.Name);
|
||||
@ -117,7 +179,7 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
|
||||
foreach (var path in paths)
|
||||
{
|
||||
if(!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(FileExtensionValidation.UseCase.ATTACHING_CONTENT, path, this.Provider))
|
||||
if(!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(FileExtensionValidation.UseCase.ATTACHING_CONTENT, path, this.ValidateMediaFileTypes, this.Provider))
|
||||
continue;
|
||||
|
||||
this.DocumentPaths.Add(FileAttachment.FromPath(path));
|
||||
@ -161,7 +223,7 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
if (!File.Exists(selectedFilePath))
|
||||
continue;
|
||||
|
||||
if (!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(FileExtensionValidation.UseCase.ATTACHING_CONTENT, selectedFilePath, this.Provider))
|
||||
if (!await FileExtensionValidation.IsExtensionValidWithNotifyAsync(FileExtensionValidation.UseCase.ATTACHING_CONTENT, selectedFilePath, this.ValidateMediaFileTypes, this.Provider))
|
||||
continue;
|
||||
|
||||
this.DocumentPaths.Add(FileAttachment.FromPath(selectedFilePath));
|
||||
@ -189,6 +251,9 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
|
||||
private void OnMouseEnter(EventArgs _)
|
||||
{
|
||||
if(this.PauseCatchingDrops)
|
||||
return;
|
||||
|
||||
this.Logger.LogDebug("Attach documents component '{Name}' is hovered.", this.Name);
|
||||
this.isComponentHovered = true;
|
||||
this.SetDragClass();
|
||||
@ -197,6 +262,9 @@ public partial class AttachDocuments : MSGComponentBase
|
||||
|
||||
private void OnMouseLeave(EventArgs _)
|
||||
{
|
||||
if(this.PauseCatchingDrops)
|
||||
return;
|
||||
|
||||
this.Logger.LogDebug("Attach documents component '{Name}' is no longer hovered.", this.Name);
|
||||
this.isComponentHovered = false;
|
||||
this.ClearDragClass();
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
}
|
||||
|
||||
<ChatTemplateSelection CanChatThreadBeUsedForTemplate="@this.CanThreadBeSaved" CurrentChatThread="@this.ChatThread" CurrentChatTemplate="@this.currentChatTemplate" CurrentChatTemplateChanged="@this.ChatTemplateWasChanged"/>
|
||||
<AttachDocuments Name="File Attachments" @bind-DocumentPaths="@this.chatDocumentPaths" CatchAllDocuments="true" UseSmallForm="true" Provider="@this.Provider"/>
|
||||
<AttachDocuments Name="File Attachments" Layer="@DropLayers.PAGES" @bind-DocumentPaths="@this.chatDocumentPaths" CatchAllDocuments="true" UseSmallForm="true" Provider="@this.Provider"/>
|
||||
|
||||
@if (this.SettingsManager.ConfigurationData.Workspace.StorageBehavior is WorkspaceStorageBehavior.STORE_CHATS_AUTOMATICALLY)
|
||||
{
|
||||
|
||||
@ -79,7 +79,11 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
// Get the preselected chat template:
|
||||
this.currentChatTemplate = this.SettingsManager.GetPreselectedChatTemplate(Tools.Components.CHAT);
|
||||
this.userInput = this.currentChatTemplate.PredefinedUserPrompt;
|
||||
|
||||
|
||||
// Apply template's file attachments, if any:
|
||||
foreach (var attachment in this.currentChatTemplate.FileAttachments)
|
||||
this.chatDocumentPaths.Add(attachment);
|
||||
|
||||
//
|
||||
// Check for deferred messages of the kind 'SEND_TO_CHAT',
|
||||
// aka the user sends an assistant result to the chat:
|
||||
@ -328,7 +332,12 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
this.currentChatTemplate = chatTemplate;
|
||||
if(!string.IsNullOrWhiteSpace(this.currentChatTemplate.PredefinedUserPrompt))
|
||||
this.userInput = this.currentChatTemplate.PredefinedUserPrompt;
|
||||
|
||||
|
||||
// Apply template's file attachments (replaces existing):
|
||||
this.chatDocumentPaths.Clear();
|
||||
foreach (var attachment in this.currentChatTemplate.FileAttachments)
|
||||
this.chatDocumentPaths.Add(attachment);
|
||||
|
||||
if(this.ChatThread is null)
|
||||
return;
|
||||
|
||||
@ -677,9 +686,14 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
Blocks = this.currentChatTemplate == ChatTemplate.NO_CHAT_TEMPLATE ? [] : this.currentChatTemplate.ExampleConversation.Select(x => x.DeepClone()).ToList(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
this.userInput = this.currentChatTemplate.PredefinedUserPrompt;
|
||||
|
||||
|
||||
// Apply template's file attachments:
|
||||
this.chatDocumentPaths.Clear();
|
||||
foreach (var attachment in this.currentChatTemplate.FileAttachments)
|
||||
this.chatDocumentPaths.Add(attachment);
|
||||
|
||||
// Now, we have to reset the data source options as well:
|
||||
this.ApplyStandardDataSourceOptions();
|
||||
|
||||
|
||||
@ -77,7 +77,22 @@
|
||||
UserAttributes="@SPELLCHECK_ATTRIBUTES"
|
||||
HelperText="@T("Tell the AI your predefined user input.")"
|
||||
/>
|
||||
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-3 mt-6">
|
||||
@T("File Attachments")
|
||||
</MudText>
|
||||
<MudJustifiedText Class="mb-3" Typo="Typo.body1">
|
||||
@T("You can attach files that will be automatically included when using this chat template. These files will be added to the first message sent in any chat using this template.")
|
||||
</MudJustifiedText>
|
||||
<AttachDocuments
|
||||
Name="ChatTemplateFileAttachments"
|
||||
Layer="@DropLayers.DIALOGS"
|
||||
@bind-DocumentPaths="@this.fileAttachments"
|
||||
UseSmallForm="false"
|
||||
CatchAllDocuments="true"
|
||||
ValidateMediaFileTypes="false"
|
||||
/>
|
||||
|
||||
<MudText Typo="Typo.h6" Class="mb-3 mt-6">
|
||||
@T("Profile Usage")
|
||||
</MudText>
|
||||
|
||||
@ -50,7 +50,10 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
[Parameter]
|
||||
public IReadOnlyCollection<ContentBlock> ExampleConversation { get; init; } = [];
|
||||
|
||||
[Parameter]
|
||||
[Parameter]
|
||||
public IReadOnlyCollection<FileAttachment> FileAttachments { get; init; } = [];
|
||||
|
||||
[Parameter]
|
||||
public bool AllowProfileUsage { get; set; } = true;
|
||||
|
||||
[Parameter]
|
||||
@ -71,6 +74,7 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
|
||||
private bool dataIsValid;
|
||||
private List<ContentBlock> dataExampleConversation = [];
|
||||
private HashSet<FileAttachment> fileAttachments = [];
|
||||
private string[] dataIssues = [];
|
||||
private string dataEditingPreviousName = string.Empty;
|
||||
private bool isInlineEditOnGoing;
|
||||
@ -95,6 +99,7 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
{
|
||||
this.dataEditingPreviousName = this.DataName.ToLowerInvariant();
|
||||
this.dataExampleConversation = this.ExampleConversation.Select(n => n.DeepClone()).ToList();
|
||||
this.fileAttachments = [..this.FileAttachments];
|
||||
}
|
||||
|
||||
if (this.CreateFromExistingChatThread && this.ExistingChatThread is not null)
|
||||
@ -128,6 +133,7 @@ public partial class ChatTemplateDialog : MSGComponentBase
|
||||
SystemPrompt = this.DataSystemPrompt,
|
||||
PredefinedUserPrompt = this.PredefinedUserPrompt,
|
||||
ExampleConversation = this.dataExampleConversation,
|
||||
FileAttachments = [..this.fileAttachments],
|
||||
AllowProfileUsage = this.AllowProfileUsage,
|
||||
|
||||
EnterpriseConfigurationPluginId = Guid.Empty,
|
||||
|
||||
@ -41,10 +41,10 @@
|
||||
{
|
||||
<MudStack Row="true" Class="mb-2 mt-2" Wrap="Wrap.Wrap">
|
||||
<MudTooltip Text="@T("Edit")">
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Edit" OnClick="() => this.EditChatTemplate(context)"/>
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Edit" OnClick="@(() => this.EditChatTemplate(context))"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="@T("Delete")">
|
||||
<MudIconButton Color="Color.Error" Icon="@Icons.Material.Filled.Delete" OnClick="() => this.DeleteChatTemplate(context)"/>
|
||||
<MudIconButton Color="Color.Error" Icon="@Icons.Material.Filled.Delete" OnClick="@(() => this.DeleteChatTemplate(context))"/>
|
||||
</MudTooltip>
|
||||
</MudStack>
|
||||
}
|
||||
|
||||
@ -65,6 +65,7 @@ public partial class SettingsDialogChatTemplate : SettingsDialogBase
|
||||
{ x => x.PredefinedUserPrompt, chatTemplate.PredefinedUserPrompt },
|
||||
{ x => x.IsEditing, true },
|
||||
{ x => x.ExampleConversation, chatTemplate.ExampleConversation },
|
||||
{ x => x.FileAttachments, chatTemplate.FileAttachments },
|
||||
{ x => x.AllowProfileUsage, chatTemplate.AllowProfileUsage },
|
||||
};
|
||||
|
||||
|
||||
@ -125,6 +125,33 @@ CONFIG["CHAT_TEMPLATES"][#CONFIG["CHAT_TEMPLATES"]+1] = {
|
||||
}
|
||||
}
|
||||
|
||||
-- An example chat template with file attachments:
|
||||
-- This template automatically attaches specified files when the user selects it.
|
||||
CONFIG["CHAT_TEMPLATES"][#CONFIG["CHAT_TEMPLATES"]+1] = {
|
||||
["Id"] = "00000000-0000-0000-0000-000000000001",
|
||||
["Name"] = "Document Analysis Template",
|
||||
["SystemPrompt"] = "You are an expert document analyst. Please analyze the attached documents and provide insights.",
|
||||
["PredefinedUserPrompt"] = "Please analyze the attached company guidelines and summarize the key points.",
|
||||
["AllowProfileUsage"] = true,
|
||||
-- Optional: Pre-attach files that will be automatically included when using this template.
|
||||
-- These files will be loaded when the user selects this chat template.
|
||||
-- Note: File paths must be absolute paths and accessible to all users.
|
||||
["FileAttachments"] = {
|
||||
"G:\\Company\\Documents\\Guidelines.pdf",
|
||||
"G:\\Company\\Documents\\CompanyPolicies.docx"
|
||||
},
|
||||
["ExampleConversation"] = {
|
||||
{
|
||||
["Role"] = "USER",
|
||||
["Content"] = "I have attached the company documents for analysis."
|
||||
},
|
||||
{
|
||||
["Role"] = "AI",
|
||||
["Content"] = "Thank you. I'll analyze the documents and provide a comprehensive summary."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-- Profiles for this configuration:
|
||||
CONFIG["PROFILES"] = {}
|
||||
|
||||
|
||||
@ -2445,6 +2445,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T2147062613"] = "Profiln
|
||||
-- Add messages of an example conversation (user prompt followed by assistant prompt) to demonstrate the desired interaction pattern. These examples help the AI understand your expectations by showing it the correct format, style, and content of responses before it receives actual user inputs.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T2292424657"] = "Fügen Sie Nachrichten einer Beispiel-Konversation hinzu (Nutzereingabe, gefolgt von einer Antwort des Assistenten), um das gewünschte Interaktionsmuster zu demonstrieren. Diese Beispiele helfen der KI, ihre Erwartungen zu verstehen, indem Sie das korrekte Format, den Stil und den Inhalt von Antworten zeigen, bevor tatsächliche Nutzereingaben erfolgen."
|
||||
|
||||
-- File Attachments
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T2294745309"] = "Dateianhänge"
|
||||
|
||||
-- Role
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T2418769465"] = "Rolle"
|
||||
|
||||
@ -2484,6 +2487,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3016903701"] = "Der Nam
|
||||
-- Image content
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3094908719"] = "Bildinhalt"
|
||||
|
||||
-- You can attach files that will be automatically included when using this chat template. These files will be added to the first message sent in any chat using this template.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3108503534"] = "Sie können Dateien anhängen, die bei Verwendung dieser Chat-Vorlage automatisch einbezogen werden. Diese Dateien werden der ersten Nachricht hinzugefügt, die in einem Chat gesendet wird, der diese Vorlage verwendet."
|
||||
|
||||
-- Are you unsure which system prompt to use? You might start with the default system prompt that AI Studio uses for all chats.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3127437308"] = "Sind Sie unsicher, welchen System-Prompt Sie verwenden sollen? Sie können mit dem Standard-System-Prompt beginnen, den AI Studio für alle Chats verwendet."
|
||||
|
||||
|
||||
@ -2445,6 +2445,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T2147062613"] = "Profile
|
||||
-- Add messages of an example conversation (user prompt followed by assistant prompt) to demonstrate the desired interaction pattern. These examples help the AI understand your expectations by showing it the correct format, style, and content of responses before it receives actual user inputs.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T2292424657"] = "Add messages of an example conversation (user prompt followed by assistant prompt) to demonstrate the desired interaction pattern. These examples help the AI understand your expectations by showing it the correct format, style, and content of responses before it receives actual user inputs."
|
||||
|
||||
-- File Attachments
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T2294745309"] = "File Attachments"
|
||||
|
||||
-- Role
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T2418769465"] = "Role"
|
||||
|
||||
@ -2484,6 +2487,9 @@ UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3016903701"] = "The nam
|
||||
-- Image content
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3094908719"] = "Image content"
|
||||
|
||||
-- You can attach files that will be automatically included when using this chat template. These files will be added to the first message sent in any chat using this template.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3108503534"] = "You can attach files that will be automatically included when using this chat template. These files will be added to the first message sent in any chat using this template."
|
||||
|
||||
-- Are you unsure which system prompt to use? You might start with the default system prompt that AI Studio uses for all chats.
|
||||
UI_TEXT_CONTENT["AISTUDIO::DIALOGS::CHATTEMPLATEDIALOG::T3127437308"] = "Are you unsure which system prompt to use? You might start with the default system prompt that AI Studio uses for all chats."
|
||||
|
||||
|
||||
@ -12,13 +12,12 @@ public record ChatTemplate(
|
||||
string SystemPrompt,
|
||||
string PredefinedUserPrompt,
|
||||
List<ContentBlock> ExampleConversation,
|
||||
List<FileAttachment> FileAttachments,
|
||||
bool AllowProfileUsage,
|
||||
bool IsEnterpriseConfiguration = false,
|
||||
Guid EnterpriseConfigurationPluginId = default) : ConfigurationBaseObject
|
||||
{
|
||||
private const string USE_NO_CHAT_TEMPLATE_TEXT = "Use no chat template";
|
||||
|
||||
public ChatTemplate() : this(0, Guid.Empty.ToString(), string.Empty, string.Empty, string.Empty, [], false)
|
||||
public ChatTemplate() : this(0, Guid.Empty.ToString(), string.Empty, string.Empty, string.Empty, [], [], false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -28,12 +27,13 @@ public record ChatTemplate(
|
||||
|
||||
public static readonly ChatTemplate NO_CHAT_TEMPLATE = new()
|
||||
{
|
||||
Name = TB(USE_NO_CHAT_TEMPLATE_TEXT), // Cannot be localized due to being a static readonly field
|
||||
Name = TB("Use no chat template"), // Cannot be localized due to being a static readonly field
|
||||
SystemPrompt = string.Empty,
|
||||
PredefinedUserPrompt = string.Empty,
|
||||
Id = Guid.Empty.ToString(),
|
||||
Num = uint.MaxValue,
|
||||
ExampleConversation = [],
|
||||
FileAttachments = [],
|
||||
AllowProfileUsage = true,
|
||||
EnterpriseConfigurationPluginId = Guid.Empty,
|
||||
IsEnterpriseConfiguration = false,
|
||||
@ -61,7 +61,7 @@ public record ChatTemplate(
|
||||
public string GetSafeName()
|
||||
{
|
||||
if(this == NO_CHAT_TEMPLATE)
|
||||
return TB(USE_NO_CHAT_TEMPLATE_TEXT);
|
||||
return TB("Use no chat template");
|
||||
|
||||
return this.Name;
|
||||
}
|
||||
@ -102,7 +102,9 @@ public record ChatTemplate(
|
||||
var allowProfileUsage = false;
|
||||
if (table.TryGetValue("AllowProfileUsage", out var allowProfileValue) && allowProfileValue.TryRead<bool>(out var allow))
|
||||
allowProfileUsage = allow;
|
||||
|
||||
|
||||
var fileAttachments = ParseFileAttachments(idx, table);
|
||||
|
||||
template = new ChatTemplate
|
||||
{
|
||||
Num = 0,
|
||||
@ -111,6 +113,7 @@ public record ChatTemplate(
|
||||
SystemPrompt = systemPrompt,
|
||||
PredefinedUserPrompt = predefinedUserPrompt,
|
||||
ExampleConversation = ParseExampleConversation(idx, table),
|
||||
FileAttachments = fileAttachments,
|
||||
AllowProfileUsage = allowProfileUsage,
|
||||
IsEnterpriseConfiguration = true,
|
||||
EnterpriseConfigurationPluginId = configPluginId,
|
||||
@ -165,4 +168,26 @@ public record ChatTemplate(
|
||||
|
||||
return exampleConversation;
|
||||
}
|
||||
|
||||
private static List<FileAttachment> ParseFileAttachments(int idx, LuaTable table)
|
||||
{
|
||||
var fileAttachments = new List<FileAttachment>();
|
||||
if (!table.TryGetValue("FileAttachments", out var fileAttValue) || !fileAttValue.TryRead<LuaTable>(out var fileAttTable))
|
||||
return fileAttachments;
|
||||
|
||||
var numAttachments = fileAttTable.ArrayLength;
|
||||
for (var attachmentNum = 1; attachmentNum <= numAttachments; attachmentNum++)
|
||||
{
|
||||
var attachmentValue = fileAttTable[attachmentNum];
|
||||
if (!attachmentValue.TryRead<string>(out var filePath))
|
||||
{
|
||||
LOGGER.LogWarning("The FileAttachments entry {AttachmentNum} in chat template {IdxChatTemplate} is not a valid string.", attachmentNum, idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
fileAttachments.Add(FileAttachment.FromPath(filePath));
|
||||
}
|
||||
|
||||
return fileAttachments;
|
||||
}
|
||||
}
|
||||
11
app/MindWork AI Studio/Tools/DropLayers.cs
Normal file
11
app/MindWork AI Studio/Tools/DropLayers.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace AIStudio.Tools;
|
||||
|
||||
public static class DropLayers
|
||||
{
|
||||
public const int ROOT = 0;
|
||||
|
||||
public const int PAGES = 10;
|
||||
public const int ASSISTANTS = 20;
|
||||
|
||||
public const int DIALOGS = 100;
|
||||
}
|
||||
@ -34,6 +34,10 @@ public enum Event
|
||||
// RAG events:
|
||||
RAG_AUTO_DATA_SOURCES_SELECTED,
|
||||
|
||||
// File attachment events:
|
||||
REGISTER_FILE_DROP_AREA,
|
||||
UNREGISTER_FILE_DROP_AREA,
|
||||
|
||||
// Send events:
|
||||
SEND_TO_GRAMMAR_SPELLING_ASSISTANT,
|
||||
SEND_TO_ICON_FINDER_ASSISTANT,
|
||||
|
||||
@ -32,15 +32,16 @@ public static class FileExtensionValidation
|
||||
/// </summary>
|
||||
ATTACHING_CONTENT,
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Validates the file extension and sends appropriate MessageBus notifications when invalid.
|
||||
/// </summary>
|
||||
/// <param name="useCae">The validation use case.</param>
|
||||
/// <param name="filePath">The file path to validate.</param>
|
||||
/// <param name="validateMediaFileTypes">Whether to validate media file types against provider capabilities.</param>
|
||||
/// <param name="provider">The selected provider.</param>
|
||||
/// <returns>True if valid, false if invalid (error/warning already sent via MessageBus).</returns>
|
||||
public static async Task<bool> IsExtensionValidWithNotifyAsync(UseCase useCae, string filePath, Settings.Provider? provider = null)
|
||||
public static async Task<bool> IsExtensionValidWithNotifyAsync(UseCase useCae, string filePath, bool validateMediaFileTypes = true, Settings.Provider? provider = null)
|
||||
{
|
||||
var ext = Path.GetExtension(filePath).TrimStart('.').ToLowerInvariant();
|
||||
if(FileTypeFilter.Executables.FilterExtensions.Contains(ext))
|
||||
@ -63,6 +64,10 @@ public static class FileExtensionValidation
|
||||
TB("Images are not supported at this place")));
|
||||
return false;
|
||||
|
||||
// In this use case, we don't validate the provider capabilities:
|
||||
case UseCase.ATTACHING_CONTENT when !validateMediaFileTypes:
|
||||
return true;
|
||||
|
||||
// In this use case, we can check the provider capabilities:
|
||||
case UseCase.ATTACHING_CONTENT when capabilities.Contains(Capability.SINGLE_IMAGE_INPUT) ||
|
||||
capabilities.Contains(Capability.MULTIPLE_IMAGE_INPUT):
|
||||
|
||||
@ -1 +0,0 @@
|
||||
# v0.10.1, build 231 (2026-01-xx xx:xx UTC)
|
||||
3
app/MindWork AI Studio/wwwroot/changelog/v26.1.1.md
Normal file
3
app/MindWork AI Studio/wwwroot/changelog/v26.1.1.md
Normal file
@ -0,0 +1,3 @@
|
||||
# v26.1.1, build 231 (2026-01-xx xx:xx UTC)
|
||||
- Added the option to attach files, including images, to chat templates. You can also define templates with file attachments through a configuration plugin. These file attachments aren’t copied—they’re re-read every time. That means the AI will pick up any updates you make to those files.
|
||||
- Improved the app versioning. Starting in 2026, each version number includes the year, followed by the month. The last digit shows the release number for that month. For example, version `26.1.1` is the first release in January 2026.
|
||||
Loading…
Reference in New Issue
Block a user