from app.logger_config import logger as logging import gradio as gr from pathlib import Path import os DEFAULT_CONFIG = { "task_type": "Transcription", "lang_source": "French", "lang_target": "English", "chunk_secs": 1.0, "left_context_secs": 20.0, "right_context_secs": 0.5, "streaming_policy": "waitk", "alignatt_thr": 8, "waitk_lagging": 2, "exclude_sink_frames": 8, "xatt_scores_layer": -2, "hallucinations_detector": True, } EXAMPLE_CONFIGS = { "data/english_meeting.wav": { "task_type": "Transcription", "lang_source": "English", "lang_target": "English", "chunk_secs": 1.0, "left_context_secs": 20.0, "right_context_secs": 0.5, "streaming_policy": "waitk", "alignatt_thr": 8, "waitk_lagging": 2, "exclude_sink_frames": 8, "xatt_scores_layer": -2, "hallucinations_detector": True }, "data/french_news.wav": { "task_type": "Transcription", "lang_source": "French", "lang_target": "English", "chunk_secs": 1.0, "left_context_secs": 15.0, "right_context_secs": 0.3, "streaming_policy": "alignatt", "alignatt_thr": 10, "waitk_lagging": 3, "exclude_sink_frames": 6, "xatt_scores_layer": -1, "hallucinations_detector": True }, "data/spanish_podcast.wav": { "task_type": "Translation", "lang_source": "Spanish", "lang_target": "English", "chunk_secs": 1.5, "left_context_secs": 25.0, "right_context_secs": 0.4, "streaming_policy": "waitk", "alignatt_thr": 7, "waitk_lagging": 1, "exclude_sink_frames": 8, "xatt_scores_layer": -2, "hallucinations_detector": False } } SUPPORTED_LANGS_MAP = { "Bulgarian": "bg", "Croatian": "hr", "Czech": "cs", "Danish": "da", "Dutch": "nl", "English": "en", "Estonian": "et", "Finnish": "fi", "French": "fr", "German": "de", "Greek": "el", "Hungarian": "hu", "Italian": "it", "Latvian": "lv", "Lithuanian": "lt", "Maltese": "mt", "Polish": "pl", "Portuguese": "pt", "Romanian": "ro", "Slovak": "sk", "Slovenian": "sl", "Spanish": "es", "Swedish": "sv", "Russian": "ru", "Ukrainian": "uk" } # ========== FONCTIONS UTILITAIRES ========== def to_updates(cfg): """Map dict -> gr.update list dans l'ordre des sorties.""" return [ gr.update(value=cfg["task_type"]), gr.update(value=cfg["lang_source"]), gr.update( value=cfg["lang_target"], visible=(cfg["task_type"] == "Translation") ), gr.update(value=cfg["chunk_secs"]), gr.update(value=cfg["left_context_secs"]), gr.update(value=cfg["right_context_secs"]), gr.update(value=cfg["streaming_policy"]), gr.update(value=cfg["alignatt_thr"]), gr.update(value=cfg["waitk_lagging"]), gr.update(value=cfg["exclude_sink_frames"]), gr.update(value=cfg["xatt_scores_layer"]), gr.update(value=cfg["hallucinations_detector"]), ] def apply_preset_if_example(filepath, auto_apply): """Si fichier = exemple ET auto_apply=True -> applique preset. Sinon, ne rien changer.""" logging.info(f"apply_preset_if_example {filepath} {auto_apply} ") if not filepath or not auto_apply: updates = [gr.update() for _ in range(12)] updates.append(gr.update()) return tuple(updates) # On compare uniquement le nom de fichier, pas le chemin complet file_name = Path(filepath).name # Recherche dans EXAMPLE_CONFIGS par nom de fichier cfg = next( (config for path, config in EXAMPLE_CONFIGS.items() if Path(path).name == file_name), None ) if not cfg: updates = [gr.update() for _ in range(12)] updates.append(gr.update()) return tuple(updates) updates = to_updates(cfg) updates.append(gr.update(value=f"Preset applied for: {file_name}")) return tuple(updates) def reset_to_defaults(): """Réinitialise tous les champs aux valeurs par défaut.""" updates = to_updates(DEFAULT_CONFIG) # 12 champs # Ajout du résumé (13e sortie) updates.append(gr.update(value="Defaults restored.")) return tuple(updates) def summarize_config( task, src, tgt, chunk, left, right, policy, thr, lag, sink, xatt, halluc ): txt = f"🧠 **Task:** {task}\n🌐 **Source language:** {src}" if task == "Translation": txt += f"\n🎯 **Target language:** {tgt}" txt += ( f"\n\n### ⚙️ Advanced Parameters:\n" f"- chunk_secs = {chunk}\n" f"- left_context_secs = {left}\n" f"- right_context_secs = {right}\n" f"- decoding.streaming_policy = {policy}\n" f"- decoding.alignatt_thr = {thr}\n" f"- decoding.waitk_lagging = {lag}\n" f"- decoding.exclude_sink_frames = {sink}\n" f"- decoding.xatt_scores_layer = {xatt}\n" f"- decoding.hallucinations_detector = {halluc}" ) return txt def handle_additional_outputs( progress_value): """ Update UI elements based on streaming progress or errors. Controls button states, audio visibility, and progress slider. """ logging.debug(f"Additional output received: {progress_value}") # ui_components = [start_button, stop_button,go_to_task, audio_source_step, status_slider] # Handle structured error message non_ok= ( gr.update(visible=True), # start_button enabled gr.update(visible=False), # stop_button disabled gr.update(visible=False), # go_to_task disabled gr.update(interactive=True), # audio_source_step re-shown gr.update(visible=False, value=0), # slider hidden ) if isinstance(progress_value, dict) and progress_value.get("error"): msg = progress_value.get("message", "Unknown error.") logging.error(f"[stream_ui] Client-side error: {msg}") return non_ok try: progress = float(progress_value) except (ValueError, TypeError): progress = 0 # --- Stream not started --- if progress <= 0: return non_ok # --- Stream finished --- if progress >= 100: return non_ok # --- Stream in progress --- return ( gr.update(visible=False), # start_button disabled gr.update(visible=True), # stop_button enabled gr.update(visible=True), # go_to_task enabled gr.update(interactive=False), # hide audio_source_step gr.update(visible=True, value=progress), # show progress ) def on_file_load(filepath): """ Update active audio path or reset". """ # Si un fichier est chargé (upload, micro, ou exemple), # audio_path ne sera pas None. is_visible = filepath is not None return filepath, gr.update(visible=is_visible) def get_custom_theme() : # === Thème personnalisé (studio néon) === theme = gr.themes.Base( primary_hue="blue", secondary_hue="indigo", ).set( body_background_fill="#F7F8FA", body_text_color="#222222", block_border_color="#D0D3D9", button_primary_background_fill="#3B82F6", button_primary_background_fill_hover="#2563EB", button_primary_text_color="#FFFFFF", ) css_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "assets", "custom_style.css") with open(css_path, encoding="utf-8") as f: css_style = f.read() return theme, css_style