Compare commits

...
9 Commits
21 changed files with 230 additions and 136 deletions

No files matched your search

+15 -10
View File
@@ -7,15 +7,17 @@ Things we are currently working on:
- [x] ~~Runtime: Restructuring the code into meaningful modules (PR [#192](https://github.com/MindWorkAI/AI-Studio/pull/192))~~
- [x] ~~Define the [External Data API (EDI)](https://github.com/MindWorkAI/EDI) as a contract for integrating arbitrary external data (PR [#1](https://github.com/MindWorkAI/EDI/pull/1))~~
- [ ] App: Metadata for providers (which provider offers embeddings?)
- [ ] App: Management of data sources (local data)
- [x] ~~App: Metadata for providers (which provider offers embeddings?) (PR [#205](https://github.com/MindWorkAI/AI-Studio/pull/205))~~
- [ ] App: Add an option to show preview features
- [ ] App: Configure embedding providers
- [ ] App: Management of data sources (local & external data via [EDI](https://github.com/MindWorkAI/EDI))
- [ ] Runtime: Extract data from txt / md / pdf / docx / xlsx files
- [ ] App: Implement embedding providers
- [ ] App: Implement the process to vectorize local data using embeddings
- [ ] App: Implement the process to vectorize one local file using embeddings
- [ ] Runtime: Integration of the vector database [LanceDB](https://github.com/lancedb/lancedb)
- [ ] App: Implement the continuous process of vectorizing data
- [ ] App: Define an interface for the integration of RAG processes in chats
- [ ] App: Integrate data sources in chats
- [ ] App: Management of data sources (external data via [EDI](https://github.com/MindWorkAI/EDI))
- Since September 2024: Experiments have been started on how we can work on long texts with AI Studio. Let's say you want to write a fantasy novel or create a complex project proposal and use LLM for support. The initial experiments were promising, but not yet satisfactory. We are testing further approaches until a satisfactory solution is found. Related PR: [#167](https://github.com/MindWorkAI/AI-Studio/pull/167).
@@ -30,6 +32,7 @@ Other News:
Features we have recently released:
- v0.9.18: Added the new Anthropic Heiku model; added Groq and Google Gemini as provider options.
- v0.9.17: Added the new Anthropic model `claude-3-5-sonnet-20241022`.
- v0.9.16: Added workspace display options & improved the layout of the app window.
- v0.9.15: Added the bias-of-the-day assistant. Tells you about a cognitive bias every day.
@@ -47,7 +50,7 @@ MindWork AI Studio is a desktop application available for macOS, Windows, and Li
**Key advantages:**
- **Free of charge**: The app is free to use, both for personal and commercial purposes.
- **Independence**: You are not tied to any single provider. Instead, you can choose the provider that best suits their needs. Right now, we support OpenAI (GPT4o etc.), Mistral, Anthropic (Claude), and self-hosted models using [llama.cpp](https://github.com/ggerganov/llama.cpp), [ollama](https://github.com/ollama/ollama), [LM Studio](https://lmstudio.ai/), or [Fireworks](https://fireworks.ai/). Support for Google Gemini, and [Replicate](https://replicate.com/) is planned.
- **Independence**: You are not tied to any single provider. Instead, you can choose the provider that best suits their needs. Right now, we support OpenAI (GPT4o etc.), Mistral, Anthropic (Claude), Google Gemini, and self-hosted models using [llama.cpp](https://github.com/ggerganov/llama.cpp), [ollama](https://github.com/ollama/ollama), [LM Studio](https://lmstudio.ai/), [Groq](https://groq.com/), or [Fireworks](https://fireworks.ai/).
- **Unrestricted usage**: Unlike services like ChatGPT, which impose limits after intensive use, MindWork AI Studio offers unlimited usage through the providers API.
- **Cost-effective**: You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit.
- **Privacy**: The data entered into the app is not used for training by the providers since we are using the provider's API.
@@ -71,11 +74,13 @@ To view all available tiers, please visit our [GitHub Sponsors page](https://git
Your support, whether big or small, keeps the wheels turning and is deeply appreciated ❤️.
## Planned Features
Here's an exciting look at some of the features we're planning to add to MindWork AI Studio in future releases:
- **More providers**: We plan to add support for additional LLM providers, such as Google Gemini, giving you more options to choose from.
- **System prompts**: Integration of a system prompt library will allow you to control the behavior of the LLM with predefined prompts, ensuring consistency and efficiency.
- **Text replacement for better privacy**: Define keywords that will be replaced in your chats before sending content to the provider, enhancing your privacy.
- **Advanced interactions**: We're full of ideas for advanced interactions tailored for specific use cases, whether in a business context or for writers and other professionals.
Here's an exciting look at some of the features we're planning to add to AI Studio in future releases:
- **Integrating your data**: You should be able to integrate your data into AI Studio. For example, your PDF or Office files, or your Markdown notes.
- **Integration of enterprise data:** Soon, it will also be possible to integrate data from the corporate network using an interface that we have specified ([External Data API](https://github.com/MindWorkAI/EDI), EDI for short).
- **Writing mode:** We want to integrate a writing mode that should support you in creating extensive works. We are thinking of comprehensive project proposals, tenders, or your next fantasy novel.
- **Browser usage:** We're trying to offer the features from AI Studio to you in the browser via a plugin, so we could use spell-checking or rewriting text directly in the browser.
- **Voice control:** You should be able to interact with the AI systems using your voice as well. To achieve this, we want to integrate voice input (speech-to-text) and output (text-to-speech). However, later on, it should also have a natural conversation flow, i.e., seamless conversation.
- **Email monitoring:** You should have the option to connect your email inboxes with AI Studio. The AI reads your emails and sends you a notification when something important happens. At the same time, you can access knowledge from your emails in your chats.
Stay tuned for more updates and enhancements to make MindWork AI Studio even more powerful and versatile 🤩.
@@ -128,7 +128,7 @@ public partial class BiasOfTheDayAssistant : AssistantBaseCore
ChatId = this.SettingsManager.ConfigurationData.BiasOfTheDay.BiasOfTheDayChatId,
};
if (Workspaces.IsChatExisting(biasChat))
if (WorkspaceBehaviour.IsChatExisting(biasChat))
{
MessageBus.INSTANCE.DeferMessage(this, Event.LOAD_CHAT, biasChat);
this.NavigationManager.NavigateTo(Routes.CHAT);
+1 -1
View File
@@ -40,7 +40,7 @@ public sealed class ContentText : IContent
if(chatThread is null)
return;
// Store the last time we got a response. We use this ater
// Store the last time we got a response. We use this later
// to determine whether we should notify the UI about the
// new content or not. Depends on the energy saving mode
// the user chose.
@@ -13,6 +13,8 @@ public partial class Changelog
public static readonly Log[] LOGS =
[
new (195, "v0.9.20, build 195 (2024-11-16 20:44 UTC)", "v0.9.20.md"),
new (194, "v0.9.19, build 194 (2024-11-14 05:58 UTC)", "v0.9.19.md"),
new (193, "v0.9.18, build 193 (2024-11-09 21:10 UTC)", "v0.9.18.md"),
new (192, "v0.9.17, build 192 (2024-11-03 11:11 UTC)", "v0.9.17.md"),
new (191, "v0.9.16, build 191 (2024-11-02 22:04 UTC)", "v0.9.16.md"),
@@ -6,11 +6,11 @@ public partial class Vision : ComponentBase
{
private static readonly TextItem[] ITEMS_VISION =
[
new TextItem("Meet your needs", "Whatever your job or task is, MindWork AI Studio aims to meet your needs: whether you're a project manager, scientist, artist, author, software developer, or game developer."),
new TextItem("One stop shop", "The app will strive to fulfill all your AI needs: text-generation AI (LLM), image-generation AI, audio-generation AI (text-to-speech, potentially even text-to-music), and audio input (transcription, dictation). When there's a provider and an API available, we'll try to integrate it."),
new TextItem("Local file system", "When you wish, we aim to integrate your local system. Local documents could be incorporated using Retrieval-Augmented Generation (RAG), and we could directly save AI-generated content to your file system."),
new TextItem("Local AI systems", "Want to use AI systems locally and offline? We aim to make that possible too."),
new TextItem("Your AI systems", "Prefer to run your AI systems with providers like replicate.com? We plan to support that!"),
new TextItem("Assistants", "We aim to integrate specialized user interfaces as assistants. For example, a UI specifically for writing emails, or one designed for translating and correcting text, and more."),
new("Meet your needs", "Whatever your job or task is, MindWork AI Studio aims to meet your needs: whether you're a project manager, scientist, artist, author, software developer, or game developer."),
new("One stop shop", "The app will strive to fulfill all your AI needs: text-generation AI (LLM), image-generation AI, audio-generation AI (text-to-speech, potentially even text-to-music), and audio input (transcription, dictation). When there's a provider and an API available, we'll try to integrate it."),
new("Local file system", "When you wish, we aim to integrate your local system. Local documents could be incorporated using Retrieval-Augmented Generation (RAG), and we could directly save AI-generated content to your file system."),
new("Local AI systems", "Want to use AI systems locally and offline? We aim to make that possible too."),
new("Your AI systems", "Prefer to run your AI systems with providers like replicate.com? We plan to support that!"),
new("Assistants", "We aim to integrate specialized user interfaces as assistants. For example, a UI specifically for writing emails, or one designed for translating and correcting text, and more."),
];
}
@@ -1,6 +1,5 @@
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using AIStudio.Chat;
using AIStudio.Dialogs;
@@ -41,18 +40,6 @@ public partial class Workspaces : ComponentBase
private const Placement WORKSPACE_ITEM_TOOLTIP_PLACEMENT = Placement.Bottom;
public static readonly Guid WORKSPACE_ID_BIAS = Guid.Parse("82050a4e-ee92-43d7-8ee5-ab512f847e02");
private static readonly JsonSerializerOptions JSON_OPTIONS = new()
{
WriteIndented = true,
AllowTrailingCommas = true,
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.SnakeCaseUpper),
}
};
private readonly List<TreeItemData<ITreeItem>> treeItems = new();
@@ -160,16 +147,6 @@ public partial class Workspaces : ComponentBase
return result;
}
public async Task<string> LoadWorkspaceName(Guid workspaceId)
{
if(workspaceId == Guid.Empty)
return string.Empty;
var workspacePath = Path.Join(SettingsManager.DataDirectory, "workspaces", workspaceId.ToString());
var workspaceNamePath = Path.Join(workspacePath, "name");
return await File.ReadAllTextAsync(workspaceNamePath, Encoding.UTF8);
}
private async Task<IReadOnlyCollection<TreeItemData<ITreeItem>>> LoadWorkspaces()
{
var workspaces = new List<TreeItemData<ITreeItem>>();
@@ -261,22 +238,7 @@ public partial class Workspaces : ComponentBase
public async Task StoreChat(ChatThread chat, bool reloadTreeItems = true)
{
string chatDirectory;
if (chat.WorkspaceId == Guid.Empty)
chatDirectory = Path.Join(SettingsManager.DataDirectory, "tempChats", chat.ChatId.ToString());
else
chatDirectory = Path.Join(SettingsManager.DataDirectory, "workspaces", chat.WorkspaceId.ToString(), chat.ChatId.ToString());
// Ensure the directory exists:
Directory.CreateDirectory(chatDirectory);
// Save the chat name:
var chatNamePath = Path.Join(chatDirectory, "name");
await File.WriteAllTextAsync(chatNamePath, chat.Name);
// Save the thread as thread.json:
var chatPath = Path.Join(chatDirectory, "thread.json");
await File.WriteAllTextAsync(chatPath, JsonSerializer.Serialize(chat, JSON_OPTIONS), Encoding.UTF8);
await WorkspaceBehaviour.StoreChat(chat);
// Reload the tree items:
if(reloadTreeItems)
@@ -284,24 +246,6 @@ public partial class Workspaces : ComponentBase
this.StateHasChanged();
}
public async Task LoadChat(LoadChat loadChat)
{
var chatPath = loadChat.WorkspaceId == Guid.Empty
? Path.Join(SettingsManager.DataDirectory, "tempChats", loadChat.ChatId.ToString())
: Path.Join(SettingsManager.DataDirectory, "workspaces", loadChat.WorkspaceId.ToString(), loadChat.ChatId.ToString());
await this.LoadChat(chatPath, switchToChat: true);
}
public static bool IsChatExisting(LoadChat loadChat)
{
var chatPath = loadChat.WorkspaceId == Guid.Empty
? Path.Join(SettingsManager.DataDirectory, "tempChats", loadChat.ChatId.ToString())
: Path.Join(SettingsManager.DataDirectory, "workspaces", loadChat.WorkspaceId.ToString(), loadChat.ChatId.ToString());
return Directory.Exists(chatPath);
}
private async Task<ChatThread?> LoadChat(string? chatPath, bool switchToChat)
{
@@ -328,7 +272,7 @@ public partial class Workspaces : ComponentBase
try
{
var chatData = await File.ReadAllTextAsync(Path.Join(chatPath, "thread.json"), Encoding.UTF8);
var chat = JsonSerializer.Deserialize<ChatThread>(chatData, JSON_OPTIONS);
var chat = JsonSerializer.Deserialize<ChatThread>(chatData, WorkspaceBehaviour.JSON_OPTIONS);
if (switchToChat)
{
this.CurrentChatThread = chat;
@@ -354,7 +298,7 @@ public partial class Workspaces : ComponentBase
if (askForConfirmation)
{
var workspaceName = await this.LoadWorkspaceName(chat.WorkspaceId);
var workspaceName = await WorkspaceBehaviour.LoadWorkspaceName(chat.WorkspaceId);
var dialogParameters = new DialogParameters
{
{
@@ -419,7 +363,7 @@ public partial class Workspaces : ComponentBase
return;
var workspaceId = Guid.Parse(Path.GetFileName(workspacePath));
var workspaceName = await this.LoadWorkspaceName(workspaceId);
var workspaceName = await WorkspaceBehaviour.LoadWorkspaceName(workspaceId);
var dialogParameters = new DialogParameters
{
{ "Message", $"Please enter a new or edit the name for your workspace '{workspaceName}':" },
@@ -482,7 +426,7 @@ public partial class Workspaces : ComponentBase
return;
var workspaceId = Guid.Parse(Path.GetFileName(workspacePath));
var workspaceName = await this.LoadWorkspaceName(workspaceId);
var workspaceName = await WorkspaceBehaviour.LoadWorkspaceName(workspaceId);
// Determine how many chats are in the workspace:
var chatCount = Directory.EnumerateDirectories(workspacePath).Count();
@@ -572,7 +516,7 @@ public partial class Workspaces : ComponentBase
ChatId = Guid.NewGuid(),
Name = string.Empty,
Seed = this.RNG.Next(),
SystemPrompt = "You are a helpful assistant!",
SystemPrompt = SystemPrompts.DEFAULT,
Blocks = [],
};
@@ -99,17 +99,21 @@ public partial class ProviderDialog : ComponentBase
private readonly List<Model> availableModels = new();
private readonly Encryption encryption = Program.ENCRYPTION;
private Settings.Provider CreateProviderSettings() => new()
private Settings.Provider CreateProviderSettings()
{
Num = this.DataNum,
Id = this.DataId,
InstanceName = this.DataInstanceName,
UsedLLMProvider = this.DataLLMProvider,
Model = this.DataLLMProvider is LLMProviders.FIREWORKS ? new Model(this.dataManuallyModel, null) : this.DataModel,
IsSelfHosted = this.DataLLMProvider is LLMProviders.SELF_HOSTED,
Hostname = this.DataHostname.EndsWith('/') ? this.DataHostname[..^1] : this.DataHostname,
Host = this.DataHost,
};
var cleanedHostname = this.DataHostname.Trim();
return new()
{
Num = this.DataNum,
Id = this.DataId,
InstanceName = this.DataInstanceName,
UsedLLMProvider = this.DataLLMProvider,
Model = this.DataLLMProvider is LLMProviders.FIREWORKS ? new Model(this.dataManuallyModel, null) : this.DataModel,
IsSelfHosted = this.DataLLMProvider is LLMProviders.SELF_HOSTED,
Hostname = cleanedHostname.EndsWith('/') ? cleanedHostname[..^1] : cleanedHostname,
Host = this.DataHost,
};
}
#region Overrides of ComponentBase
@@ -45,9 +45,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.11.70" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.10" />
<PackageReference Include="MudBlazor" Version="7.14.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.71" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.11" />
<PackageReference Include="MudBlazor" Version="7.15.0" />
<PackageReference Include="MudBlazor.Markdown" Version="7.14.0" />
<PackageReference Include="ReverseMarkdown" Version="4.6.0" />
</ItemGroup>
+18 -11
View File
@@ -112,18 +112,19 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && this.workspaces is not null && this.chatThread is not null && this.mustStoreChat)
if (firstRender && this.chatThread is not null && this.mustStoreChat)
{
this.mustStoreChat = false;
await this.workspaces.StoreChat(this.chatThread, false);
await WorkspaceBehaviour.StoreChat(this.chatThread);
this.currentWorkspaceId = this.chatThread.WorkspaceId;
this.currentWorkspaceName = await this.workspaces.LoadWorkspaceName(this.chatThread.WorkspaceId);
this.currentWorkspaceName = await WorkspaceBehaviour.LoadWorkspaceName(this.chatThread.WorkspaceId);
}
if (firstRender && this.workspaces is not null && this.mustLoadChat)
if (firstRender && this.mustLoadChat)
{
this.mustLoadChat = false;
await this.workspaces.LoadChat(this.loadChat);
this.chatThread = await WorkspaceBehaviour.LoadChat(this.loadChat);
this.StateHasChanged();
}
if(this.mustScrollToBottomAfterRender)
@@ -323,16 +324,22 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable
private async Task SaveThread()
{
if(this.workspaces is null)
return;
if(this.chatThread is null)
return;
if (!this.CanThreadBeSaved)
return;
//
// When the workspace component is visible, we store the chat
// through the workspace component. The advantage of this is that
// the workspace gets updated automatically when the chat is saved.
//
if (this.workspaces is not null)
await this.workspaces.StoreChat(this.chatThread);
else
await WorkspaceBehaviour.StoreChat(this.chatThread);
await this.workspaces.StoreChat(this.chatThread);
this.hasUnsavedChanges = false;
}
@@ -462,7 +469,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable
await this.SaveThread();
this.currentWorkspaceId = this.chatThread.WorkspaceId;
this.currentWorkspaceName = await this.workspaces.LoadWorkspaceName(this.chatThread.WorkspaceId);
this.currentWorkspaceName = await WorkspaceBehaviour.LoadWorkspaceName(this.chatThread.WorkspaceId);
}
private async Task LoadedChatChanged()
@@ -474,7 +481,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable
this.hasUnsavedChanges = false;
this.userInput = string.Empty;
this.currentWorkspaceId = this.chatThread?.WorkspaceId ?? Guid.Empty;
this.currentWorkspaceName = this.chatThread is null ? string.Empty : await this.workspaces.LoadWorkspaceName(this.chatThread.WorkspaceId);
this.currentWorkspaceName = this.chatThread is null ? string.Empty : await WorkspaceBehaviour.LoadWorkspaceName(this.chatThread.WorkspaceId);
this.userInput = string.Empty;
if (this.SettingsManager.ConfigurationData.Chat.ShowLatestMessageAfterLoading)
+7 -7
View File
@@ -32,13 +32,13 @@ public partial class Home : ComponentBase
private static readonly TextItem[] ITEMS_ADVANTAGES =
[
new TextItem("Free of charge", "The app is free to use, both for personal and commercial purposes."),
new TextItem("Independence", "You are not tied to any single provider. Instead, you might choose the provider that best suits your needs. Right now, we support OpenAI (GPT4o etc.), Mistral, Anthropic (Claude), and self-hosted models using llama.cpp, ollama, LM Studio, or Fireworks. Support for Google Gemini and Replicate is planned."),
new TextItem("Unrestricted usage", "Unlike services like ChatGPT, which impose limits after intensive use, MindWork AI Studio offers unlimited usage through the providers API."),
new TextItem("Cost-effective", "You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit."),
new TextItem("Privacy", "The data entered into the app is not used for training by the providers since we are using the provider's API."),
new TextItem("Flexibility", "Choose the provider and model best suited for your current task."),
new TextItem("No bloatware", "The app requires minimal storage for installation and operates with low memory usage. Additionally, it has a minimal impact on system resources, which is beneficial for battery life."),
new("Free of charge", "The app is free to use, both for personal and commercial purposes."),
new("Independence", "You are not tied to any single provider. Instead, you might choose the provider that best suits your needs. Right now, we support OpenAI (GPT4o etc.), Mistral, Anthropic (Claude), Google Gemini, and self-hosted models using llama.cpp, ollama, LM Studio, Groq, or Fireworks."),
new("Unrestricted usage", "Unlike services like ChatGPT, which impose limits after intensive use, MindWork AI Studio offers unlimited usage through the providers API."),
new("Cost-effective", "You only pay for what you use, which can be cheaper than monthly subscription services like ChatGPT Plus, especially if used infrequently. But beware, here be dragons: For extremely intensive usage, the API costs can be significantly higher. Unfortunately, providers currently do not offer a way to display current costs in the app. Therefore, check your account with the respective provider to see how your costs are developing. When available, use prepaid and set a cost limit."),
new("Privacy", "The data entered into the app is not used for training by the providers since we are using the provider's API."),
new("Flexibility", "Choose the provider and model best suited for your current task."),
new("No bloatware", "The app requires minimal storage for installation and operates with low memory usage. Additionally, it has a minimal impact on system resources, which is beneficial for battery life."),
];
private const string QUICK_START_GUIDE =
@@ -36,6 +36,13 @@
<Supporter Name="richard-stanton" Type="SupporterType.INDIVIDUAL" URL="https://github.com/richard-stanton" Acknowledgment="Thank you, Richard, for being the first."/>
<Supporter Name="peerschuett" Type="SupporterType.INDIVIDUAL" URL="https://github.com/peerschuett" Acknowledgment="Thank you, Peer, for your courage in being the second person to support the project financially."/>
</MudList>
<MudText Typo="Typo.h6" Class="mt-8">
The first 10 supporters who make a one-time contribution:
</MudText>
<MudList T="string">
<Supporter Name="Bessieres" Type="SupporterType.INDIVIDUAL" URL="https://github.com/Bessieres" Acknowledgment="Thank you for being the first to contribute a one-time donation."/>
</MudList>
</MudPaper>
</MudItem>
@@ -65,6 +65,35 @@ public static class LLMProvidersExtensions
_ => Confidence.UNKNOWN.WithLevel(settingsManager.GetConfiguredConfidenceLevel(llmProvider)),
};
/// <summary>
/// Determines if the specified provider supports embeddings.
/// </summary>
/// <param name="llmProvider">The provider to check.</param>
/// <returns>True if the provider supports embeddings; otherwise, false.</returns>
public static bool ProvideEmbeddings(this LLMProviders llmProvider) => llmProvider switch
{
//
// Providers that support embeddings:
//
LLMProviders.OPEN_AI => true,
LLMProviders.MISTRAL => true,
LLMProviders.GOOGLE => true,
//
// Providers that do not support embeddings:
//
LLMProviders.GROQ => false,
LLMProviders.ANTHROPIC => false,
LLMProviders.FIREWORKS => false,
//
// Self-hosted providers are treated as a special case anyway.
//
LLMProviders.SELF_HOSTED => false,
_ => false,
};
/// <summary>
/// Creates a new provider instance based on the provider value.
/// </summary>
@@ -0,0 +1,84 @@
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using AIStudio.Chat;
using AIStudio.Settings;
namespace AIStudio.Tools;
public static class WorkspaceBehaviour
{
public static readonly JsonSerializerOptions JSON_OPTIONS = new()
{
WriteIndented = true,
AllowTrailingCommas = true,
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
Converters =
{
new JsonStringEnumConverter(JsonNamingPolicy.SnakeCaseUpper),
}
};
public static bool IsChatExisting(LoadChat loadChat)
{
var chatPath = loadChat.WorkspaceId == Guid.Empty
? Path.Join(SettingsManager.DataDirectory, "tempChats", loadChat.ChatId.ToString())
: Path.Join(SettingsManager.DataDirectory, "workspaces", loadChat.WorkspaceId.ToString(), loadChat.ChatId.ToString());
return Directory.Exists(chatPath);
}
public static async Task StoreChat(ChatThread chat)
{
string chatDirectory;
if (chat.WorkspaceId == Guid.Empty)
chatDirectory = Path.Join(SettingsManager.DataDirectory, "tempChats", chat.ChatId.ToString());
else
chatDirectory = Path.Join(SettingsManager.DataDirectory, "workspaces", chat.WorkspaceId.ToString(), chat.ChatId.ToString());
// Ensure the directory exists:
Directory.CreateDirectory(chatDirectory);
// Save the chat name:
var chatNamePath = Path.Join(chatDirectory, "name");
await File.WriteAllTextAsync(chatNamePath, chat.Name);
// Save the thread as thread.json:
var chatPath = Path.Join(chatDirectory, "thread.json");
await File.WriteAllTextAsync(chatPath, JsonSerializer.Serialize(chat, JSON_OPTIONS), Encoding.UTF8);
}
public static async Task<ChatThread?> LoadChat(LoadChat loadChat)
{
var chatPath = loadChat.WorkspaceId == Guid.Empty
? Path.Join(SettingsManager.DataDirectory, "tempChats", loadChat.ChatId.ToString())
: Path.Join(SettingsManager.DataDirectory, "workspaces", loadChat.WorkspaceId.ToString(), loadChat.ChatId.ToString());
if(!Directory.Exists(chatPath))
return null;
try
{
var chatData = await File.ReadAllTextAsync(Path.Join(chatPath, "thread.json"), Encoding.UTF8);
var chat = JsonSerializer.Deserialize<ChatThread>(chatData, JSON_OPTIONS);
return chat;
}
catch (Exception)
{
return null;
}
}
public static async Task<string> LoadWorkspaceName(Guid workspaceId)
{
if(workspaceId == Guid.Empty)
return string.Empty;
var workspacePath = Path.Join(SettingsManager.DataDirectory, "workspaces", workspaceId.ToString());
var workspaceNamePath = Path.Join(workspacePath, "name");
return await File.ReadAllTextAsync(workspaceNamePath, Encoding.UTF8);
}
}
+5 -2
View File
@@ -63,8 +63,11 @@ def "main fix_web_assets" []: nothing -> nothing {
mkdir wwwroot/system
# Copy the web assets from the first RID to the source project:
let source_path: glob = $"bin/release/net8.0/($rid)/publish/wwwroot/_content/*"
cp --recursive --force --update $source_path wwwroot/system/
let source_paths = glob --depth 99 bin/release/net8.0/($rid)/publish/wwwroot/_content/*
for source_path in $source_paths {
cp --recursive --force --update $source_path wwwroot/system/
}
}
def "main publish" []: nothing -> nothing {
+13 -13
View File
@@ -4,30 +4,30 @@
"net8.0": {
"HtmlAgilityPack": {
"type": "Direct",
"requested": "[1.11.70, )",
"resolved": "1.11.70",
"contentHash": "lwCgdq4H+WXH+lkM7TvJhyEs5uNGzoTud1VmXz2jr30/yOTRtG/oMCour5JMTN0t0fU4uFwFYIrDd98FH2RKsQ=="
"requested": "[1.11.71, )",
"resolved": "1.11.71",
"contentHash": "HlEThQBnob4/29DIiyrPSYlGXXSZUtOH7571PRev+yu8FW8n5pdxqHyun+PMm17cp3ovCrxFhXedC+1HUSdRMA=="
},
"Microsoft.Extensions.FileProviders.Embedded": {
"type": "Direct",
"requested": "[8.0.10, )",
"resolved": "8.0.10",
"contentHash": "N/Ow71LLKXbC4fOFoAG7QNyyhgRypd8in8lc92xInZyyNFlBTgGR3R1BV91Wr5+1/l9+Qvo+2Ee2cAth43OP/Q==",
"requested": "[8.0.11, )",
"resolved": "8.0.11",
"contentHash": "1tn+c7d628+dASqo0UezdeWdKrEpp2XA376MUkr4nFYDj295iPWeWOV8rOvgR0Gma1xfOEjNJur1QvS6AVnjng==",
"dependencies": {
"Microsoft.Extensions.FileProviders.Abstractions": "8.0.0"
}
},
"Microsoft.NET.ILLink.Tasks": {
"type": "Direct",
"requested": "[8.0.10, )",
"resolved": "8.0.10",
"contentHash": "xT8jYjlroY7SLbGtoV9vUTVW/TPgodL4Egc31a444Xe0TMytLZ3UlKQ0kxMZsy/CrWsFB6wtKnSG1SsXcWreew=="
"requested": "[8.0.11, )",
"resolved": "8.0.11",
"contentHash": "zk5lnZrYJgtuJG8L4v17Ej8rZ3PUcR2iweNV08BaO5LbYHIi2wNaVNcJoLxvqgQdnjLlKnCCfVGLDr6QHeAarQ=="
},
"MudBlazor": {
"type": "Direct",
"requested": "[7.14.0, )",
"resolved": "7.14.0",
"contentHash": "hpuNSlI6/BVCe4H6X4BoHijxMffFE1ldunvFzAFZRTGuSGoYC7N6IIUv64MN3F/hkiRllx3gtivTZjivymxIpQ==",
"requested": "[7.15.0, )",
"resolved": "7.15.0",
"contentHash": "b2+hO7ZTGwsGhu9SoowuNe2ETeF1GzExpg/hIYR++rSh+vy4v/QD0iOsrATWv3LdFJXSgk3d1+XIr5srW3jBiA==",
"dependencies": {
"Microsoft.AspNetCore.Components": "8.0.8",
"Microsoft.AspNetCore.Components.Web": "8.0.8",
@@ -178,6 +178,6 @@
"contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA=="
}
},
"net8.0/osx-arm64": {}
"net8.0/osx-x64": {}
}
}
@@ -0,0 +1,7 @@
# v0.9.19, build 194 (2024-11-14 05:58 UTC)
- Added provider's metadata: which providers offer embeddings for RAG? This is in preparation for integrating your data and files.
- Added `Bessieres` as a one-time contributor. Thank you for your support.
- Fixed a bug regarding hostnames of self-hosted providers, where it was possible to enter spaces at the end.
- Upgraded .NET to v8.0.11.
- Upgraded HtmlAgilityPack to v1.11.71.
- Upgraded MudBlazor to v7.15.0.
@@ -0,0 +1,2 @@
# v0.9.20, build 195 (2024-11-16 20:44 UTC)
- Fixed bugs related to storing and loading chats when the workspaces were docked to the left and were collapsed.
+7 -7
View File
@@ -1,9 +1,9 @@
0.9.18
2024-11-09 21:10:03 UTC
193
8.0.110 (commit 87a66bb3d1)
8.0.10 (commit 81cabf2857)
0.9.20
2024-11-15 20:44:07 UTC
195
8.0.111 (commit f3835a7fb4)
8.0.11 (commit 9cb3b725e3)
1.82.0 (commit f6e511eec)
7.14.0
7.15.0
1.8.1
826d15729b5, release
ca46dde69c0, release
+1 -1
View File
@@ -2174,7 +2174,7 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mindwork-ai-studio"
version = "0.9.18"
version = "0.9.20"
dependencies = [
"aes",
"arboard",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "mindwork-ai-studio"
version = "0.9.18"
version = "0.9.20"
edition = "2021"
description = "MindWork AI Studio"
authors = ["Thorsten Sommer"]
+1 -1
View File
@@ -6,7 +6,7 @@
},
"package": {
"productName": "MindWork AI Studio",
"version": "0.9.18"
"version": "0.9.20"
},
"tauri": {
"allowlist": {