diff --git a/app/MindWork AI Studio/Plugins/configuration/plugin.lua b/app/MindWork AI Studio/Plugins/configuration/plugin.lua index d3817cd3..8068531b 100644 --- a/app/MindWork AI Studio/Plugins/configuration/plugin.lua +++ b/app/MindWork AI Studio/Plugins/configuration/plugin.lua @@ -582,6 +582,9 @@ CONFIG["SETTINGS"] = {} -- 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. +-- Please note: this bitrate applies whenever a recording has to be re-encoded. A file which already +-- is a single mono 48 kHz Opus track in a WebM container and stays below 25 MiB is forwarded to the +-- transcription provider unchanged, keeping the bitrate it was created with. -- CONFIG["SETTINGS"]["DataApp.OpusBitrate"] = "KBPS_32" -- -- Allow the user to change the Opus bitrate even though your organization set a default above: diff --git a/app/MindWork AI Studio/Settings/ConfigurationSelectDataFactory.cs b/app/MindWork AI Studio/Settings/ConfigurationSelectDataFactory.cs index f54de705..d570d18d 100644 --- a/app/MindWork AI Studio/Settings/ConfigurationSelectDataFactory.cs +++ b/app/MindWork AI Studio/Settings/ConfigurationSelectDataFactory.cs @@ -327,6 +327,8 @@ public static class ConfigurationSelectDataFactory public static IEnumerable> GetTranscriptionOpusBitrateData() { foreach (var bitrate in Enum.GetValues()) + { yield return new(bitrate.GetName(), bitrate); + } } } diff --git a/app/MindWork AI Studio/Settings/DataModel/DataApp.cs b/app/MindWork AI Studio/Settings/DataModel/DataApp.cs index f1f8e0ba..fd485d76 100644 --- a/app/MindWork AI Studio/Settings/DataModel/DataApp.cs +++ b/app/MindWork AI Studio/Settings/DataModel/DataApp.cs @@ -115,6 +115,13 @@ public sealed class DataApp(Expression>? configSelection = n /// /// The Opus bitrate used when normalizing uploaded audio/video for transcription. /// + /// + /// Every recording is re-encoded to mono Opus before it goes to the transcription provider. That + /// encoding used to be fixed at 32 kbps, which cost the transcription models entire quiet passages: + /// a greeting spoken softly at the start of a recording was simply missing from the transcript. The + /// same recording compared at 64 and 128 kbps came back complete, which is why 128 kbps is the + /// default here. Users trading accuracy for a smaller upload can still pick a lower bitrate. + /// public TranscriptionOpusBitrate OpusBitrate { get; set; } = ManagedConfiguration.Register(configSelection, n => n.OpusBitrate, TranscriptionOpusBitrate.KBPS_128); /// diff --git a/app/MindWork AI Studio/Settings/DataModel/TranscriptionOpusBitrate.cs b/app/MindWork AI Studio/Settings/DataModel/TranscriptionOpusBitrate.cs index 08f61011..288f37e6 100644 --- a/app/MindWork AI Studio/Settings/DataModel/TranscriptionOpusBitrate.cs +++ b/app/MindWork AI Studio/Settings/DataModel/TranscriptionOpusBitrate.cs @@ -2,8 +2,13 @@ namespace AIStudio.Settings.DataModel; public enum TranscriptionOpusBitrate { + // The recommended bitrate is deliberately the member with the underlying value 0: when the + // settings file holds a value TolerantEnumConverter cannot read, it falls back to that member. + // Landing on the lowest bitrate there would silently reintroduce the very defect this setting + // exists to prevent -- transcripts losing what was said quietly. + KBPS_128 = 0, + KBPS_32, KBPS_64, - KBPS_128, KBPS_256, -} +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Settings/DataModel/TranscriptionOpusBitrateExtensions.cs b/app/MindWork AI Studio/Settings/DataModel/TranscriptionOpusBitrateExtensions.cs index 2a20c1a2..a24aedc6 100644 --- a/app/MindWork AI Studio/Settings/DataModel/TranscriptionOpusBitrateExtensions.cs +++ b/app/MindWork AI Studio/Settings/DataModel/TranscriptionOpusBitrateExtensions.cs @@ -21,6 +21,9 @@ public static class TranscriptionOpusBitrateExtensions TranscriptionOpusBitrate.KBPS_64 => 64_000, TranscriptionOpusBitrate.KBPS_128 => 128_000, TranscriptionOpusBitrate.KBPS_256 => 256_000, - _ => 32_000, + + // A value we do not know must never mean the lowest quality: that is how quiet passages + // went missing from transcripts in the first place. Fall back to the recommended bitrate. + _ => 128_000, }; -} +} \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/Services/MediaTranscriptionService.cs b/app/MindWork AI Studio/Tools/Services/MediaTranscriptionService.cs index af7be01b..b89dcb29 100644 --- a/app/MindWork AI Studio/Tools/Services/MediaTranscriptionService.cs +++ b/app/MindWork AI Studio/Tools/Services/MediaTranscriptionService.cs @@ -647,9 +647,14 @@ public sealed class MediaTranscriptionService( MediaOperation operation, bool updateImportState) { + // The bitrate governs re-encoding, not every upload: the runtime hands a file through + // unchanged when it already is a single mono 48 kHz Opus track in a WebM container and small + // enough. Such a file keeps whatever bitrate it was made with, which is the better outcome -- + // re-encoding it could only take quality away, never add any. + var opusBitrateBps = settingsManager.ConfigurationData.App.OpusBitrate.GetBitsPerSecond(); + // 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 opusBitrateBps = settingsManager.ConfigurationData.App.OpusBitrate.GetBitsPerSecond(); var jobId = await rustService.StartMediaJobAsync(mediaPath, normalizedPath, opusBitrateBps, CancellationToken.None); operation.JobId = jobId; diff --git a/runtime/src/media.rs b/runtime/src/media.rs index 41fa4aaf..d41282f9 100644 --- a/runtime/src/media.rs +++ b/runtime/src/media.rs @@ -60,6 +60,11 @@ const OPUS_PRE_SKIP: u16 = 312; const DEFAULT_MAX_PASS_THROUGH_BYTES: u64 = 25 * 1024 * 1024; /// Default target bitrate for mono speech-oriented Opus output, used when a request omits it. +/// +/// AI Studio always states a bitrate, so this default only covers requests which leave it out. It is +/// 128 kbps because the 32 kbps this encoder used to be fixed at cost transcription models whole +/// quiet passages: a softly spoken greeting at the start of a recording never reached the transcript, +/// while the same recording at 128 kbps came back complete. const DEFAULT_OPUS_BITRATE_BPS: u32 = 128_000; /// Bounded input block used for streaming resampling.