import json import os import sqlite3 from datetime import datetime from typing import Optional import requests from fastapi import FastAPI, File, Form, HTTPException, UploadFile from fastapi.responses import HTMLResponse API_BASE = os.getenv("API_BASE", "http://gx10.aquantico.lan:8093").rstrip("/") OLLAMA_BASE_URL = os.getenv("OLLAMA_BASE_URL", "http://gx10.aquantico.lan:11434").rstrip("/") OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "qwen3.5:9b") DB_PATH = os.getenv("DB_PATH", "/data/ui.db") app = FastAPI(title="Diarization UI + LLM") def db(): conn = sqlite3.connect(DB_PATH) conn.row_factory = sqlite3.Row return conn def init_db(): os.makedirs(os.path.dirname(DB_PATH), exist_ok=True) with db() as c: c.execute( """ CREATE TABLE IF NOT EXISTS transcripts ( id INTEGER PRIMARY KEY AUTOINCREMENT, created_at TEXT NOT NULL, filename TEXT, formatted_text TEXT NOT NULL, raw_json TEXT NOT NULL ) """ ) c.execute( """ CREATE TABLE IF NOT EXISTS analyses ( id INTEGER PRIMARY KEY AUTOINCREMENT, transcript_id INTEGER NOT NULL, created_at TEXT NOT NULL, prompt TEXT NOT NULL, answer TEXT NOT NULL, FOREIGN KEY(transcript_id) REFERENCES transcripts(id) ) """ ) @app.on_event("startup") def startup(): init_db() @app.get("/healthz") def healthz(): return { "ok": True, "api_base": API_BASE, "ollama_base_url": OLLAMA_BASE_URL, "ollama_model": OLLAMA_MODEL, "db_path": DB_PATH, } @app.get("/", response_class=HTMLResponse) def index(): return """ Diarization UI

Upload -> Transcribe + Diarize -> speichern -> LLM Analyse



Analyse



Gespeicherte Transkripte

""" @app.post("/process") async def process(file: UploadFile = File(...)): data = await file.read() if not data: raise HTTPException(400, "empty file") files = {"file": (file.filename or "audio.bin", data, file.content_type or "application/octet-stream")} try: r = requests.post(f"{API_BASE}/transcribe-diarize", files=files, timeout=1800) except Exception as e: raise HTTPException(502, f"API unreachable: {e}") if r.status_code >= 400: raise HTTPException(r.status_code, r.text) payload = r.json() formatted = payload.get("formatted_text", "") with db() as c: cur = c.execute( "INSERT INTO transcripts(created_at, filename, formatted_text, raw_json) VALUES (?,?,?,?)", (datetime.utcnow().isoformat(), file.filename, formatted, json.dumps(payload, ensure_ascii=False)), ) transcript_id = cur.lastrowid return {"ok": True, "transcript_id": transcript_id, **payload} @app.get("/transcripts") def transcripts(limit: int = 20): with db() as c: rows = c.execute( "SELECT id, created_at, filename, formatted_text FROM transcripts ORDER BY id DESC LIMIT ?", (limit,), ).fetchall() return {"items": [dict(r) for r in rows]} @app.post("/analyze") def analyze(transcript_id: int = Form(...), prompt: str = Form(...)): with db() as c: row = c.execute("SELECT formatted_text FROM transcripts WHERE id=?", (transcript_id,)).fetchone() if not row: raise HTTPException(404, "transcript not found") transcript_text = row[0] llm_prompt = ( "Du bist ein Meeting-Analyst. Arbeite auf Deutsch.\n" "Erzeuge präzise Ausgabe für den folgenden Auftrag.\n\n" f"AUFTRAG:\n{prompt}\n\n" f"TRANSKRIPT:\n{transcript_text}\n" ) body = { "model": OLLAMA_MODEL, "prompt": llm_prompt, "stream": False, } try: r = requests.post(f"{OLLAMA_BASE_URL}/api/generate", json=body, timeout=600) except Exception as e: raise HTTPException(502, f"Ollama unreachable: {e}") if r.status_code >= 400: raise HTTPException(r.status_code, r.text) j = r.json() answer = j.get("response", "") with db() as c: cur = c.execute( "INSERT INTO analyses(transcript_id, created_at, prompt, answer) VALUES (?,?,?,?)", (transcript_id, datetime.utcnow().isoformat(), prompt, answer), ) analysis_id = cur.lastrowid return {"ok": True, "analysis_id": analysis_id, "answer": answer}