import gradio as gr import os import re import base64 import io from pathlib import Path import pypdfium2 as pdfium from huggingface_hub import snapshot_download, HfApi HF_TOKEN = os.environ.get("HF_TOKEN") PRIVATE_DATA = os.environ.get("PRIVATE_DATA") # FIX: removed duplicate `api = HfApi(...)` line that appeared twice api = HfApi(token=HF_TOKEN) # Check access info = api.repo_info(repo_id=PRIVATE_DATA, repo_type="dataset") print(info.id) # Download dataset_path = snapshot_download( repo_id=PRIVATE_DATA, repo_type="dataset", token=HF_TOKEN, local_dir="data", ) print(dataset_path) # --- Configuration --- AUDIO_FILES_INFO = {} LANGUAGES = { "Arabic": "ar", "English": "en", "French": "fr", "Spanish": "es", "German": "de", "Italian": "it", } def discover_audio_files(root_dir=None): """ Scans the demo_audio directory for wav files from a specific list. FIX: default arg now uses None to avoid capturing dataset_path at import time. """ # FIX: resolve root_dir lazily so dataset_path is always defined if root_dir is None: root_dir = f"{dataset_path}/demo_audio" allowed_files = [ "A02997", "A03046", "A03520", "A03858", "A04616", "A04957", "A04960", "A04965", "A05012", "A05195", "A05857", "A06010", "A06118", "A06622", "A06850", "A06888", "A06918", "A06936", "A07167", "A07251", "A07296", "A07452", "A07462", "A07679", "A07768", "A07791", "A08133", "A08649", "A08957", "A08958", "A08960", "A08966", "A09304" ] audio_files = {} if not os.path.isdir(root_dir): print(f"Warning: Audio source directory '{root_dir}' not found.") return audio_files for file_id in allowed_files: expected_wav_path = os.path.join(root_dir, file_id, f"{file_id}.wav") if os.path.exists(expected_wav_path): audio_files[file_id] = file_id if not audio_files: print(f"Warning: No allowed audio files found in '{root_dir}'") return audio_files # --- Gradio Application Logic --- def load_audio_and_transcript(audio_selection): """ Callback: loads audio, transcript, enables language dropdown, defaults to English PDF. FIX: all component returns now use gr.update() — Gradio 5+ requires this, returning gr.Audio(...) / gr.Dropdown(...) instances is silently ignored. """ if not audio_selection or audio_selection not in AUDIO_FILES_INFO: return ( None, "Please select an audio file to see its transcript.", gr.update(interactive=False, value=None), gr.update(value="
Select an audio file to load the PDF summary.
", visible=True), ) base_filename = AUDIO_FILES_INFO[audio_selection] audio_path = os.path.join( f"{dataset_path}/demo_audio", base_filename, f"{base_filename}.wav" ) transcript_path = os.path.join( f"{dataset_path}/meeting_reports", base_filename, "final_transcript_text.txt" ) try: with open(transcript_path, "r", encoding="utf-8") as f: transcript_content = f.read() except FileNotFoundError: transcript_content = f"Transcript file not found at: {transcript_path}" english_pdf_html = load_summary_pdf(audio_selection, "English") pdf_update = gr.update( value=english_pdf_html or "No English PDF found.
", visible=True, ) return ( gr.update(value=audio_path, label=f"Playing: {audio_selection}"), transcript_content, gr.update(interactive=True, value="English"), pdf_update, ) def pdf_path_to_html(pdf_path): """Render PDF pages as high-quality embedded PNG images inside HTML.""" try: pdf = pdfium.PdfDocument(pdf_path) page_html = [] # 300 DPI ~= 300 / 72 scale in PDFium render_scale = 300 / 72 for i in range(len(pdf)): page = pdf[i] pil_image = page.render(scale=render_scale).to_pil() buffer = io.BytesIO() pil_image.save(buffer, format="PNG", optimize=True) img_b64 = base64.b64encode(buffer.getvalue()).decode("utf-8") page_html.append(f"""Could not load PDF: {e}
Path: {pdf_path}
No PDF found for this selection.
", visible=True) def create_interface(): # --- Default initial values --- default_audio = list(AUDIO_FILES_INFO.keys())[0] if AUDIO_FILES_INFO else None default_lang = "English" if default_audio else None if default_audio: default_audio_path = os.path.join( f"{dataset_path}/demo_audio", default_audio, f"{default_audio}.wav" ) transcript_path = os.path.join( f"{dataset_path}/meeting_reports", default_audio, "final_transcript_text.txt" ) try: with open(transcript_path, "r", encoding="utf-8") as f: default_transcript = f.read() except FileNotFoundError: default_transcript = f"Transcript file not found at: {transcript_path}" default_pdf_html = load_summary_pdf(default_audio, default_lang) or "No English PDF found.
" default_audio_label = f"Playing: {default_audio}" else: default_audio_path = None default_transcript = "Please select an audio file to see its transcript." default_pdf_html = "Select an audio file to load the PDF summary.
" default_audio_label = "Audio Player" css = """ :root { --primary-color: #2563eb; --primary-hover: #1d4ed8; --secondary-color: #8b5cf6; --accent-color: #06b6d4; --success-color: #10b981; --bg-primary: #ffffff; --bg-secondary: #f8fafc; --bg-tertiary: #f1f5f9; --border-color: #e2e8f0; --text-primary: #1e293b; --text-secondary: #64748b; --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1); --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1); color-scheme: light !important; } * { color-scheme: light !important; } .gradio-container { background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 50%, #faf5ff 100%) !important; color-scheme: light !important; } .gradio-container * { color-scheme: light !important; } .box-style { background: rgba(255, 255, 255, 0.95) !important; border-radius: 16px !important; border: 1px solid var(--border-color) !important; padding: 24px !important; box-shadow: var(--shadow-md) !important; } #main-content-row { min-height: 9vh; } """ theme = gr.themes.Soft( primary_hue="blue", secondary_hue="purple", neutral_hue="slate", font=gr.themes.GoogleFont("Inter"), font_mono=gr.themes.GoogleFont("JetBrains Mono"), ).set( body_background_fill="*neutral_50", body_background_fill_dark="*neutral_50", background_fill_primary="white", background_fill_primary_dark="white", background_fill_secondary="*neutral_50", background_fill_secondary_dark="*neutral_50", block_background_fill="white", block_background_fill_dark="white", input_background_fill="white", input_background_fill_dark="white", panel_background_fill="white", panel_background_fill_dark="white", body_text_color="*neutral_800", body_text_color_dark="*neutral_800", ) with gr.Blocks( theme=theme, css=css, title="InterPARES-Audio", js=""" function() { document.documentElement.style.colorScheme = 'light'; document.body.style.colorScheme = 'light'; document.documentElement.classList.remove('dark'); document.body.classList.remove('dark'); document.documentElement.classList.add('light'); document.body.classList.add('light'); document.documentElement.setAttribute('data-theme', 'light'); document.body.setAttribute('data-theme', 'light'); } """, ) as demo: gr.HTML(""" """) gr.HTML( """This demo showcases the results of a powerful pipeline designed to process long audio files with multiple speakers and languages: