Added the possibility to attach files to the chat (#585)
Build and Release / Read metadata (push) Waiting to run
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg updater) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis updater) (push) Blocked by required conditions
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) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg updater) (push) Blocked by required conditions
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) Blocked by required conditions
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) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions

Co-authored-by: Thorsten Sommer
This commit is contained in:
Sabrina-devopsandThorsten Sommer authored and GitHub committed 2025-12-10 13:48:13 +01:00
1 parent 0aff45eca3
commit f521c11a60
33 files changed
+579 -280

No files matched your search

@@ -16,11 +16,19 @@
</MudText>
</CardHeaderContent>
<CardHeaderActions>
@if (this.Content.FileAttachments.Count > 0)
{
<MudTooltip Text="@T("Number of attachments")" Placement="Placement.Bottom">
<MudBadge Content="@this.Content.FileAttachments.Count" Color="Color.Primary" Overlap="true" BadgeClass="sources-card-header">
<MudIconButton Icon="@Icons.Material.Filled.AttachFile" />
</MudBadge>
</MudTooltip>
}
@if (this.Content.Sources.Count > 0)
{
<MudTooltip Text="@T("Number of sources")" Placement="Placement.Bottom">
<MudBadge Content="@this.Content.Sources.Count" Color="Color.Primary" Overlap="true" BadgeClass="sources-card-header">
<MudIconButton Icon="@Icons.Material.Filled.Link" />
<MudIconButton Icon="@Icons.Material.Filled.Link"/>
</MudBadge>
</MudTooltip>
}
@@ -30,6 +30,9 @@ public sealed class ContentImage : IContent, IImageSource
/// <inheritdoc />
public List<Source> Sources { get; set; } = [];
/// <inheritdoc />
public List<string> FileAttachments { get; set; } = [];
/// <inheritdoc />
public Task<ChatThread> CreateFromProviderAsync(IProvider provider, Model chatModel, IContent? lastUserPrompt, ChatThread? chatChatThread, CancellationToken token = default)
{
@@ -1,3 +1,4 @@
using System.Text;
using System.Text.Json.Serialization;
using AIStudio.Provider;
@@ -39,6 +40,9 @@ public sealed class ContentText : IContent
/// <inheritdoc />
public List<Source> Sources { get; set; } = [];
/// <inheritdoc />
public List<string> FileAttachments { get; set; } = [];
/// <inheritdoc />
public async Task<ChatThread> CreateFromProviderAsync(IProvider provider, Model chatModel, IContent? lastUserPrompt, ChatThread? chatThread, CancellationToken token = default)
@@ -139,9 +143,44 @@ public sealed class ContentText : IContent
Text = this.Text,
InitialRemoteWait = this.InitialRemoteWait,
IsStreaming = this.IsStreaming,
Sources = [..this.Sources],
FileAttachments = [..this.FileAttachments],
};
#endregion
public async Task<string> PrepareContentForAI()
{
var sb = new StringBuilder();
sb.AppendLine(this.Text);
if(this.FileAttachments.Count > 0)
{
// Check Pandoc availability once before processing file attachments
var pandocState = await Pandoc.CheckAvailabilityAsync(Program.RUST_SERVICE, showMessages: true, showSuccessMessage: false);
if (!pandocState.IsAvailable)
LOGGER.LogWarning("File attachments could not be processed because Pandoc is not available.");
else if (!pandocState.CheckWasSuccessful)
LOGGER.LogWarning("File attachments could not be processed because the Pandoc version check failed.");
else
{
sb.AppendLine();
sb.AppendLine("The following files are attached to this message:");
foreach(var file in this.FileAttachments)
{
sb.AppendLine();
sb.AppendLine("---------------------------------------");
sb.AppendLine($"File path: {file}");
sb.AppendLine("File content:");
sb.AppendLine("````");
sb.AppendLine(await Program.RUST_SERVICE.ReadArbitraryFileData(file, int.MaxValue));
sb.AppendLine("````");
}
}
}
return sb.ToString();
}
/// <summary>
/// The text content.
+7
View File
@@ -47,6 +47,13 @@ public interface IContent
/// </remarks>
[JsonIgnore]
public List<Source> Sources { get; set; }
/// <summary>
/// Represents a collection of file attachments associated with the content.
/// This property contains a list of file paths that are appended
/// to the content to provide additional context or resources.
/// </summary>
public List<string> FileAttachments { get; set; }
/// <summary>
/// Uses the provider to create the content.
@@ -0,0 +1,25 @@
namespace AIStudio.Chat;
public static class ListContentBlockExtensions
{
/// <summary>
/// Processes a list of content blocks by transforming them into a collection of message results asynchronously.
/// </summary>
/// <param name="blocks">The list of content blocks to process.</param>
/// <param name="transformer">A function that transforms each content block into a message result asynchronously.</param>
/// <typeparam name="TResult">The type of the result produced by the transformation function.</typeparam>
/// <returns>An asynchronous task that resolves to a list of transformed results.</returns>
public static async Task<IList<TResult>> BuildMessages<TResult>(this List<ContentBlock> blocks, Func<ContentBlock, Task<TResult>> transformer)
{
var messages = blocks
.Where(n => n.ContentType is ContentType.TEXT && !string.IsNullOrWhiteSpace((n.Content as ContentText)?.Text))
.Select(transformer)
.ToList();
// Await all messages:
await Task.WhenAll(messages);
// Select all results:
return messages.Select(n => n.Result).ToList();
}
}