Transcriber: accept video uploads (mp4/mov/webm/mkv) -> ffmpeg-extract audio -> MIDI; ffmpeg in workers
This commit is contained in:
@@ -7,6 +7,7 @@ Run with:
|
||||
celery -A portal.tasks.celery_app worker --loglevel=info
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import os
|
||||
|
||||
import logging
|
||||
|
||||
@@ -34,6 +35,22 @@ celery_app.conf.update(
|
||||
)
|
||||
|
||||
|
||||
_VIDEO_EXT = {".mp4", ".mov", ".webm", ".mkv", ".m4v", ".avi", ".mpg", ".mpeg"}
|
||||
|
||||
|
||||
def _audio_wav(path: str, suffix: str) -> str:
|
||||
"""If the uploaded file is a video, extract its audio track as a 16k mono WAV."""
|
||||
if suffix.lower() in _VIDEO_EXT:
|
||||
import subprocess
|
||||
out = os.path.splitext(path)[0] + ".wav"
|
||||
subprocess.run(
|
||||
["ffmpeg", "-v", "error", "-y", "-i", path, "-ac", "1", "-ar", "16000", out],
|
||||
check=True,
|
||||
)
|
||||
return out
|
||||
return path
|
||||
|
||||
|
||||
@celery_app.task(bind=True, max_retries=3, default_retry_delay=30)
|
||||
def ensure_user_bucket(self, username: str) -> dict:
|
||||
"""Create (idempotently) the per-user S3 bucket in Garage."""
|
||||
@@ -69,6 +86,7 @@ def transcribe_sheetmusic(self, bucket: str, key: str, user: str = "") -> dict:
|
||||
base = pathlib.Path(key).stem or "score"
|
||||
audio_path = os.path.join(workdir, base + pathlib.Path(key).suffix)
|
||||
client.download_file(bucket, key, audio_path)
|
||||
audio_path = _audio_wav(audio_path, pathlib.Path(key).suffix)
|
||||
|
||||
if not os.environ.get("HUGGINGFACE_TOKEN"):
|
||||
return {"ok": False, "error": "HUGGINGFACE_TOKEN not set (CC BY-NC model is gated)"}
|
||||
@@ -119,6 +137,7 @@ def transcribe_audio(self, bucket: str, key: str, user: str = "") -> dict:
|
||||
base = pathlib.Path(key).stem or "input"
|
||||
audio_path = os.path.join(workdir, base + pathlib.Path(key).suffix)
|
||||
client.download_file(bucket, key, audio_path)
|
||||
audio_path = _audio_wav(audio_path, pathlib.Path(key).suffix)
|
||||
|
||||
outdir = os.path.join(workdir, "out")
|
||||
os.makedirs(outdir, exist_ok=True)
|
||||
@@ -168,4 +187,4 @@ def transcribe_audio(self, bucket: str, key: str, user: str = "") -> dict:
|
||||
def notify_backup(scope: str = "family-home-lab") -> dict:
|
||||
"""Hook point for backup/health notifications (currently a no-op stub)."""
|
||||
logger.info("Backup notify stub fired for %s", scope)
|
||||
return {"ok": True, "scope": scope}
|
||||
return {"ok": True, "scope": scope}
|
||||
Reference in New Issue
Block a user