root f408a555f8 feat: kontinuierliche LXC↔Mac-Diagnose + Auto-Retry
Diagnose-Sichtbarkeit (Plan A):
- Job.step_started_at + last_heartbeat_at, Heartbeat-Task pingt alle 3 s
  während laufender Mac-Calls
- Mac-Worker hält per X-Job-Id Header einen Log-Ringbuffer pro Job
  (200 Zeilen, 1 h TTL); GET /api/jobs/{id}/log liefert ihn aus
- LXC-Endpoint GET /api/jobs/{id}/diag bündelt Job-Status, Stage-Sekunden,
  Heartbeat-Alter und Mac-Worker-Log
- Frontend: Live-Timing im Status-Pill ("läuft seit Xs · letzter Ping vor Ys"),
  klappbares Diagnose-Panel mit Mac-Log für FAILED + langlaufende Jobs

Robustheit (Plan B):
- MacClient: einmaliger Retry mit 3 s Backoff bei RemoteProtocolError /
  ConnectError / ReadError für summarize/protocol/export
- Mac-Worker /api/preload heizt Ollama vor (keep_alive 30 m, num_predict 1);
  Pipeline ruft Preload vor summarize, damit Modell-Reload nicht mitten
  in der Generierung passiert (Hauptursache "Server disconnected")

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 09:12:27 +00:00

35 lines
1.1 KiB
Python

from datetime import datetime, timezone
from typing import Optional
from sqlmodel import SQLModel, Field
class JobStatus:
QUEUED = "queued"
TRANSCRIBING = "transcribing"
SUMMARIZING = "summarizing"
PROTOCOLLING = "protocolling"
EXPORTING = "exporting"
DONE = "done"
FAILED = "failed"
class Job(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
owner_id: Optional[int] = Field(default=None, foreign_key="user.id", index=True)
profile: str = Field(default="meeting")
filename: str
original_name: str
title: str = ""
status: str = JobStatus.QUEUED
progress: int = 0
error: str = ""
transcript_path: str = ""
summary_path: str = ""
protocol_path: str = ""
docx_path: str = ""
pdf_path: str = ""
step_started_at: Optional[datetime] = Field(default=None)
last_heartbeat_at: Optional[datetime] = Field(default=None)
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))