diff --git "a/src/ui/interface.py" "b/src/ui/interface.py" new file mode 100644--- /dev/null +++ "b/src/ui/interface.py" @@ -0,0 +1,3016 @@ +"""Gradio UI — layout, CSS, JS animation system, and event handlers.""" +import json +from pathlib import Path + +import gradio as gr + +from config import ( + MIN_SILENCE_MIN, MIN_SILENCE_MAX, MIN_SILENCE_STEP, + MIN_SPEECH_MIN, MIN_SPEECH_MAX, MIN_SPEECH_STEP, + PAD_MIN, PAD_MAX, PAD_STEP, + PRESET_MUJAWWAD, PRESET_MURATTAL, PRESET_FAST, + QURAN_TEXT_SIZE_PX, ARABIC_WORD_SPACING, + DELETE_CACHE_FREQUENCY, DELETE_CACHE_AGE, + ANIM_WORD_COLOR, ANIM_STYLE_ROW_SCALES, + ANIM_DISPLAY_MODES, ANIM_DISPLAY_MODE_DEFAULT, + ANIM_OPACITY_PREV_DEFAULT, ANIM_OPACITY_AFTER_DEFAULT, ANIM_OPACITY_STEP, + ANIM_PRESETS, + ANIM_GRANULARITIES, ANIM_GRANULARITY_DEFAULT, + ANIM_WINDOW_PREV_DEFAULT, ANIM_WINDOW_AFTER_DEFAULT, + ANIM_WINDOW_PREV_MIN, ANIM_WINDOW_PREV_MAX, + ANIM_WINDOW_AFTER_MIN, ANIM_WINDOW_AFTER_MAX, + MEGA_WORD_SPACING_MIN, MEGA_WORD_SPACING_MAX, MEGA_WORD_SPACING_STEP, MEGA_WORD_SPACING_DEFAULT, + MEGA_TEXT_SIZE_MIN, MEGA_TEXT_SIZE_MAX, MEGA_TEXT_SIZE_STEP, MEGA_TEXT_SIZE_DEFAULT, + MEGA_LINE_SPACING_MIN, MEGA_LINE_SPACING_MAX, MEGA_LINE_SPACING_STEP, MEGA_LINE_SPACING_DEFAULT, + MEGA_SURAH_LIGATURE_SIZE, + LEFT_COLUMN_SCALE, RIGHT_COLUMN_SCALE, +) +from data.font_data import DIGITAL_KHATT_FONT_B64, SURAH_NAME_FONT_B64 +from src.pipeline.process import ( + process_audio, resegment_audio, + _retranscribe_wrapper, process_audio_json, save_json_export, +) +from src.mfa.timestamps import compute_mfa_timestamps + +# Load surah name ligature map +with open(Path(__file__).parent.parent.parent / "data" / "ligatures.json") as _f: + _SURAH_LIGATURES = json.load(_f) + + +def build_interface(): + """Build the Gradio interface.""" + + css = f""" + /* Font faces */ + @font-face {{ + font-family: 'DigitalKhatt'; + src: url(data:font/otf;base64,{DIGITAL_KHATT_FONT_B64}) format('opentype'); + font-weight: normal; + font-style: normal; + }} + @font-face {{ + font-family: 'SurahName'; + src: url(data:font/truetype;base64,{SURAH_NAME_FONT_B64}) format('truetype'); + font-weight: normal; + font-style: normal; + }} + + .arabic-text {{ + font-family: 'DigitalKhatt', 'Traditional Arabic', sans-serif; + direction: rtl; + text-align: right; + }} + + /* Prevent output area from being in a scrolling box */ + .gradio-container .prose {{ + max-height: none !important; + }} + .output-html {{ + max-height: none !important; + overflow: visible !important; + }} + + /* Segment cards - theme adaptive */ + .segment-card {{ + border-radius: 8px; + padding: 12px 16px; + margin-bottom: 12px; + border: 2px solid; + }} + .segment-header {{ + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 8px; + }} + .segment-title {{ + font-size: 13px; + opacity: 0.9; + }} + .segment-badges {{ + display: flex; + gap: 6px; + align-items: center; + }} + .segment-badge {{ + color: white; + padding: 2px 8px; + border-radius: 12px; + font-size: 12px; + font-weight: bold; + }} + .segment-audio {{ + margin: 8px 0; + display: flex; + align-items: center; + gap: 8px; + }} + .segment-audio audio {{ + flex: 1; + height: 32px; + border-radius: 4px; + }} + + /* Lazy play button (replaces