Initial commit: Nat20 Notes — TTRPG session transcription & summarization

This commit is contained in:
KansaiGaijin
2026-07-06 23:45:54 +12:00
commit 524c8ab96d
50 changed files with 2969 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
import shutil
import subprocess
import requests
from . import database as db, config
def _check_ffmpeg() -> dict:
path = shutil.which("ffmpeg")
if not path:
return {"name": "ffmpeg", "ok": False, "message": "ffmpeg not found on PATH. This should be baked into the Docker image - if you're seeing this, the image build is broken."}
return {"name": "ffmpeg", "ok": True, "message": path}
def _check_gpu() -> dict:
try:
import torch
if torch.cuda.is_available():
name = torch.cuda.get_device_name(0)
free, total = torch.cuda.mem_get_info(0)
free_gb, total_gb = free / 1e9, total / 1e9
return {"name": "gpu", "ok": True, "message": f"{name}{free_gb:.1f}GB free of {total_gb:.1f}GB"}
return {"name": "gpu", "ok": False, "message": "No CUDA GPU visible. Check that the container was started with --gpus all / GPU passthrough in compose, and that host NVIDIA drivers + Container Toolkit are installed. Transcription will fall back to CPU, which is much slower."}
except Exception as e:
return {"name": "gpu", "ok": False, "message": f"Could not query GPU: {e}"}
def _check_hf_token() -> dict:
settings = db.get_settings()
token = settings.get("hf_token", "")
if not token:
return {"name": "huggingface_token", "ok": False, "message": "No HF token set. Diarization (speaker separation) will fail without one. Add it in Settings."}
return {"name": "huggingface_token", "ok": True, "message": "Token is set (not validated against HF until first diarization run)."}
def _check_llm_backend() -> dict:
settings = db.get_settings()
if settings.get("llm_mode") == "api":
if not settings.get("api_key"):
return {"name": "llm_backend", "ok": False, "message": "Hosted API selected but no API key set."}
return {"name": "llm_backend", "ok": True, "message": f"Hosted API configured ({settings.get('api_base_url')})"}
host = settings.get("ollama_host", "http://localhost:11434")
model = settings.get("ollama_model", "")
try:
resp = requests.get(f"{host.rstrip('/')}/api/tags", timeout=5)
resp.raise_for_status()
models = [m["name"] for m in resp.json().get("models", [])]
if model not in models:
return {"name": "llm_backend", "ok": False, "message": f"Reached Ollama at {host}, but model '{model}' isn't pulled there. Available: {', '.join(models) or '(none)'}. Run: ollama pull {model}"}
return {"name": "llm_backend", "ok": True, "message": f"Ollama reachable at {host}, model '{model}' available"}
except requests.exceptions.ConnectionError:
return {"name": "llm_backend", "ok": False, "message": f"Could not connect to Ollama at {host}. Check the host/port in Settings, and that Ollama is running and reachable from this container."}
except Exception as e:
return {"name": "llm_backend", "ok": False, "message": f"Error checking Ollama: {e}"}
def _check_disk_space() -> dict:
usage = shutil.disk_usage(config.DATA_DIR)
free_gb = usage.free / 1e9
ok = free_gb > 5
return {"name": "disk_space", "ok": ok, "message": f"{free_gb:.1f}GB free in {config.DATA_DIR}" + ("" if ok else " — this is low, recordings and model caches need room")}
def run_diagnostics() -> list[dict]:
return [
_check_ffmpeg(),
_check_gpu(),
_check_hf_token(),
_check_llm_backend(),
_check_disk_space(),
]