mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-13 00:14:26 +00:00
Added the option to search for chats in all workspaces (#795)
Build and Release / Determine run mode (push) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled
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,app,updater, dmg) (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, nsis) (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,updater, appimage) (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,app,updater, dmg) (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, nsis) (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,updater, appimage) (push) Has been cancelled
Build and Release / Determine run mode (push) Has been cancelled
Build and Release / Prepare & create release (push) Has been cancelled
Build and Release / Publish release (push) Has been cancelled
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,app,updater, dmg) (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, nsis) (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,updater, appimage) (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,app,updater, dmg) (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, nsis) (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,updater, appimage) (push) Has been cancelled
This commit is contained in:
1 parent
9fc7eaff99
commit
0b41f5eb96
12 files changed
+515
-22
No files matched your search
@@ -230,6 +230,92 @@ public static class WorkspaceBehaviour
|
||||
chats.RemoveAt(existingIndex);
|
||||
}
|
||||
|
||||
private static IReadOnlyList<string> ParseSearchTerms(string searchText) => searchText
|
||||
.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Where(term => !string.IsNullOrWhiteSpace(term))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToList();
|
||||
|
||||
private static IReadOnlyList<string> GetMissingTerms(string text, IReadOnlyList<string> terms) => terms
|
||||
.Where(term => text.IndexOf(term, StringComparison.OrdinalIgnoreCase) < 0)
|
||||
.ToList();
|
||||
|
||||
private static bool ChatThreadContainsTerms(ChatThread thread, IReadOnlyList<string> terms)
|
||||
{
|
||||
var matchedTerms = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var block in thread.Blocks)
|
||||
{
|
||||
if (block.HideFromUser || block.Content is not ContentText textContent || string.IsNullOrWhiteSpace(textContent.Text))
|
||||
continue;
|
||||
|
||||
foreach (var term in terms)
|
||||
if (textContent.Text.Contains(term, StringComparison.OrdinalIgnoreCase))
|
||||
matchedTerms.Add(term);
|
||||
|
||||
if (matchedTerms.Count == terms.Count)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static async Task<bool> ThreadContainsTermsAsync(WorkspaceTreeChat chat, IReadOnlyList<string> terms, CancellationToken token)
|
||||
{
|
||||
var (acquired, semaphore) = await TryAcquireChatSemaphoreAsync(chat.WorkspaceId, chat.ChatId, nameof(ThreadContainsTermsAsync));
|
||||
if (!acquired)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
var threadPath = Path.Join(chat.ChatPath, "thread.json");
|
||||
if (!File.Exists(threadPath))
|
||||
return false;
|
||||
|
||||
var chatData = await File.ReadAllTextAsync(threadPath, Encoding.UTF8, token);
|
||||
token.ThrowIfCancellationRequested();
|
||||
var thread = JsonSerializer.Deserialize<ChatThread>(chatData, JSON_OPTIONS);
|
||||
return thread is not null && ChatThreadContainsTerms(thread, terms);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.LogWarning(ex, "Failed to search chat thread for workspace '{WorkspaceId}', chat '{ChatId}'.", chat.WorkspaceId, chat.ChatId);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
semaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<List<WorkspaceSearchResult>> SearchChatsAsync(IReadOnlyList<WorkspaceTreeChat> chats, IReadOnlyList<string> terms, bool includeThreadContents, CancellationToken token)
|
||||
{
|
||||
var results = new List<WorkspaceSearchResult>();
|
||||
foreach (var chat in chats)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
var missingTerms = GetMissingTerms(chat.Name, terms);
|
||||
if (missingTerms.Count == 0)
|
||||
{
|
||||
results.Add(new(chat, NameMatched: true, ThreadMatched: false));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!includeThreadContents)
|
||||
continue;
|
||||
|
||||
var threadMatched = await ThreadContainsTermsAsync(chat, missingTerms, token);
|
||||
if (threadMatched)
|
||||
results.Add(new(chat, NameMatched: false, ThreadMatched: true));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static async Task UpdateCacheAfterChatStored(Guid workspaceId, Guid chatId, string chatDirectory, string chatName, DateTimeOffset lastEditTime)
|
||||
{
|
||||
await WORKSPACE_TREE_CACHE_SEMAPHORE.WaitAsync();
|
||||
@@ -348,6 +434,55 @@ public static class WorkspaceBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<WorkspaceSearchSnapshot> SearchWorkspaceChatsAsync(string searchText, bool includeThreadContents, CancellationToken token = default)
|
||||
{
|
||||
var terms = ParseSearchTerms(searchText);
|
||||
if (terms.Count == 0)
|
||||
return new([], []);
|
||||
|
||||
List<WorkspaceTreeWorkspace> workspaces;
|
||||
List<WorkspaceTreeChat> temporaryChats;
|
||||
|
||||
await WORKSPACE_TREE_CACHE_SEMAPHORE.WaitAsync(token);
|
||||
try
|
||||
{
|
||||
await EnsureTreeShellLoadedCoreAsync();
|
||||
workspaces = [];
|
||||
foreach (var workspaceId in WORKSPACE_TREE_CACHE.WorkspaceOrder)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
if (!WORKSPACE_TREE_CACHE.Workspaces.TryGetValue(workspaceId, out var workspace))
|
||||
continue;
|
||||
|
||||
if (!workspace.ChatsLoaded)
|
||||
{
|
||||
workspace.Chats = await ReadWorkspaceChatsCoreAsync(workspaceId, workspace.WorkspacePath);
|
||||
workspace.ChatsLoaded = true;
|
||||
}
|
||||
|
||||
workspaces.Add(ToPublicWorkspace(workspace));
|
||||
}
|
||||
|
||||
temporaryChats = WORKSPACE_TREE_CACHE.TemporaryChats.Select(ToPublicChat).ToList();
|
||||
}
|
||||
finally
|
||||
{
|
||||
WORKSPACE_TREE_CACHE_SEMAPHORE.Release();
|
||||
}
|
||||
|
||||
var matchingWorkspaces = new List<WorkspaceSearchWorkspace>();
|
||||
foreach (var workspace in workspaces)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
var matchingChats = await SearchChatsAsync(workspace.Chats, terms, includeThreadContents, token);
|
||||
if (matchingChats.Count > 0)
|
||||
matchingWorkspaces.Add(new(workspace.WorkspaceId, workspace.WorkspacePath, workspace.Name, matchingChats));
|
||||
}
|
||||
|
||||
var matchingTemporaryChats = await SearchChatsAsync(temporaryChats, terms, includeThreadContents, token);
|
||||
return new(matchingWorkspaces, matchingTemporaryChats);
|
||||
}
|
||||
|
||||
public static async Task TryPrefetchRemainingChatsAsync(Func<Guid, Task>? onWorkspaceUpdated = null, CancellationToken token = default)
|
||||
{
|
||||
while (true)
|
||||
|
||||
Reference in new issue
Block a user