Spaces:
Sleeping
Sleeping
| import os | |
| import shutil | |
| import tempfile | |
| from pathlib import Path | |
| import gradio as gr | |
| from transformers import pipeline | |
| # Prøv å støtte video via pydub + ffmpeg hvis tilgjengelig (valgfritt) | |
| try: | |
| from pydub import AudioSegment | |
| HAS_PYDUB = True | |
| except Exception: | |
| HAS_PYDUB = False | |
| # --- Konfigurasjon --- | |
| # CPU: bruk en mindre, flerspråklig modell. (large-v3 på CPU vil ofte knekke.) | |
| # Alternativer: "openai/whisper-small", "openai/whisper-medium", "distil-whisper/distil-small.multilingual" | |
| ASR_MODEL_ID = "openai/whisper-small" | |
| def make_transcriber(): | |
| # device=-1 tvinger CPU. return_timestamps=True gir tidskoder i retur. | |
| return pipeline( | |
| task="automatic-speech-recognition", | |
| model=ASR_MODEL_ID, | |
| device=-1, | |
| return_timestamps=True | |
| ) | |
| transcriber = make_transcriber() | |
| VIDEO_EXTS = {".mp4", ".avi", ".mov", ".mkv", ".webm"} | |
| AUDIO_EXTS = {".wav", ".mp3", ".m4a", ".flac", ".ogg", ".opus", ".aac"} | |
| def extract_audio_if_needed(input_path: str) -> str: | |
| """ | |
| Tar inn en filsti (audio eller video). | |
| Hvis video og pydub+ffmpeg finnes, ekstraheres WAV til temp-katalog og | |
| vi returnerer ny filsti. Hvis ikke, kastes en forklarende feil. | |
| Hvis allerede audio, returneres originalstien. | |
| """ | |
| suffix = Path(input_path).suffix.lower() | |
| # Allerede audio? | |
| if suffix in AUDIO_EXTS: | |
| return input_path | |
| # Video? | |
| if suffix in VIDEO_EXTS: | |
| if not HAS_PYDUB: | |
| raise RuntimeError( | |
| "Video oppdaget, men pydub/ffmpeg er ikke tilgjengelig. " | |
| "Installer pydub og ffmpeg (se requirements.txt og apt.txt), " | |
| "eller last opp en ren lydfil." | |
| ) | |
| # Ekstraher WAV | |
| temp_dir = tempfile.mkdtemp(prefix="asr_") | |
| out_wav = os.path.join(temp_dir, "extracted_audio.wav") | |
| audio = AudioSegment.from_file(input_path) | |
| audio.export(out_wav, format="wav") | |
| return out_wav | |
| # Ukjent – la Whisper prøve; hvis det feiler, får brukeren feilmelding | |
| return input_path | |
| def handle_upload_and_transcribe(file_path: str): | |
| if not file_path: | |
| return "Last opp en lyd- eller videofil." | |
| tmp_to_cleanup = None | |
| try: | |
| # Kan generere en temp WAV (for video) | |
| maybe_audio = extract_audio_if_needed(file_path) | |
| if maybe_audio != file_path: | |
| tmp_to_cleanup = os.path.dirname(maybe_audio) | |
| # Tips: du kan sette språk eksplisitt for raskere/mer stabil dekoding: | |
| # generate_kwargs={"task": "transcribe", "language": "no"} | |
| result = transcriber(maybe_audio) | |
| # Rydd temp | |
| if tmp_to_cleanup and os.path.exists(tmp_to_cleanup): | |
| shutil.rmtree(tmp_to_cleanup, ignore_errors=True) | |
| # Normaliser utdata | |
| if isinstance(result, dict): | |
| # transformers>=4.30 gir ofte {"text": "...", "chunks": [...]} | |
| text = result.get("text") | |
| if text: | |
| return text.strip() | |
| # fallback | |
| return str(result) | |
| elif isinstance(result, list) and result: | |
| return result[0].get("text", str(result)) | |
| return str(result) | |
| except Exception as e: | |
| # Rydd opp ved feil | |
| if tmp_to_cleanup and os.path.exists(tmp_to_cleanup): | |
| shutil.rmtree(tmp_to_cleanup, ignore_errors=True) | |
| return f"❌ Feil under prosessering/transkripsjon: {e}" | |
| with gr.Blocks(title="Multilingual Audio/Video Transcription") as demo: | |
| gr.Markdown( | |
| "## Multilingual Transcription (CPU)\n" | |
| "Last opp en lydfil (.wav/.mp3/.m4a/…) eller videofil (.mp4/.mov/…). " | |
| "På CPU brukes en mindre Whisper-modell for stabil kjøring." | |
| ) | |
| inp = gr.Audio(type="filepath", label="Fil (audio eller video)") | |
| out = gr.Textbox(label="Transkripsjon") | |
| btn = gr.Button("Transkriber") | |
| btn.click(handle_upload_and_transcribe, inputs=inp, outputs=out) | |
| if __name__ == "__main__": | |
| # På HF Spaces trenger du vanligvis ikke server_name/server_port her. | |
| demo.launch() |