mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-02-13 21:21:36 +00:00
Add support for configurable transcription providers
This commit is contained in:
parent
ef33a4fc23
commit
ce8948880c
@ -33,18 +33,27 @@
|
||||
<MudTd>@context.Name</MudTd>
|
||||
<MudTd>@context.UsedLLMProvider.ToName()</MudTd>
|
||||
<MudTd>@GetTranscriptionProviderModelName(context)</MudTd>
|
||||
|
||||
|
||||
<MudTd>
|
||||
<MudStack Row="true" Class="mb-2 mt-2" Wrap="Wrap.Wrap">
|
||||
<MudTooltip Text="@T("Open Dashboard")">
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.OpenInBrowser" Href="@context.UsedLLMProvider.GetDashboardURL()" Target="_blank" Disabled="@(!context.UsedLLMProvider.HasDashboard())"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="@T("Edit")">
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Edit" OnClick="@(() => this.EditTranscriptionProvider(context))"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="@T("Delete")">
|
||||
<MudIconButton Color="Color.Error" Icon="@Icons.Material.Filled.Delete" OnClick="@(() => this.DeleteTranscriptionProvider(context))"/>
|
||||
</MudTooltip>
|
||||
<MudStack Row="true" Class="mb-2 mt-2" Spacing="1" Wrap="Wrap.Wrap">
|
||||
@if (context.IsEnterpriseConfiguration)
|
||||
{
|
||||
<MudTooltip Text="@T("This transcription provider is managed by your organization.")">
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Business" Disabled="true"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
else
|
||||
{
|
||||
<MudTooltip Text="@T("Open Dashboard")">
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.OpenInBrowser" Href="@context.UsedLLMProvider.GetDashboardURL()" Target="_blank" Disabled="@(!context.UsedLLMProvider.HasDashboard())"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="@T("Edit")">
|
||||
<MudIconButton Color="Color.Info" Icon="@Icons.Material.Filled.Edit" OnClick="@(() => this.EditTranscriptionProvider(context))"/>
|
||||
</MudTooltip>
|
||||
<MudTooltip Text="@T("Delete")">
|
||||
<MudIconButton Color="Color.Error" Icon="@Icons.Material.Filled.Delete" OnClick="@(() => this.DeleteTranscriptionProvider(context))"/>
|
||||
</MudTooltip>
|
||||
}
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
</RowTemplate>
|
||||
|
||||
@ -137,6 +137,8 @@ public partial class TranscriptionProviderDialog : MSGComponentBase, ISecretId
|
||||
IsSelfHosted = this.DataLLMProvider is LLMProviders.SELF_HOSTED,
|
||||
Hostname = cleanedHostname.EndsWith('/') ? cleanedHostname[..^1] : cleanedHostname,
|
||||
Host = this.DataHost,
|
||||
IsEnterpriseConfiguration = false,
|
||||
EnterpriseConfigurationPluginId = Guid.Empty,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -53,11 +53,11 @@ CONFIG["LLM_PROVIDERS"][#CONFIG["LLM_PROVIDERS"]+1] = {
|
||||
["Id"] = "00000000-0000-0000-0000-000000000000",
|
||||
["InstanceName"] = "<user-friendly name for the combination of server and model>",
|
||||
["UsedLLMProvider"] = "SELF_HOSTED",
|
||||
|
||||
|
||||
-- Allowed values for Host are: LM_STUDIO, LLAMACPP, OLLAMA, and VLLM
|
||||
["Host"] = "OLLAMA",
|
||||
["Hostname"] = "<https address of the server>",
|
||||
|
||||
|
||||
-- Optional: Additional parameters for the API.
|
||||
-- Please refer to the documentation of the selected host for details.
|
||||
-- Might be something like ... \"temperature\": 0.5 ... for one parameter.
|
||||
@ -70,6 +70,24 @@ CONFIG["LLM_PROVIDERS"][#CONFIG["LLM_PROVIDERS"]+1] = {
|
||||
}
|
||||
}
|
||||
|
||||
-- Transcription providers for voice-to-text functionality:
|
||||
CONFIG["TRANSCRIPTION_PROVIDERS"] = {}
|
||||
|
||||
-- An example of a transcription provider configuration:
|
||||
-- CONFIG["TRANSCRIPTION_PROVIDERS"][#CONFIG["TRANSCRIPTION_PROVIDERS"]+1] = {
|
||||
-- ["Id"] = "00000000-0000-0000-0000-000000000001",
|
||||
-- ["Name"] = "<user-friendly name for the transcription provider>",
|
||||
-- ["UsedLLMProvider"] = "SELF_HOSTED",
|
||||
--
|
||||
-- -- Allowed values for Host are: LM_STUDIO, LLAMACPP, OLLAMA, VLLM, and WHISPER_CPP
|
||||
-- ["Host"] = "WHISPER_CPP",
|
||||
-- ["Hostname"] = "<https address of the server>",
|
||||
-- ["Model"] = {
|
||||
-- ["Id"] = "<the model ID>",
|
||||
-- ["DisplayName"] = "<user-friendly name of the model>",
|
||||
-- }
|
||||
-- }
|
||||
|
||||
CONFIG["SETTINGS"] = {}
|
||||
|
||||
-- Configure the update check interval:
|
||||
@ -101,6 +119,12 @@ CONFIG["SETTINGS"] = {}
|
||||
-- Please note: using an empty string ("") will lock the preselected profile selection, even though no valid preselected profile is found.
|
||||
-- CONFIG["SETTINGS"]["DataApp.PreselectedProfile"] = "00000000-0000-0000-0000-000000000000"
|
||||
|
||||
-- Configure the transcription provider for voice-to-text functionality.
|
||||
-- It must be one of the transcription provider IDs defined in CONFIG["TRANSCRIPTION_PROVIDERS"].
|
||||
-- Without a selected transcription provider, dictation and transcription features will be disabled.
|
||||
-- Please note: using an empty string ("") will lock the selection and disable dictation/transcription.
|
||||
-- CONFIG["SETTINGS"]["DataApp.UseTranscriptionProvider"] = "00000000-0000-0000-0000-000000000000"
|
||||
|
||||
-- Example chat templates for this configuration:
|
||||
CONFIG["CHAT_TEMPLATES"] = {}
|
||||
|
||||
|
||||
@ -1,32 +1,134 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
|
||||
using Lua;
|
||||
|
||||
using Host = AIStudio.Provider.SelfHosted.Host;
|
||||
|
||||
namespace AIStudio.Settings;
|
||||
|
||||
public readonly record struct TranscriptionProvider(
|
||||
public sealed record TranscriptionProvider(
|
||||
uint Num,
|
||||
string Id,
|
||||
string Name,
|
||||
LLMProviders UsedLLMProvider,
|
||||
Model Model,
|
||||
bool IsSelfHosted = false,
|
||||
bool IsEnterpriseConfiguration = false,
|
||||
Guid EnterpriseConfigurationPluginId = default,
|
||||
string Hostname = "http://localhost:1234",
|
||||
Host Host = Host.NONE) : ISecretId
|
||||
Host Host = Host.NONE) : ConfigurationBaseObject, ISecretId
|
||||
{
|
||||
private static readonly ILogger<TranscriptionProvider> LOGGER = Program.LOGGER_FACTORY.CreateLogger<TranscriptionProvider>();
|
||||
|
||||
public static readonly TranscriptionProvider NONE = new();
|
||||
|
||||
public TranscriptionProvider() : this(
|
||||
0,
|
||||
Guid.Empty.ToString(),
|
||||
string.Empty,
|
||||
LLMProviders.NONE,
|
||||
default,
|
||||
false,
|
||||
false,
|
||||
Guid.Empty)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToString() => this.Name;
|
||||
|
||||
|
||||
#region Implementation of ISecretId
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonIgnore]
|
||||
public string SecretId => this.Id;
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonIgnore]
|
||||
public string SecretName => this.Name;
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
public static bool TryParseTranscriptionProviderTable(int idx, LuaTable table, Guid configPluginId, out ConfigurationBaseObject provider)
|
||||
{
|
||||
provider = NONE;
|
||||
if (!table.TryGetValue("Id", out var idValue) || !idValue.TryRead<string>(out var idText) || !Guid.TryParse(idText, out var id))
|
||||
{
|
||||
LOGGER.LogWarning($"The configured transcription provider {idx} does not contain a valid ID. The ID must be a valid GUID.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!table.TryGetValue("Name", out var nameValue) || !nameValue.TryRead<string>(out var name))
|
||||
{
|
||||
LOGGER.LogWarning($"The configured transcription provider {idx} does not contain a valid name.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!table.TryGetValue("UsedLLMProvider", out var usedLLMProviderValue) || !usedLLMProviderValue.TryRead<string>(out var usedLLMProviderText) || !Enum.TryParse<LLMProviders>(usedLLMProviderText, true, out var usedLLMProvider))
|
||||
{
|
||||
LOGGER.LogWarning($"The configured transcription provider {idx} does not contain a valid LLM provider enum value.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!table.TryGetValue("Host", out var hostValue) || !hostValue.TryRead<string>(out var hostText) || !Enum.TryParse<Host>(hostText, true, out var host))
|
||||
{
|
||||
LOGGER.LogWarning($"The configured transcription provider {idx} does not contain a valid host enum value.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!table.TryGetValue("Hostname", out var hostnameValue) || !hostnameValue.TryRead<string>(out var hostname))
|
||||
{
|
||||
LOGGER.LogWarning($"The configured transcription provider {idx} does not contain a valid hostname.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!table.TryGetValue("Model", out var modelValue) || !modelValue.TryRead<LuaTable>(out var modelTable))
|
||||
{
|
||||
LOGGER.LogWarning($"The configured transcription provider {idx} does not contain a valid model table.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryReadModelTable(idx, modelTable, out var model))
|
||||
{
|
||||
LOGGER.LogWarning($"The configured transcription provider {idx} does not contain a valid model configuration.");
|
||||
return false;
|
||||
}
|
||||
|
||||
provider = new TranscriptionProvider
|
||||
{
|
||||
Num = 0,
|
||||
Id = id.ToString(),
|
||||
Name = name,
|
||||
UsedLLMProvider = usedLLMProvider,
|
||||
Model = model,
|
||||
IsSelfHosted = usedLLMProvider is LLMProviders.SELF_HOSTED,
|
||||
IsEnterpriseConfiguration = true,
|
||||
EnterpriseConfigurationPluginId = configPluginId,
|
||||
Hostname = hostname,
|
||||
Host = host,
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryReadModelTable(int idx, LuaTable table, out Model model)
|
||||
{
|
||||
model = default;
|
||||
if (!table.TryGetValue("Id", out var idValue) || !idValue.TryRead<string>(out var id))
|
||||
{
|
||||
LOGGER.LogWarning($"The configured transcription provider {idx} does not contain a valid model ID.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!table.TryGetValue("DisplayName", out var displayNameValue) || !displayNameValue.TryRead<string>(out var displayName))
|
||||
{
|
||||
LOGGER.LogWarning($"The configured transcription provider {idx} does not contain a valid model display name.");
|
||||
return false;
|
||||
}
|
||||
|
||||
model = new(id, displayName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -69,7 +69,10 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT
|
||||
|
||||
// Handle configured LLM providers:
|
||||
PluginConfigurationObject.TryParse(PluginConfigurationObjectType.LLM_PROVIDER, x => x.Providers, x => x.NextProviderNum, mainTable, this.Id, ref this.configObjects, dryRun);
|
||||
|
||||
|
||||
// Handle configured transcription providers:
|
||||
PluginConfigurationObject.TryParse(PluginConfigurationObjectType.TRANSCRIPTION_PROVIDER, x => x.TranscriptionProviders, x => x.NextTranscriptionNum, mainTable, this.Id, ref this.configObjects, dryRun);
|
||||
|
||||
// Handle configured chat templates:
|
||||
PluginConfigurationObject.TryParse(PluginConfigurationObjectType.CHAT_TEMPLATE, x => x.ChatTemplates, x => x.NextChatTemplateNum, mainTable, this.Id, ref this.configObjects, dryRun);
|
||||
|
||||
|
||||
@ -68,8 +68,9 @@ public sealed record PluginConfigurationObject
|
||||
PluginConfigurationObjectType.CHAT_TEMPLATE => "CHAT_TEMPLATES",
|
||||
PluginConfigurationObjectType.DATA_SOURCE => "DATA_SOURCES",
|
||||
PluginConfigurationObjectType.EMBEDDING_PROVIDER => "EMBEDDING_PROVIDERS",
|
||||
PluginConfigurationObjectType.TRANSCRIPTION_PROVIDER => "TRANSCRIPTION_PROVIDERS",
|
||||
PluginConfigurationObjectType.PROFILE => "PROFILES",
|
||||
|
||||
|
||||
_ => null,
|
||||
};
|
||||
|
||||
@ -102,7 +103,8 @@ public sealed record PluginConfigurationObject
|
||||
PluginConfigurationObjectType.LLM_PROVIDER => (Settings.Provider.TryParseProviderTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != Settings.Provider.NONE, configurationObject),
|
||||
PluginConfigurationObjectType.CHAT_TEMPLATE => (ChatTemplate.TryParseChatTemplateTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != ChatTemplate.NO_CHAT_TEMPLATE, configurationObject),
|
||||
PluginConfigurationObjectType.PROFILE => (Profile.TryParseProfileTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != Profile.NO_PROFILE, configurationObject),
|
||||
|
||||
PluginConfigurationObjectType.TRANSCRIPTION_PROVIDER => (TranscriptionProvider.TryParseTranscriptionProviderTable(i, luaObjectTable, configPluginId, out var configurationObject) && configurationObject != TranscriptionProvider.NONE, configurationObject),
|
||||
|
||||
_ => (false, NoConfigurationObject.INSTANCE)
|
||||
};
|
||||
|
||||
|
||||
@ -4,10 +4,11 @@ public enum PluginConfigurationObjectType
|
||||
{
|
||||
NONE,
|
||||
UNKNOWN,
|
||||
|
||||
|
||||
PROFILE,
|
||||
DATA_SOURCE,
|
||||
LLM_PROVIDER,
|
||||
CHAT_TEMPLATE,
|
||||
EMBEDDING_PROVIDER,
|
||||
TRANSCRIPTION_PROVIDER,
|
||||
}
|
||||
@ -132,7 +132,11 @@ public static partial class PluginFactory
|
||||
|
||||
// Check LLM providers:
|
||||
var wasConfigurationChanged = PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.LLM_PROVIDER, x => x.Providers, AVAILABLE_PLUGINS, configObjectList);
|
||||
|
||||
|
||||
// Check transcription providers:
|
||||
if(PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.TRANSCRIPTION_PROVIDER, x => x.TranscriptionProviders, AVAILABLE_PLUGINS, configObjectList))
|
||||
wasConfigurationChanged = true;
|
||||
|
||||
// Check chat templates:
|
||||
if(PluginConfigurationObject.CleanLeftOverConfigurationObjects(PluginConfigurationObjectType.CHAT_TEMPLATE, x => x.ChatTemplates, AVAILABLE_PLUGINS, configObjectList))
|
||||
wasConfigurationChanged = true;
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
- 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.
|
||||
- Added the option to use source code files in chats and document analysis. This supports software development workflows.
|
||||
- Added a preview feature that lets you record your own voice for transcription. The feature remains in development and appears only when the preview feature is enabled.
|
||||
- Added the option to configure transcription providers (for example, using Whisper models). As usual, there can be local as well as cloud models configured. This option is part of the transcription preview and remains hidden until the preview is activated or the feature gets released.
|
||||
- Added the option to configure transcription providers (for example, using Whisper models). As usual, there can be local as well as cloud models configured. This option is part of the transcription preview and remains hidden until the preview is activated or the feature gets released. Transcription providers can be configured through configuration plugins as well.
|
||||
- Added an option to the app settings to select a provider for transcribing dictated text. If no provider is selected, dictation and text transcription are disabled.
|
||||
- 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.
|
||||
- Fixed a bug in the profile selection where the "Use no profile" entry could not be localized, causing English text to appear in languages such as German. This behavior has now been fixed.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user