diff --git a/src/gui_main.c b/src/gui_main.c index 41fcdb4..c666f01 100644 --- a/src/gui_main.c +++ b/src/gui_main.c @@ -11,6 +11,7 @@ #include #include #include +#include typedef struct { GtkApplication *app; @@ -42,6 +43,8 @@ typedef struct { unsigned int meter_timer_id; float live_peak; int runtime_ready; + char last_transcript[4096]; + double last_transcript_time; } gui_state_t; static float clampf(float v, float lo, float hi) { @@ -163,6 +166,28 @@ static int peak_is_speech(const float *samples, size_t count, float threshold) { return peak_abs >= threshold; } +static double monotonic_seconds(void) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0; +} + +static int is_duplicate_transcript(gui_state_t *s, const char *text) { + if (!s || !text || text[0] == '\0') return 0; + if (s->last_transcript[0] == '\0') return 0; + + const double dt = monotonic_seconds() - s->last_transcript_time; + if (dt < 0.0 || dt > 1.0) return 0; + + return strcmp(s->last_transcript, text) == 0; +} + +static void remember_transcript(gui_state_t *s, const char *text) { + if (!s || !text || text[0] == '\0') return; + snprintf(s->last_transcript, sizeof(s->last_transcript), "%s", text); + s->last_transcript_time = monotonic_seconds(); +} + static void process_segment(gui_state_t *s, float *samples, size_t count) { if (!samples || count == 0) { free(samples); @@ -178,7 +203,13 @@ static void process_segment(gui_state_t *s, float *samples, size_t count) { return; } - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s->type_check))) { + int should_autotype = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s->type_check)) ? 1 : 0; + if (should_autotype && gtk_window_is_active(GTK_WINDOW(s->window))) { + should_autotype = 0; + fprintf(stderr, "gui: autotype skipped because voice_linux window is focused\n"); + } + + if (should_autotype) { if (typer_capture_focus() != 0) { fprintf(stderr, "gui: failed to capture focus target for autotype\n"); } @@ -200,9 +231,16 @@ static void process_segment(gui_state_t *s, float *samples, size_t count) { return; } + if (is_duplicate_transcript(s, text)) { + fprintf(stderr, "gui: suppressed duplicate transcript within 1s window\n"); + set_status(s, "Duplicate segment suppressed"); + free(text); + return; + } + append_transcript(s, text); - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(s->type_check))) { + if (should_autotype) { if (typer_type_text(text) != 0) { fprintf(stderr, "gui: autotype injection failed\n"); set_status(s, "Autotype failed (see terminal logs)"); @@ -211,6 +249,7 @@ static void process_segment(gui_state_t *s, float *samples, size_t count) { } } + remember_transcript(s, text); set_status(s, audio_msg); free(text); }