Persist web UI translation settings
This commit is contained in:
101
web_app.py
101
web_app.py
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timezone
|
||||
import json
|
||||
from pathlib import Path
|
||||
import os
|
||||
import subprocess
|
||||
@@ -17,10 +18,16 @@ import gradio as gr
|
||||
from main import build_parser
|
||||
from src.audio_separation import DEFAULT_MIX_MODE
|
||||
from src.engines import OUTPUT_DIR
|
||||
from src.translation import (
|
||||
DEFAULT_LM_STUDIO_API_KEY,
|
||||
DEFAULT_LM_STUDIO_BASE_URL,
|
||||
DEFAULT_LM_STUDIO_MODEL,
|
||||
)
|
||||
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
LOG_DIR = BASE_DIR / "logs" / "gradio"
|
||||
SETTINGS_FILE = BASE_DIR / ".cache" / "web_settings.json"
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -30,6 +37,7 @@ class DubJob:
|
||||
id: str
|
||||
command: list[str]
|
||||
log_path: Path
|
||||
env_overrides: dict[str, str] = field(default_factory=dict)
|
||||
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
status: str = "queued"
|
||||
returncode: int | None = None
|
||||
@@ -40,6 +48,52 @@ JOBS: dict[str, DubJob] = {}
|
||||
JOBS_LOCK = threading.Lock()
|
||||
|
||||
|
||||
def _default_translation_settings() -> dict[str, str]:
|
||||
return {
|
||||
"base_url": os.getenv("LM_STUDIO_BASE_URL") or DEFAULT_LM_STUDIO_BASE_URL,
|
||||
"api_key": os.getenv("LM_STUDIO_API_KEY") or DEFAULT_LM_STUDIO_API_KEY,
|
||||
"model": os.getenv("LM_STUDIO_MODEL") or DEFAULT_LM_STUDIO_MODEL,
|
||||
}
|
||||
|
||||
|
||||
def load_translation_settings() -> dict[str, str]:
|
||||
"""Load saved OpenAI-compatible translation settings."""
|
||||
settings = _default_translation_settings()
|
||||
if not SETTINGS_FILE.exists():
|
||||
return settings
|
||||
|
||||
try:
|
||||
payload = json.loads(SETTINGS_FILE.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError):
|
||||
return settings
|
||||
|
||||
if not isinstance(payload, dict):
|
||||
return settings
|
||||
|
||||
for key in settings:
|
||||
value = payload.get(key)
|
||||
if isinstance(value, str) and value.strip():
|
||||
settings[key] = value.strip()
|
||||
return settings
|
||||
|
||||
|
||||
def save_translation_settings(base_url: str, api_key: str, model: str) -> tuple[str, str, str, str]:
|
||||
"""Persist OpenAI-compatible endpoint settings for future web jobs."""
|
||||
settings = {
|
||||
"base_url": (base_url or "").strip() or DEFAULT_LM_STUDIO_BASE_URL,
|
||||
"api_key": (api_key or "").strip() or DEFAULT_LM_STUDIO_API_KEY,
|
||||
"model": (model or "").strip() or DEFAULT_LM_STUDIO_MODEL,
|
||||
}
|
||||
SETTINGS_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
SETTINGS_FILE.write_text(json.dumps(settings, indent=2), encoding="utf-8")
|
||||
return (
|
||||
settings["base_url"],
|
||||
settings["api_key"],
|
||||
settings["model"],
|
||||
f"Saved settings to {SETTINGS_FILE}",
|
||||
)
|
||||
|
||||
|
||||
def _utc_iso(value: datetime | None) -> str | None:
|
||||
if value is None:
|
||||
return None
|
||||
@@ -143,6 +197,7 @@ def _run_job(job: DubJob) -> None:
|
||||
|
||||
env = os.environ.copy()
|
||||
env["PYTHONUNBUFFERED"] = "1"
|
||||
env.update(job.env_overrides)
|
||||
|
||||
with job.log_path.open("w", encoding="utf-8", errors="replace") as log_file:
|
||||
log_file.write("Gradio started a YouTube Auto Dub job.\n")
|
||||
@@ -185,9 +240,14 @@ def _start_job(
|
||||
browser: str,
|
||||
cookies: str,
|
||||
lmstudio_base_url: str,
|
||||
lmstudio_api_key: str,
|
||||
lmstudio_model: str,
|
||||
gpu: bool,
|
||||
) -> tuple[str, str, str, gr.Dropdown]:
|
||||
saved_settings = load_translation_settings()
|
||||
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"]
|
||||
form = {
|
||||
"url": url,
|
||||
"lang": lang,
|
||||
@@ -196,8 +256,8 @@ def _start_job(
|
||||
"browser": browser,
|
||||
"cookies": cookies,
|
||||
"translation_backend": "lmstudio",
|
||||
"lmstudio_base_url": lmstudio_base_url,
|
||||
"lmstudio_model": lmstudio_model,
|
||||
"lmstudio_base_url": base_url,
|
||||
"lmstudio_model": model,
|
||||
"gpu": gpu,
|
||||
}
|
||||
|
||||
@@ -213,6 +273,11 @@ def _start_job(
|
||||
id=job_id,
|
||||
command=command,
|
||||
log_path=LOG_DIR / f"{job_id}.log",
|
||||
env_overrides={
|
||||
"LM_STUDIO_BASE_URL": base_url,
|
||||
"LM_STUDIO_API_KEY": api_key,
|
||||
"LM_STUDIO_MODEL": model,
|
||||
},
|
||||
)
|
||||
|
||||
with JOBS_LOCK:
|
||||
@@ -245,6 +310,7 @@ def _select_output(filename: str | None) -> str | None:
|
||||
|
||||
def create_app() -> gr.Blocks:
|
||||
"""Create the Gradio app."""
|
||||
saved_settings = load_translation_settings()
|
||||
with gr.Blocks(title="Gradio YouTube Auto Dub") as demo:
|
||||
gr.Markdown(
|
||||
"""
|
||||
@@ -277,12 +343,29 @@ def create_app() -> gr.Blocks:
|
||||
)
|
||||
cookies = gr.Textbox(label="Cookies File", placeholder=r"C:\path\to\cookies.txt")
|
||||
|
||||
with gr.Accordion("Translation Settings", open=False):
|
||||
with gr.Accordion("OpenAI-Compatible Settings", open=False):
|
||||
lmstudio_base_url = gr.Textbox(
|
||||
label="LM Studio URL",
|
||||
placeholder="http://127.0.0.1:1234/v1",
|
||||
label="Endpoint",
|
||||
value=saved_settings["base_url"],
|
||||
placeholder=DEFAULT_LM_STUDIO_BASE_URL,
|
||||
)
|
||||
lmstudio_model = gr.Textbox(label="Model", placeholder="gemma-3-4b-it")
|
||||
lmstudio_api_key = gr.Textbox(
|
||||
label="API Key",
|
||||
value=saved_settings["api_key"],
|
||||
type="password",
|
||||
)
|
||||
lmstudio_model = gr.Textbox(
|
||||
label="Model",
|
||||
value=saved_settings["model"],
|
||||
placeholder=DEFAULT_LM_STUDIO_MODEL,
|
||||
)
|
||||
with gr.Row():
|
||||
save_settings = gr.Button("Save Settings")
|
||||
settings_status = gr.Textbox(
|
||||
label="Settings Status",
|
||||
value=f"Loaded from {SETTINGS_FILE if SETTINGS_FILE.exists() else 'environment defaults'}",
|
||||
interactive=False,
|
||||
)
|
||||
gpu = gr.Checkbox(label="Prefer GPU", value=False)
|
||||
|
||||
start = gr.Button("Start Dub", variant="primary")
|
||||
@@ -309,9 +392,15 @@ def create_app() -> gr.Blocks:
|
||||
browser,
|
||||
cookies,
|
||||
lmstudio_base_url,
|
||||
lmstudio_api_key,
|
||||
lmstudio_model,
|
||||
gpu,
|
||||
]
|
||||
save_settings.click(
|
||||
save_translation_settings,
|
||||
inputs=[lmstudio_base_url, lmstudio_api_key, lmstudio_model],
|
||||
outputs=[lmstudio_base_url, lmstudio_api_key, lmstudio_model, settings_status],
|
||||
)
|
||||
start.click(
|
||||
_start_job,
|
||||
inputs=inputs,
|
||||
|
||||
Reference in New Issue
Block a user