Spaces:
Sleeping
Sleeping
| import os | |
| import gradio as gr | |
| import subprocess | |
| import requests | |
| import tempfile | |
| import yt_dlp | |
| from groq import Groq | |
| from huggingface_hub import InferenceClient | |
| # ========= CONFIG ========== | |
| GROQ_API_KEY = os.getenv("GROQ_API_KEY") | |
| HUGGINGFACE_API_TOKEN = os.getenv("HUGGINGFACE_API_TOKEN") | |
| if not GROQ_API_KEY or not HUGGINGFACE_API_TOKEN: | |
| raise EnvironmentError("Please set GROQ_API_KEY and HUGGINGFACE_API_TOKEN.") | |
| # Whisper and summarization models | |
| WHISPER_MODEL = "openai/whisper-large-v3-turbo" | |
| SUMMARIZER_MODEL = "facebook/bart-large-cnn" | |
| TUTORIAL_MODEL = "openai/gpt-oss-120b" | |
| # API Clients | |
| groq_client = Groq(api_key=GROQ_API_KEY) | |
| hf_client = InferenceClient(token=HUGGINGFACE_API_TOKEN) | |
| # ========= AUDIO HELPERS ========== | |
| def convert_to_wav(audio_path): | |
| """Convert any audio/video to WAV 16kHz mono.""" | |
| try: | |
| if audio_path.endswith(".wav"): | |
| return audio_path | |
| base, _ = os.path.splitext(audio_path) | |
| wav_path = base + "_converted.wav" | |
| subprocess.run( | |
| ["ffmpeg", "-y", "-i", audio_path, "-ar", "16000", "-ac", "1", wav_path], | |
| check=True, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE, | |
| ) | |
| return wav_path | |
| except subprocess.CalledProcessError as e: | |
| raise RuntimeError(f"β ffmpeg conversion failed: {e.stderr.decode('utf-8')}") | |
| except Exception as e: | |
| raise RuntimeError(f"β Error converting to WAV: {e}") | |
| def download_youtube_audio(url): | |
| """Download audio from YouTube using yt_dlp.""" | |
| try: | |
| with tempfile.TemporaryDirectory() as tmpdir: | |
| ydl_opts = { | |
| "format": "bestaudio/best", | |
| "outtmpl": os.path.join(tmpdir, "audio.%(ext)s"), | |
| "quiet": True, | |
| "postprocessors": [{"key": "FFmpegExtractAudio", "preferredcodec": "mp3"}], | |
| } | |
| with yt_dlp.YoutubeDL(ydl_opts) as ydl: | |
| ydl.download([url]) | |
| audio_file = os.path.join(tmpdir, "audio.mp3") | |
| wav_file = convert_to_wav(audio_file) | |
| return wav_file | |
| except Exception as e: | |
| raise RuntimeError(f"β Error downloading YouTube audio: {e}") | |
| # ========= CORE FUNCTIONS ========== | |
| def transcribe_audio(audio_path=None, youtube_url=None): | |
| """Transcribe uploaded, recorded, or YouTube audio.""" | |
| try: | |
| if youtube_url: | |
| wav_file = download_youtube_audio(youtube_url) | |
| elif audio_path: | |
| wav_file = convert_to_wav(audio_path) | |
| else: | |
| return "β οΈ Please upload or record an audio or provide YouTube link." | |
| with open(wav_file, "rb") as audio_file: | |
| response = hf_client.post( | |
| f"https://api-inference.huggingface.co/models/{WHISPER_MODEL}", | |
| headers={"Authorization": f"Bearer {HUGGINGFACE_API_TOKEN}"}, | |
| data=audio_file.read(), | |
| ) | |
| if response.status_code != 200: | |
| return f"β Transcription failed: {response.text}" | |
| result = response.json() | |
| text = result.get("text", "").strip() | |
| if not text: | |
| return "β No text generated from transcription." | |
| return text | |
| except Exception as e: | |
| return f"β Error during transcription: {e}" | |
| def summarize_text(text, language): | |
| """Generate detailed summary in selected language.""" | |
| try: | |
| if len(text.split()) < 20: | |
| return "β οΈ Text too short to summarize." | |
| prompt = ( | |
| f"Summarize the following text in detail in {language}. " | |
| f"Ensure the summary is coherent and complete.\n\n{text}" | |
| ) | |
| summary = groq_client.chat.completions.create( | |
| model="llama-3.1-8b-instant", | |
| messages=[{"role": "user", "content": prompt}], | |
| temperature=0.6, | |
| max_tokens=1500, | |
| ) | |
| return summary.choices[0].message.content.strip() | |
| except Exception as e: | |
| return f"β Summarization failed: {e}" | |
| def generate_tutorial(summary_text, language): | |
| """Generate an easy tutorial in Urdu or English based on summary.""" | |
| try: | |
| prompt = ( | |
| f"Create a simple tutorial for absolute beginners based on this summary. " | |
| f"Write it in {language} language, use simple and clear explanations, and keep it structured:\n\n{summary_text}" | |
| ) | |
| tutorial = groq_client.chat.completions.create( | |
| model="llama-3.1-8b-instant", | |
| messages=[{"role": "user", "content": prompt}], | |
| temperature=0.7, | |
| max_tokens=1800, | |
| ) | |
| return tutorial.choices[0].message.content.strip() | |
| except Exception as e: | |
| return f"β Tutorial generation failed: {e}" | |
| # ========= GRADIO INTERFACE ========== | |
| with gr.Blocks(theme=gr.themes.Soft(primary_hue="teal")) as app: | |
| gr.Markdown( | |
| """ | |
| # ποΈ Smart Transcriber & Tutor | |
| **Features:** | |
| - Upload / Record / YouTube Transcription | |
| - Summarize in English or Urdu | |
| - Generate Tutorial for Beginners | |
| """ | |
| ) | |
| with gr.Row(): | |
| audio_upload = gr.Audio(label="π§ Upload Audio", type="filepath") | |
| record_audio = gr.Audio(label="π€ Record Audio", type="filepath", sources=["microphone"]) | |
| youtube_link = gr.Textbox(label="πΊ YouTube Link (optional)") | |
| language_dropdown = gr.Dropdown(["English", "Urdu"], label="Select Language", value="English") | |
| transcribe_btn = gr.Button("π Transcribe Audio") | |
| transcription_output = gr.Textbox(label="Transcription Result", lines=10) | |
| summarize_btn = gr.Button("π§ Generate Detailed Summary") | |
| summary_output = gr.Textbox(label="Summary", lines=8) | |
| tutorial_btn = gr.Button("π Create Beginner Tutorial") | |
| tutorial_output = gr.Textbox(label="Tutorial", lines=10) | |
| # Button logic | |
| transcribe_btn.click( | |
| transcribe_audio, | |
| inputs=[audio_upload, youtube_link], | |
| outputs=transcription_output, | |
| ) | |
| summarize_btn.click( | |
| summarize_text, | |
| inputs=[transcription_output, language_dropdown], | |
| outputs=summary_output, | |
| ) | |
| tutorial_btn.click( | |
| generate_tutorial, | |
| inputs=[summary_output, language_dropdown], | |
| outputs=tutorial_output, | |
| ) | |
| # ========= LAUNCH APP ========== | |
| if __name__ == "__main__": | |
| app.launch() | |