Spaces:
Running
on
Zero
Running
on
Zero
| 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 |