Spaces:
Running on Zero
Running on Zero
| """MeetPilot Whisper + PyAnnote Diarization Gradio Space (ZeroGPU Compatible). | |
| Exposes a Gradio web interface and named API endpoint (`/transcribe`) | |
| powered by faster-whisper and pyannote.audio with WhisperX alignment. | |
| """ | |
| import logging | |
| import os | |
| from typing import Any, Dict, Optional | |
| import gradio as gr | |
| from handler import EndpointHandler | |
| # Configure logging | |
| logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s") | |
| logger = logging.getLogger("meetpilot-space") | |
| # Optional ZeroGPU import (graceful fallback if running locally on standard CPU/GPU) | |
| try: | |
| import spaces | |
| has_spaces = True | |
| except ImportError: | |
| spaces = None | |
| has_spaces = False | |
| # Initialize EndpointHandler in lazy mode so models are NOT loaded during import/startup | |
| handler = EndpointHandler(lazy=True) | |
| def _run_transcription( | |
| audio_path, | |
| min_speakers=None, | |
| max_speakers=None, | |
| language=None, | |
| ): | |
| """Core transcription worker called inside the active execution context.""" | |
| if not audio_path or not os.path.exists(audio_path): | |
| raise gr.Error("Please provide a valid audio file.") | |
| hf_token = ( | |
| os.getenv("HFTOKEN") | |
| or os.getenv("HF_TOKEN") | |
| or os.getenv("HUGGINGFACE_TOKEN") | |
| or os.getenv("HF_API_TOKEN") | |
| ) | |
| if not hf_token: | |
| logger.warning("HFTOKEN is not set in Space Secrets. PyAnnote gated models may fail.") | |
| else: | |
| os.environ["HF_TOKEN"] = hf_token | |
| os.environ["HUGGING_FACE_HUB_TOKEN"] = hf_token | |
| # Sanitize speaker counts | |
| min_spk = int(min_speakers) if min_speakers is not None and min_speakers > 0 else None | |
| max_spk = int(max_speakers) if max_speakers is not None and max_speakers > 0 else None | |
| lang = language.strip() if language and language.strip() else None | |
| payload = { | |
| "inputs": audio_path, | |
| "parameters": { | |
| "min_speakers": min_spk, | |
| "max_speakers": max_spk, | |
| "language": lang, | |
| }, | |
| } | |
| try: | |
| result = handler(payload) | |
| return result | |
| except Exception as exc: | |
| logger.exception("Error during meeting transcription: %s", exc) | |
| raise gr.Error(f"Transcription failed: {str(exc)}") | |
| # Apply @spaces.GPU decorator if running in a Hugging Face ZeroGPU environment | |
| if has_spaces and spaces is not None: | |
| def transcribe(audio_file, min_speakers=None, max_speakers=None, language=None): | |
| return _run_transcription(audio_file, min_speakers, max_speakers, language) | |
| else: | |
| def transcribe(audio_file, min_speakers=None, max_speakers=None, language=None): | |
| return _run_transcription(audio_file, min_speakers, max_speakers, language) | |
| # Build Gradio Interface | |
| with gr.Blocks(title="MeetPilot - Whisper + PyAnnote Speaker Diarization") as demo: | |
| gr.Markdown( | |
| """ | |
| # 🎙️ MeetPilot AI: Speech Recognition & Speaker Diarization | |
| Transcribe audio and identify distinct speakers in a single pass using **faster-whisper** (`large-v3`) + **pyannote.audio** (`community-1`) with WhisperX alignment on **Hugging Face ZeroGPU**. | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| audio_input = gr.Audio( | |
| type="filepath", | |
| label="Audio Recording (WAV, MP3, M4A, etc.)", | |
| ) | |
| with gr.Accordion("Advanced Diarization Options", open=False): | |
| min_spk_input = gr.Number(label="Minimum Speakers", precision=0, value=None) | |
| max_spk_input = gr.Number(label="Maximum Speakers", precision=0, value=None) | |
| lang_input = gr.Textbox(label="Language Code (Optional, e.g. 'en')", placeholder="auto") | |
| submit_btn = gr.Button("Transcribe & Diarize", variant="primary") | |
| with gr.Column(scale=1): | |
| output_json = gr.JSON(label="Diarized Transcript Segments") | |
| submit_btn.click( | |
| fn=transcribe, | |
| inputs=[audio_input, min_spk_input, max_spk_input, lang_input], | |
| outputs=output_json, | |
| api_name="transcribe", | |
| ) | |
| gr.Markdown( | |
| """ | |
| ### API Usage from MeetPilot Backend | |
| This Space exposes a named API endpoint `transcribe`. You can call it programmatically via `gradio_client` or HTTP POST: | |
| ```python | |
| from gradio_client import Client, handle_file | |
| client = Client("Subham05x/meetpilot-whisper-diarization-space", hf_token=os.environ["HF_TOKEN"]) | |
| result = client.predict( | |
| audio_file=handle_file("meeting.wav"), | |
| min_speakers=None, | |
| max_speakers=None, | |
| language=None, | |
| api_name="/transcribe" | |
| ) | |
| print(result) # {'segments': [...], 'language': 'en', 'duration': 12.5} | |
| ``` | |
| """ | |
| ) | |
| if __name__ == "__main__": | |
| demo.queue().launch() | |