initial commit
This commit is contained in:
74
tools/autofill_translations.py
Normal file
74
tools/autofill_translations.py
Normal file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sqlite3
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
DB_FILE = os.path.join(os.path.dirname(__file__), 'summaries.db')
|
||||
TRANSLATE_SCRIPT = os.path.join(os.path.dirname(__file__), 'translate_summary.py')
|
||||
MODEL = "mistral-small3.1:24b"
|
||||
|
||||
def get_entries_needing_translation(conn):
|
||||
cursor = conn.cursor()
|
||||
cursor.execute(
|
||||
"SELECT id, summary_en, summary_de, summary_jp FROM summaries"
|
||||
)
|
||||
return [
|
||||
(row[0], row[1], row[2], row[3])
|
||||
for row in cursor.fetchall()
|
||||
if row[1] and (not row[2] or not row[3]) # summary_en vorhanden, mind. eine Übersetzung fehlt
|
||||
]
|
||||
|
||||
def translate(summary_text, lang):
|
||||
# Schreibe summary_text temporär in Datei
|
||||
import tempfile
|
||||
with tempfile.NamedTemporaryFile('w+', delete=False, suffix='.txt', encoding='utf-8') as f:
|
||||
f.write(summary_text)
|
||||
tmp_summary_path = f.name
|
||||
try:
|
||||
# Führe das Übersetzungsskript aus
|
||||
cmd = [
|
||||
sys.executable, # benutzt aktuelles Python
|
||||
TRANSLATE_SCRIPT,
|
||||
"--summary-file", tmp_summary_path,
|
||||
"--lang", lang,
|
||||
"--model", MODEL,
|
||||
]
|
||||
print(f"[{lang}] Translating with: {' '.join(cmd)}")
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
|
||||
translation = result.stdout.strip()
|
||||
return translation
|
||||
finally:
|
||||
os.remove(tmp_summary_path)
|
||||
|
||||
def main():
|
||||
conn = sqlite3.connect(DB_FILE)
|
||||
cursor = conn.cursor()
|
||||
entries = get_entries_needing_translation(conn)
|
||||
print(f"Found {len(entries)} entries needing translation.")
|
||||
for entry_id, summary_en, summary_de, summary_jp in entries:
|
||||
updated = False
|
||||
if not summary_de:
|
||||
print(f"Translating to DE for entry id {entry_id}…")
|
||||
try:
|
||||
translation = translate(summary_en, "de")
|
||||
cursor.execute("UPDATE summaries SET summary_de = ? WHERE id = ?", (translation, entry_id))
|
||||
updated = True
|
||||
except Exception as e:
|
||||
print(f"Failed to translate DE for id {entry_id}: {e}")
|
||||
if not summary_jp:
|
||||
print(f"Translating to JP for entry id {entry_id}…")
|
||||
try:
|
||||
translation = translate(summary_en, "jp")
|
||||
cursor.execute("UPDATE summaries SET summary_jp = ? WHERE id = ?", (translation, entry_id))
|
||||
updated = True
|
||||
except Exception as e:
|
||||
print(f"Failed to translate JP for id {entry_id}: {e}")
|
||||
if updated:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print("Done.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
161
tools/prepare_bundle.py
Normal file
161
tools/prepare_bundle.py
Normal file
@@ -0,0 +1,161 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Prepare local bundle assets for a distributable Tauri build.
|
||||
|
||||
This script:
|
||||
1. installs PyInstaller into the current Python environment
|
||||
2. builds the bundled backend helper as a single executable
|
||||
3. copies ffmpeg / ffprobe from the local PATH into Tauri resources
|
||||
|
||||
It targets the current host platform. Run it once per build machine before
|
||||
`cargo tauri build`.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SRC_TAURI = ROOT / "src-tauri"
|
||||
BACKEND_ROOT = SRC_TAURI / "resources" / "backend"
|
||||
FFMPEG_ROOT = SRC_TAURI / "resources" / "ffmpeg"
|
||||
BUILD_DIR = ROOT / "build"
|
||||
DIST_DIR = BUILD_DIR / "pyinstaller-dist"
|
||||
WORK_DIR = BUILD_DIR / "pyinstaller-work"
|
||||
SPEC_DIR = BUILD_DIR / "pyinstaller-spec"
|
||||
BACKEND_NAME = "yts-backend"
|
||||
|
||||
|
||||
def run(cmd: list[str]) -> None:
|
||||
subprocess.run(cmd, check=True, cwd=ROOT)
|
||||
|
||||
|
||||
def detect_target_triple() -> str:
|
||||
try:
|
||||
output = subprocess.check_output(["rustc", "--print", "host-tuple"], text=True)
|
||||
return output.strip()
|
||||
except subprocess.CalledProcessError:
|
||||
verbose = subprocess.check_output(["rustc", "-Vv"], text=True)
|
||||
for line in verbose.splitlines():
|
||||
if line.startswith("host: "):
|
||||
return line.split(": ", 1)[1].strip()
|
||||
raise SystemExit("Unable to determine the Rust host target triple.")
|
||||
|
||||
|
||||
def executable_suffix() -> str:
|
||||
return ".exe" if os.name == "nt" else ""
|
||||
|
||||
|
||||
def ensure_pyinstaller() -> None:
|
||||
run([sys.executable, "-m", "pip", "install", "--upgrade", "pip"])
|
||||
run([sys.executable, "-m", "pip", "install", "-r", str(ROOT / "requirements.txt"), "pyinstaller"])
|
||||
|
||||
|
||||
def build_backend_binary() -> Path:
|
||||
DIST_DIR.mkdir(parents=True, exist_ok=True)
|
||||
WORK_DIR.mkdir(parents=True, exist_ok=True)
|
||||
SPEC_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
cmd = [
|
||||
sys.executable,
|
||||
"-m",
|
||||
"PyInstaller",
|
||||
"--noconfirm",
|
||||
"--clean",
|
||||
"--onefile",
|
||||
"--name",
|
||||
BACKEND_NAME,
|
||||
"--distpath",
|
||||
str(DIST_DIR),
|
||||
"--workpath",
|
||||
str(WORK_DIR),
|
||||
"--specpath",
|
||||
str(SPEC_DIR),
|
||||
"--paths",
|
||||
str(ROOT),
|
||||
"--collect-submodules",
|
||||
"whisper",
|
||||
"--collect-submodules",
|
||||
"yt_dlp",
|
||||
"--collect-submodules",
|
||||
"youtube_transcript_api",
|
||||
"--collect-data",
|
||||
"whisper",
|
||||
"--collect-data",
|
||||
"yt_dlp",
|
||||
"--collect-data",
|
||||
"webvtt",
|
||||
"--collect-data",
|
||||
"youtube_transcript_api",
|
||||
str(ROOT / "backend_cli.py"),
|
||||
]
|
||||
run(cmd)
|
||||
binary = DIST_DIR / f"{BACKEND_NAME}{executable_suffix()}"
|
||||
if not binary.exists():
|
||||
raise SystemExit(f"Expected backend binary was not produced: {binary}")
|
||||
return binary
|
||||
|
||||
|
||||
def install_sidecar(binary: Path, target_triple: str) -> Path:
|
||||
target_dir = BACKEND_ROOT / target_triple
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
target = target_dir / f"{BACKEND_NAME}{executable_suffix()}"
|
||||
shutil.copy2(binary, target)
|
||||
if os.name != "nt":
|
||||
target.chmod(target.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||
return target
|
||||
|
||||
|
||||
def resolve_tool_source(env_name: str, tool_name: str) -> Path:
|
||||
override = os.environ.get(env_name, "").strip()
|
||||
if override:
|
||||
return Path(override).expanduser().resolve()
|
||||
|
||||
source = shutil.which(tool_name)
|
||||
if not source:
|
||||
raise SystemExit(
|
||||
f"Required build dependency not found: {tool_name}. "
|
||||
f"Put it on PATH or set {env_name}."
|
||||
)
|
||||
return Path(source).resolve()
|
||||
|
||||
|
||||
def copy_tool_to_resources(env_name: str, tool_name: str, resource_dir: Path) -> Path:
|
||||
source_path = resolve_tool_source(env_name, tool_name)
|
||||
destination = resource_dir / source_path.name
|
||||
shutil.copy2(source_path, destination)
|
||||
if os.name != "nt":
|
||||
destination.chmod(destination.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
||||
return destination
|
||||
|
||||
|
||||
def install_ffmpeg_resources(target_triple: str) -> tuple[Path, Path]:
|
||||
resource_dir = FFMPEG_ROOT / target_triple
|
||||
resource_dir.mkdir(parents=True, exist_ok=True)
|
||||
ffmpeg = copy_tool_to_resources("YTS_FFMPEG", "ffmpeg", resource_dir)
|
||||
ffprobe = copy_tool_to_resources("YTS_FFPROBE", "ffprobe", resource_dir)
|
||||
return ffmpeg, ffprobe
|
||||
|
||||
|
||||
def main() -> int:
|
||||
target_triple = detect_target_triple()
|
||||
ensure_pyinstaller()
|
||||
backend_binary = build_backend_binary()
|
||||
sidecar = install_sidecar(backend_binary, target_triple)
|
||||
ffmpeg, ffprobe = install_ffmpeg_resources(target_triple)
|
||||
|
||||
print(f"Prepared backend sidecar: {sidecar}")
|
||||
print(f"Prepared ffmpeg resource: {ffmpeg}")
|
||||
print(f"Prepared ffprobe resource: {ffprobe}")
|
||||
print("Next step: cargo tauri build")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user