Added a configurable Opus bitrate for audio transcription

This commit is contained in:
Dominic Neuburg committed 2026-09-18 09:54:33 +02:00
1 parent 557d0b1409
commit 6be958eb92
14 files changed
+140 -20

No files matched your search

@@ -4993,6 +4993,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T16
-- Uses the provider-configured model
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T1760715963"] = "Uses the provider-configured model"
-- Higher bitrates can improve transcription accuracy, especially for quiet or noisy recordings, at the cost of a larger upload to the transcription provider. 128 kbps is recommended.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T1859657826"] = "Higher bitrates can improve transcription accuracy, especially for quiet or noisy recordings, at the cost of a larger upload to the transcription provider. 128 kbps is recommended."
-- Add Transcription Provider
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T2066315685"] = "Add Transcription Provider"
@@ -5005,6 +5008,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T21
-- Name
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T266367750"] = "Name"
-- Transcription audio quality
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T3103106744"] = "Transcription audio quality"
-- Edit
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T3267849393"] = "Edit"
@@ -10492,6 +10498,21 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::THEMESEXTENSIONS::T4107955313"]
-- Always use light theme
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::THEMESEXTENSIONS::T534715610"] = "Always use light theme"
-- 128 kbps (recommended)
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::TRANSCRIPTIONOPUSBITRATEEXTENSIONS::T2152168180"] = "128 kbps (recommended)"
-- 256 kbps (largest upload, highest accuracy)
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::TRANSCRIPTIONOPUSBITRATEEXTENSIONS::T3092489829"] = "256 kbps (largest upload, highest accuracy)"
-- Unknown
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::TRANSCRIPTIONOPUSBITRATEEXTENSIONS::T3424652889"] = "Unknown"
-- 64 kbps
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::TRANSCRIPTIONOPUSBITRATEEXTENSIONS::T3501477553"] = "64 kbps"
-- 32 kbps (smallest upload, lowest accuracy)
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::TRANSCRIPTIONOPUSBITRATEEXTENSIONS::T767394292"] = "32 kbps (smallest upload, lowest accuracy)"
-- Use no profile
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::PROFILE::T2205839602"] = "Use no profile"
@@ -12,7 +12,7 @@
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
@T("With the support of transcription models, MindWork AI Studio can convert human speech into text. This is useful, for example, when you need to dictate text. You can choose from dedicated transcription models, but not multimodal LLMs (large language models) that can handle both speech and text. The configuration of multimodal models is done in the 'Configure providers' section.")
</MudJustifiedText>
<MudTable Items="@this.SettingsManager.GetAllTranscriptionProviders()" Hover="@true" GroupBy="@GROUP_CONFIG" Class="border-dashed border rounded-lg">
<ColGroup>
<col style="width: 12em;"/>
@@ -84,5 +84,9 @@
}
<LockableButton Text="@T("Add transcription provider")" IsLocked="@(() => !this.SettingsManager.ConfigurationData.App.AllowUserToAddProvider || !this.SettingsManager.ConfigurationData.App.AllowUserToAddTranscriptionProvider)" Icon="@Icons.Material.Filled.AddRoad" OnClickAsync="@this.AddTranscriptionProvider" Class="mt-3" />
<MudDivider Class="mt-6 mb-3"/>
<ConfigurationSelect OptionDescription="@T("Transcription audio quality")" SelectedValue="@(() => this.SettingsManager.ConfigurationData.App.OpusBitrate)" Data="@ConfigurationSelectDataFactory.GetTranscriptionOpusBitrateData()" SelectionUpdate="@(selectedValue => this.SettingsManager.ConfigurationData.App.OpusBitrate = selectedValue)" OptionHelp="@this.OpusBitrateHelp" IsLocked="@this.IsOpusBitrateLocked"/>
</ExpansionPanel>
}
@@ -36,7 +36,11 @@ public partial class SettingsPanelTranscription : SettingsPanelProviderBase
var modelName = provider.Model.ToString();
return modelName.Length > MAX_LENGTH ? "[...] " + modelName[^Math.Min(MAX_LENGTH, modelName.Length)..] : modelName;
}
private string OpusBitrateHelp => T("Higher bitrates can improve transcription accuracy, especially for quiet or noisy recordings, at the cost of a larger upload to the transcription provider. 128 kbps is recommended.");
private bool IsOpusBitrateLocked() => ManagedConfiguration.TryGet(x => x.App, x => x.OpusBitrate, out var meta) && meta.IsLocked;
#region Overrides of ComponentBase
protected override async Task OnInitializedAsync()
@@ -578,6 +578,15 @@ CONFIG["SETTINGS"] = {}
-- Please note: using an empty string ("") will lock the selection and disable dictation/transcription.
-- CONFIG["SETTINGS"]["DataApp.UseTranscriptionProvider"] = "00000000-0000-0000-0000-000000000000"
-- Configure the Opus bitrate used when normalizing uploaded audio/video for transcription.
-- Allowed values are: KBPS_32, KBPS_64, KBPS_128, KBPS_256
-- Higher bitrates improve transcription accuracy on noisy or quiet recordings, at the cost of
-- a larger upload to the transcription provider. KBPS_128 is recommended.
-- CONFIG["SETTINGS"]["DataApp.OpusBitrate"] = "KBPS_32"
--
-- Allow the user to change the Opus bitrate even though your organization set a default above:
-- CONFIG["SETTINGS"]["DataApp.OpusBitrate.AllowUserOverride"] = true
-- Configure which assistants should be hidden from the UI.
-- Allowed values are:
-- GRAMMAR_SPELLING_ASSISTANT, ICON_FINDER_ASSISTANT, REWRITE_ASSISTANT,
@@ -4995,6 +4995,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T16
-- Uses the provider-configured model
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T1760715963"] = "Verwendet das vom Anbieter konfigurierte Modell"
-- Higher bitrates can improve transcription accuracy, especially for quiet or noisy recordings, at the cost of a larger upload to the transcription provider. 128 kbps is recommended.
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T1859657826"] = "Höhere Bitraten können die Transkriptionsgenauigkeit verbessern, besonders bei ruhigen oder lauten Aufnahmen, zum Nachteil eines größeren Uploads an den Transkriptionsdienstleister. 128 kbps wird empfohlen."
-- Add Transcription Provider
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T2066315685"] = "Anbieter für Transkriptionen hinzufügen"
@@ -5007,6 +5010,9 @@ UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T21
-- Name
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T266367750"] = "Name"
-- Transcription audio quality
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T3103106744"] = "Aufzeichnungsqualität für die Transkription"
-- Edit
UI_TEXT_CONTENT["AISTUDIO::COMPONENTS::SETTINGS::SETTINGSPANELTRANSCRIPTION::T3267849393"] = "Bearbeiten"
@@ -10494,6 +10500,21 @@ UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::THEMESEXTENSIONS::T4107955313"]
-- Always use light theme
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::THEMESEXTENSIONS::T534715610"] = "Immer das helle Design verwenden"
-- 128 kbps (recommended)
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::TRANSCRIPTIONOPUSBITRATEEXTENSIONS::T2152168180"] = "128 kbps (empfohlen)"
-- 256 kbps (largest upload, highest accuracy)
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::TRANSCRIPTIONOPUSBITRATEEXTENSIONS::T3092489829"] = "256 kbps (größter Upload, höchste Genauigkeit)"
-- Unknown
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::TRANSCRIPTIONOPUSBITRATEEXTENSIONS::T3424652889"] = "Bitte geben Sie den zu übersetzenden Text an."
-- 64 kbps
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::TRANSCRIPTIONOPUSBITRATEEXTENSIONS::T3501477553"] = "64 kbps"
-- 32 kbps (smallest upload, lowest accuracy)
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::DATAMODEL::TRANSCRIPTIONOPUSBITRATEEXTENSIONS::T767394292"] = "32 kbps (kleinster Upload, geringste Genauigkeit)"
-- Use no profile
UI_TEXT_CONTENT["AISTUDIO::SETTINGS::PROFILE::T2205839602"] = "Kein Profil verwenden"
@@ -323,4 +323,10 @@ public static class ConfigurationSelectDataFactory
yield return new(level.GetName(), level);
}
}
public static IEnumerable<ConfigurationSelectData<TranscriptionOpusBitrate>> GetTranscriptionOpusBitrateData()
{
foreach (var bitrate in Enum.GetValues<TranscriptionOpusBitrate>())
yield return new(bitrate.GetName(), bitrate);
}
}
@@ -112,6 +112,11 @@ public sealed class DataApp(Expression<Func<Data, DataApp>>? configSelection = n
/// </summary>
public string UseTranscriptionProvider { get; set; } = ManagedConfiguration.Register(configSelection, n => n.UseTranscriptionProvider, string.Empty);
/// <summary>
/// The Opus bitrate used when normalizing uploaded audio/video for transcription.
/// </summary>
public TranscriptionOpusBitrate OpusBitrate { get; set; } = ManagedConfiguration.Register(configSelection, n => n.OpusBitrate, TranscriptionOpusBitrate.KBPS_128);
/// <summary>
/// The global keyboard shortcut for toggling voice recording.
/// Uses Tauri's shortcut format, e.g., "CmdOrControl+1" (Cmd+1 on macOS, Ctrl+1 on Windows/Linux).
@@ -0,0 +1,9 @@
namespace AIStudio.Settings.DataModel;
public enum TranscriptionOpusBitrate
{
KBPS_32,
KBPS_64,
KBPS_128,
KBPS_256,
}
@@ -0,0 +1,26 @@
using AIStudio.Tools.PluginSystem;
namespace AIStudio.Settings.DataModel;
public static class TranscriptionOpusBitrateExtensions
{
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(TranscriptionOpusBitrateExtensions).Namespace, nameof(TranscriptionOpusBitrateExtensions));
public static string GetName(this TranscriptionOpusBitrate bitrate) => bitrate switch
{
TranscriptionOpusBitrate.KBPS_32 => TB("32 kbps (smallest upload, lowest accuracy)"),
TranscriptionOpusBitrate.KBPS_64 => TB("64 kbps"),
TranscriptionOpusBitrate.KBPS_128 => TB("128 kbps (recommended)"),
TranscriptionOpusBitrate.KBPS_256 => TB("256 kbps (largest upload, highest accuracy)"),
_ => TB("Unknown"),
};
public static uint GetBitsPerSecond(this TranscriptionOpusBitrate bitrate) => bitrate switch
{
TranscriptionOpusBitrate.KBPS_32 => 32_000,
TranscriptionOpusBitrate.KBPS_64 => 64_000,
TranscriptionOpusBitrate.KBPS_128 => 128_000,
TranscriptionOpusBitrate.KBPS_256 => 256_000,
_ => 32_000,
};
}
@@ -398,6 +398,9 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT
// Config: transcription provider?
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.UseTranscriptionProvider, Guid.Empty, this.Id, settingsTable, dryRun);
// Config: transcription Opus bitrate?
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.OpusBitrate, this.Id, settingsTable, dryRun);
message = string.Empty;
return true;
}
@@ -4,4 +4,5 @@ namespace AIStudio.Tools.Rust;
/// <param name="InputPath">Absolute source media path.</param>
/// <param name="OutputPath">Absolute operation-owned output path.</param>
/// <param name="MaxPassThroughBytes">Optional pass-through size ceiling.</param>
public sealed record CreateMediaJobRequest(string InputPath, string OutputPath, ulong? MaxPassThroughBytes = null);
/// <param name="OpusBitrateBps">Optional target Opus encoder bitrate in bits per second.</param>
public sealed record CreateMediaJobRequest(string InputPath, string OutputPath, ulong? MaxPassThroughBytes = null, uint? OpusBitrateBps = null);
@@ -1,6 +1,7 @@
using AIStudio.Chat;
using AIStudio.Provider;
using AIStudio.Settings;
using AIStudio.Settings.DataModel;
using AIStudio.Tools.Media;
using AIStudio.Tools.PluginSystem;
using AIStudio.Tools.Rust;
@@ -648,7 +649,8 @@ public sealed class MediaTranscriptionService(
{
// The quick POST is intentionally not cancelled: losing its response could orphan a job
// whose ID the client never received. Cancellation is applied immediately after ownership.
var jobId = await rustService.StartMediaJobAsync(mediaPath, normalizedPath, CancellationToken.None);
var opusBitrateBps = settingsManager.ConfigurationData.App.OpusBitrate.GetBitsPerSecond();
var jobId = await rustService.StartMediaJobAsync(mediaPath, normalizedPath, opusBitrateBps, CancellationToken.None);
operation.JobId = jobId;
try
@@ -10,13 +10,14 @@ public partial class RustService
/// <summary>Starts a Rust media normalization job.</summary>
/// <param name="inputPath">Absolute source path.</param>
/// <param name="outputPath">Absolute operation-owned output path.</param>
/// <param name="opusBitrateBps">Target Opus encoder bitrate in bits per second.</param>
/// <param name="token">Request cancellation token.</param>
/// <returns>The opaque runtime job identifier.</returns>
public async Task<string> StartMediaJobAsync(string inputPath, string outputPath, CancellationToken token = default)
public async Task<string> StartMediaJobAsync(string inputPath, string outputPath, uint opusBitrateBps, CancellationToken token = default)
{
using var response = await this.http.PostAsJsonAsync(
"/media/jobs",
new CreateMediaJobRequest(inputPath, outputPath),
new CreateMediaJobRequest(inputPath, outputPath, OpusBitrateBps: opusBitrateBps),
this.jsonRustSerializerOptions,
token);