@@ -5,13 +5,12 @@ use rosc::{encoder::encode, OscMessage, OscPacket, OscType};
55use serde:: { Deserialize , Serialize } ;
66use std:: error:: Error ;
77use std:: fs;
8- use std:: io:: Cursor ;
8+ use std:: io:: { self , Cursor , Write } ;
99use std:: sync:: { Arc , Mutex } ;
1010use std:: time:: { Duration , Instant } ;
1111use tokio:: sync:: mpsc;
1212use tokio:: time:: sleep;
1313
14-
1514#[ derive( Deserialize , Clone ) ]
1615struct Config {
1716 osc : OscConfig ,
@@ -63,7 +62,6 @@ struct ChatGptChoice {
6362 message : ChatGptMessage ,
6463}
6564
66-
6765#[ derive( Deserialize , Clone ) ]
6866struct AudioConfig {
6967 silence_threshold : u32 ,
@@ -72,7 +70,6 @@ struct AudioConfig {
7270 min_transcription_duration : f32 ,
7371}
7472
75-
7673#[ derive( Deserialize , Clone ) ]
7774struct RateLimitConfig {
7875 requests_per_minute : usize ,
@@ -132,7 +129,7 @@ impl NoiseGate {
132129
133130 fn process ( & mut self , samples : & [ f32 ] ) -> bool {
134131 let max_amplitude = samples. iter ( ) . map ( |& s| s. abs ( ) ) . fold ( 0.0f32 , f32:: max) ;
135-
132+
136133 if max_amplitude > self . threshold {
137134 self . last_active = Instant :: now ( ) ;
138135 self . is_active = true ;
@@ -240,7 +237,7 @@ async fn send_to_chatbox(message: &str, config: &Config, socket: &UdpSocket) ->
240237
241238async fn transcribe_audio ( audio_data : Vec < u8 > , config : & OpenAiConfig , rate_limiter : & mut RateLimiter ) -> Result < String , Box < dyn Error > > {
242239 println ! ( "Starting audio transcription. Audio data size: {} bytes" , audio_data. len( ) ) ;
243-
240+
244241 if audio_data. is_empty ( ) {
245242 return Err ( "Audio data is empty" . into ( ) ) ;
246243 }
@@ -293,11 +290,11 @@ async fn process_audio(
293290) -> Result < ( ) , Box < dyn Error > > {
294291 // Calculate audio duration
295292 let audio_duration = calculate_audio_duration ( & audio_data) ?;
296-
293+
297294 // Check if audio is shorter than the minimum transcription duration
298295 let min_duration = Duration :: from_secs_f32 ( config. audio . min_transcription_duration ) ;
299296 if audio_duration < min_duration {
300- println ! ( "Audio too short ({:.2}s). Minimum duration is {:.2}s. Skipping transcription." ,
297+ println ! ( "Audio too short ({:.2}s). Minimum duration is {:.2}s. Skipping transcription." ,
301298 audio_duration. as_secs_f32( ) , min_duration. as_secs_f32( ) ) ;
302299 typing_indicator. set_typing ( false ) . await ;
303300 return Ok ( ( ) ) ;
@@ -335,7 +332,6 @@ enum AudioEvent {
335332 AudioData ( Vec < u8 > ) ,
336333}
337334
338-
339335fn start_audio_recording (
340336 config : & Config ,
341337 tx : mpsc:: Sender < AudioEvent > ,
@@ -371,22 +367,22 @@ fn start_audio_recording(
371367 move |data : & [ f32 ] , _: & cpal:: InputCallbackInfo | {
372368 if noise_gate. process ( data) {
373369 let mut buffer = audio_data_clone. lock ( ) . unwrap ( ) ;
374-
370+
375371 if !is_recording {
376372 is_recording = true ;
377373 println ! ( "Sound detected. Starting recording..." ) ;
378374 let _ = tx_clone. try_send ( AudioEvent :: StartRecording ) ;
379375 }
380-
376+
381377 buffer. extend_from_slice ( data) ;
382378 silent_frames = 0 ;
383379 } else if is_recording {
384380 silent_frames += 1 ;
385-
381+
386382 if silent_frames >= silence_threshold {
387383 is_recording = false ;
388384 silent_frames = 0 ;
389-
385+
390386 let mut buffer = audio_data_clone. lock ( ) . unwrap ( ) ;
391387 if !buffer. is_empty ( ) {
392388 println ! ( "Silence detected. Stopping recording and processing audio..." ) ;
@@ -411,7 +407,7 @@ fn start_audio_recording(
411407 let _ = tx_clone. try_send ( AudioEvent :: AudioData ( wav_buffer) ) ;
412408 buffer. clear ( ) ;
413409 }
414-
410+
415411 let _ = tx_clone. try_send ( AudioEvent :: StopRecording ) ;
416412 } else {
417413 // Keep recording during short pauses
@@ -437,6 +433,27 @@ fn start_audio_recording(
437433
438434#[ tokio:: main]
439435async fn main ( ) -> Result < ( ) , Box < dyn Error > > {
436+ // Set a panic hook to handle panics and prevent the program from closing immediately
437+ std:: panic:: set_hook ( Box :: new ( |panic_info| {
438+ eprintln ! ( "Panic occurred: {}" , panic_info) ;
439+
440+ // Ensure this is always executed after a panic
441+ println ! ( "Press Enter to exit..." ) ;
442+ io:: stdout ( ) . flush ( ) . unwrap ( ) ;
443+ let _ = io:: stdin ( ) . read_line ( & mut String :: new ( ) ) ;
444+ } ) ) ;
445+
446+ let result = run_main ( ) . await ;
447+
448+ // Ensure this is always executed
449+ println ! ( "Press Enter to exit..." ) ;
450+ io:: stdout ( ) . flush ( ) . unwrap ( ) ;
451+ let _ = io:: stdin ( ) . read_line ( & mut String :: new ( ) ) ;
452+
453+ result
454+ }
455+
456+ async fn run_main ( ) -> Result < ( ) , Box < dyn Error > > {
440457 let config_data = fs:: read_to_string ( "config.toml" ) ?;
441458 let config: Config = toml:: from_str ( & config_data) ?;
442459 let config = Arc :: new ( config) ;
0 commit comments