@@ -27,7 +27,7 @@ import Hub
2727///
2828/// The view integrates with several key components:
2929/// - `StreamViewModel`: Manages real-time audio streaming and transcription
30- /// - `TranscribeViewModel`: Handles file-based transcription and recording workflows
30+ /// - `TranscribeViewModel`: Handles file-based transcription and recording workflows
3131/// - `ArgmaxSDKCoordinator`: Coordinates access to WhisperKit and SpeakerKit instances
3232/// - Audio discovery services for device and process selection (macOS)
3333///
@@ -75,6 +75,8 @@ struct ContentView: View {
7575 @AppStorage ( " silenceThreshold " ) private var silenceThreshold : Double = 0.2
7676 @AppStorage ( " maxSilenceBufferLength " ) private var maxSilenceBufferLength : Double = 10.0
7777 @AppStorage ( " transcribeInterval " ) private var transcribeInterval : Double = 0.1
78+ @AppStorage ( " minProcessInterval " ) private var minProcessInterval : Double = 0.0
79+ @AppStorage ( " transcriptionMode " ) private var transcriptionModeRawValue : String = TranscriptionModeSelection . voiceTriggered. rawValue
7880 @AppStorage ( " useVAD " ) private var useVAD : Bool = true
7981 @AppStorage ( " tokenConfirmationsNeeded " ) private var tokenConfirmationsNeeded : Double = 2
8082 @AppStorage ( " concurrentWorkerCount " ) private var concurrentWorkerCount : Double = 4
@@ -91,6 +93,16 @@ struct ContentView: View {
9193 @AppStorage ( " fastLoadDecoderComputeUnits " ) private var fastLoadDecoderComputeUnits : MLComputeUnits = . cpuAndNeuralEngine
9294 #endif
9395 @AppStorage ( " trackingPermissionStatePro " ) private var trackingPermissionStateRawValue : Int = TrackingPermissionState . undetermined. rawValue
96+
97+ /// Computed property to work with transcription mode as an enum
98+ private var transcriptionMode : TranscriptionModeSelection {
99+ get {
100+ TranscriptionModeSelection ( rawValue: transcriptionModeRawValue) ?? . voiceTriggered
101+ }
102+ set {
103+ transcriptionModeRawValue = newValue. rawValue
104+ }
105+ }
94106
95107 // MARK: Standard properties
96108
@@ -139,7 +151,6 @@ struct ContentView: View {
139151
140152 // MARK: Alerts
141153
142- @State private var showReportingAlert = false
143154 @State private var showShortAudioWarningAlert : Bool = false
144155 @State private var showPermissionAlert : Bool = false
145156 @State private var permissionAlertMessage : String = " "
@@ -184,18 +195,6 @@ struct ContentView: View {
184195 set: { newValue in
185196 trackingPermissionStateRawValue = newValue ? TrackingPermissionState . granted. rawValue : TrackingPermissionState . denied. rawValue
186197 Logging . debug ( newValue)
187-
188- if newValue {
189- sdkCoordinator. setupArgmax ( )
190- analyticsLogger. configureIfNeeded ( )
191- } else {
192- Task {
193- if await ArgmaxSDK . enabled ( ) {
194- await ArgmaxSDK . close ( )
195- }
196- Logging . debug ( " Shutting down ArgmaxSDK " )
197- }
198- }
199198 }
200199 )
201200 }
@@ -348,18 +347,6 @@ struct ContentView: View {
348347 #endif
349348 . navigationSplitViewColumnWidth( min: 300 , ideal: 350 )
350349 . padding ( . horizontal)
351- . alert ( isPresented: $showReportingAlert) {
352- Alert (
353- title: Text ( " Performance Reporting " ) ,
354- message: Text ( " Help us catch bugs early and improve reliability by enabling reporting and performance monitoring. Required to enable experimental features. Learn more at [argmaxinc.com/privacy](https://www.argmaxinc.com/privacy) " ) ,
355- primaryButton: . default( Text ( " Enable reporting " ) ) {
356- updateTracking ( state: . granted)
357- } ,
358- secondaryButton: . cancel( Text ( " Opt Out " ) ) {
359- updateTracking ( state: . denied)
360- }
361- )
362- }
363350 } detail: {
364351 VStack {
365352 #if os(iOS)
@@ -448,12 +435,6 @@ struct ContentView: View {
448435 showWhisperKitComputeUnits = true
449436 speakerKitComputeUnitsExpanded = false
450437
451- showReportingAlert = ( trackingPermissionStateRawValue == 0 ) // undetermined
452- if trackingPermissionStateRawValue == TrackingPermissionState . granted. rawValue {
453- sdkCoordinator. setupArgmax ( )
454- analyticsLogger. configureIfNeeded ( )
455- }
456-
457438 // Check if Pro models are supported on this OS version
458439 if #unavailable( macOS 15 , iOS 18 , watchOS 11 , visionOS 2 ) {
459440 showOSVersionAlert = true
@@ -1425,27 +1406,59 @@ struct ContentView: View {
14251406 }
14261407 . padding ( . horizontal)
14271408
1428- VStack {
1429- Text ( " Silence Threshold " )
1409+ Section ( header: Text ( " Stream Mode Settings " ) ) {
14301410 HStack {
1431- Slider ( value: $silenceThreshold, in: 0 ... 1 , step: 0.05 )
1432- Text ( silenceThreshold. formatted ( . number) )
1433- . frame ( width: 30 )
1434- InfoButton ( " Relative silence threshold for the audio. \n Baseline is set by the quietest 100ms in the previous 2 seconds. " )
1411+ Picker ( " Mode " , selection: Binding (
1412+ get: { TranscriptionModeSelection ( rawValue: transcriptionModeRawValue) ?? . voiceTriggered } ,
1413+ set: { transcriptionModeRawValue = $0. rawValue }
1414+ ) ) {
1415+ ForEach ( TranscriptionModeSelection . allCases) { mode in
1416+ Text ( mode. displayName) . tag ( mode)
1417+ }
1418+ }
1419+ . pickerStyle ( MenuPickerStyle ( ) )
1420+ Spacer ( )
1421+ InfoButton ( transcriptionMode. description)
14351422 }
1436- }
1437- . padding ( . horizontal)
1438-
1439- VStack {
1440- Text ( " Max Silence Buffer Size " )
1441- HStack {
1442- Slider ( value: $maxSilenceBufferLength, in: 10 ... 60 , step: 1 )
1443- Text ( maxSilenceBufferLength. formatted ( . number) )
1444- . frame ( width: 30 )
1445- InfoButton ( " Seconds of silence to buffer before audio is sent for transcription. " )
1423+
1424+ if transcriptionMode == . voiceTriggered {
1425+ VStack {
1426+ Text ( " Silence Threshold " )
1427+ HStack {
1428+ Slider ( value: $silenceThreshold, in: 0 ... 1 , step: 0.05 )
1429+ Text ( silenceThreshold. formatted ( . number. precision ( . fractionLength( 1 ) ) ) )
1430+ . frame ( width: 30 )
1431+ . lineLimit ( 1 )
1432+ InfoButton ( " Relative silence threshold for the audio. \n Baseline is set by the quietest 100ms in the previous 2 seconds. " )
1433+ }
1434+ }
1435+ . padding ( . horizontal)
1436+
1437+ VStack {
1438+ Text ( " Max Silence Buffer Size " )
1439+ HStack {
1440+ Slider ( value: $maxSilenceBufferLength, in: 10 ... 60 , step: 1 )
1441+ Text ( maxSilenceBufferLength. formatted ( . number. precision ( . fractionLength( 0 ) ) ) )
1442+ . frame ( width: 30 )
1443+ . lineLimit ( 1 )
1444+ InfoButton ( " Seconds of silence to buffer before audio is sent for transcription. " )
1445+ }
1446+ }
1447+ . padding ( . horizontal)
1448+
1449+ VStack {
1450+ Text ( " Min Process Interval " )
1451+ HStack {
1452+ Slider ( value: $minProcessInterval, in: 0 ... 15 , step: 1 )
1453+ Text ( minProcessInterval. formatted ( . number. precision ( . fractionLength( 0 ) ) ) )
1454+ . frame ( width: 30 )
1455+ . lineLimit ( 1 )
1456+ InfoButton ( " Minimum interval the incoming stream data is fed to transcription pipeline. " )
1457+ }
1458+ }
1459+ . padding ( . horizontal)
14461460 }
14471461 }
1448- . padding ( . horizontal)
14491462
14501463 VStack {
14511464 Text ( " Transcribe Interval " )
@@ -1458,21 +1471,6 @@ struct ContentView: View {
14581471 }
14591472 . padding ( . horizontal)
14601473
1461- Section ( header: Text ( " Performance Reporting " ) ) {
1462- VStack ( alignment: . leading) {
1463- HStack {
1464- Text ( " Enable Reporting " )
1465- InfoButton ( " Help us catch bugs early and improve reliability by enabling reporting and performance monitoring. " )
1466- Spacer ( )
1467- Toggle ( " " , isOn: trackingPermissionBinding)
1468- }
1469- Link ( destination: URL ( string: " https://www.argmaxinc.com/privacy " ) !) {
1470- Text ( " Learn more at argmaxinc.com/privacy " )
1471- }
1472- }
1473- . padding ( . horizontal)
1474- . padding ( . top)
1475- }
14761474 Section ( header: Text ( " Diarization Settings " ) ) {
14771475 HStack {
14781476 Picker ( " Diarization " , selection: $diarizationMode) {
@@ -2074,11 +2072,21 @@ struct ContentView: View {
20742072 isRecording = true
20752073 }
20762074
2075+ let streamMode : StreamTranscriptionMode
2076+ switch transcriptionMode {
2077+ case . alwaysOn:
2078+ streamMode = . alwaysOn
2079+ case . voiceTriggered:
2080+ streamMode = . voiceTriggered( silenceThreshold: Float ( silenceThreshold) , maxBufferLength: Float ( maxSilenceBufferLength) , minProcessInterval: Float ( minProcessInterval) )
2081+ case . batteryOptimized:
2082+ streamMode = . batteryOptimized
2083+ }
2084+
20772085 try await streamViewModel. startTranscribing (
20782086 options: DecodingOptionsPro (
20792087 base: decodingOptions,
20802088 transcribeInterval: transcribeInterval,
2081- streamTranscriptionMode: . voiceTriggered ( silenceThreshold : Float ( silenceThreshold ) , maxBufferLength : Float ( maxSilenceBufferLength ) )
2089+ streamTranscriptionMode: streamMode
20822090 )
20832091 )
20842092 } catch {
@@ -2188,6 +2196,7 @@ struct ContentView: View {
21882196 " compression_check_window " : " \( compressionCheckWindow) " ,
21892197 " sample_length " : " \( sampleLength) " ,
21902198 " silence_threshold " : " \( silenceThreshold) " ,
2199+ " transcription_mode " : " \( transcriptionMode. rawValue) " ,
21912200 " use_vad " : " \( useVAD) " ,
21922201 " token_confirmations_needed " : " \( tokenConfirmationsNeeded) " ,
21932202 " chunking_strategy " : " \( chunkingStrategy) " ,
0 commit comments