Add MP4 upload support
This commit is contained in:
50
web_app.py
50
web_app.py
@@ -8,6 +8,7 @@ from datetime import datetime, timezone
|
||||
import json
|
||||
from pathlib import Path
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
@@ -28,6 +29,7 @@ from src.translation import (
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
LOG_DIR = BASE_DIR / "logs" / "gradio"
|
||||
SETTINGS_FILE = BASE_DIR / ".cache" / "web_settings.json"
|
||||
UPLOAD_DIR = BASE_DIR / ".cache" / "uploads"
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -107,12 +109,15 @@ def build_pipeline_command(form: dict[str, str | bool]) -> list[str]:
|
||||
command = [
|
||||
sys.executable,
|
||||
str(BASE_DIR / "main.py"),
|
||||
args.url,
|
||||
"--lang",
|
||||
args.lang,
|
||||
"--mix-mode",
|
||||
args.mix_mode,
|
||||
]
|
||||
if args.url:
|
||||
command.insert(2, args.url)
|
||||
if args.input_file:
|
||||
command.extend(["--input-file", args.input_file])
|
||||
if args.translation_backend:
|
||||
command.extend(["--translation-backend", args.translation_backend])
|
||||
|
||||
@@ -135,10 +140,15 @@ def build_pipeline_command(form: dict[str, str | bool]) -> list[str]:
|
||||
|
||||
def _form_to_cli_args(form: dict[str, str | bool]) -> list[str]:
|
||||
url = (form.get("url") or "").strip()
|
||||
if not url:
|
||||
raise ValueError("A YouTube URL is required.")
|
||||
input_file = (form.get("input_file") or "").strip()
|
||||
if not url and not input_file:
|
||||
raise ValueError("A YouTube URL or uploaded MP4 is required.")
|
||||
if url and input_file:
|
||||
raise ValueError("Use either a YouTube URL or uploaded MP4, not both.")
|
||||
|
||||
cli_args = [url]
|
||||
cli_args = [url] if url else []
|
||||
if input_file:
|
||||
cli_args.extend(["--input-file", input_file])
|
||||
field_flags = {
|
||||
"lang": "--lang",
|
||||
"browser": "--browser",
|
||||
@@ -168,6 +178,24 @@ def _form_to_cli_args(form: dict[str, str | bool]) -> list[str]:
|
||||
return cli_args
|
||||
|
||||
|
||||
def _stage_uploaded_mp4(uploaded_file: str | None) -> str:
|
||||
if not uploaded_file:
|
||||
return ""
|
||||
|
||||
source_path = Path(uploaded_file)
|
||||
if source_path.suffix.lower() != ".mp4":
|
||||
raise ValueError("Only MP4 uploads are supported.")
|
||||
if not source_path.exists():
|
||||
raise FileNotFoundError(f"Uploaded file not found: {source_path}")
|
||||
|
||||
safe_stem = "".join(char if char.isalnum() or char in {"-", "_"} else "_" for char in source_path.stem)
|
||||
staged_name = f"{uuid.uuid4().hex[:12]}_{safe_stem or 'upload'}.mp4"
|
||||
UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
|
||||
staged_path = UPLOAD_DIR / staged_name
|
||||
shutil.copy2(source_path, staged_path)
|
||||
return str(staged_path)
|
||||
|
||||
|
||||
def _format_job_status(job: DubJob | None) -> str:
|
||||
if job is None:
|
||||
return "Ready"
|
||||
@@ -234,6 +262,7 @@ def _output_choices() -> list[str]:
|
||||
|
||||
def _start_job(
|
||||
url: str,
|
||||
uploaded_mp4: str | None,
|
||||
lang: str,
|
||||
whisper_model: str,
|
||||
mix_mode: str,
|
||||
@@ -248,8 +277,15 @@ def _start_job(
|
||||
base_url = (lmstudio_base_url or "").strip() or saved_settings["base_url"]
|
||||
api_key = (lmstudio_api_key or "").strip() or saved_settings["api_key"]
|
||||
model = (lmstudio_model or "").strip() or saved_settings["model"]
|
||||
try:
|
||||
input_file = _stage_uploaded_mp4(uploaded_mp4)
|
||||
except (OSError, ValueError) as exc:
|
||||
message = str(exc) or "Invalid uploaded MP4."
|
||||
return "", message, message, gr.update(choices=_output_choices())
|
||||
|
||||
form = {
|
||||
"url": url,
|
||||
"input_file": input_file,
|
||||
"lang": lang,
|
||||
"whisper_model": whisper_model,
|
||||
"mix_mode": mix_mode,
|
||||
@@ -323,6 +359,11 @@ def create_app() -> gr.Blocks:
|
||||
with gr.Row():
|
||||
with gr.Column(scale=5):
|
||||
url = gr.Textbox(label="YouTube URL", placeholder="https://www.youtube.com/watch?v=...")
|
||||
uploaded_mp4 = gr.File(
|
||||
label="Upload MP4",
|
||||
file_types=[".mp4"],
|
||||
type="filepath",
|
||||
)
|
||||
with gr.Row():
|
||||
lang = gr.Textbox(label="Target Language", value="es", max_lines=1)
|
||||
whisper_model = gr.Dropdown(
|
||||
@@ -386,6 +427,7 @@ def create_app() -> gr.Blocks:
|
||||
|
||||
inputs = [
|
||||
url,
|
||||
uploaded_mp4,
|
||||
lang,
|
||||
whisper_model,
|
||||
mix_mode,
|
||||
|
||||
Reference in New Issue
Block a user