Files
VoiceStudio/backend/api/schemas.py
T
Palash DebnathandClaude Opus 4.8 e740786a08 fix(about): show server CPU arch, not the client browser's platform (#262) (#266)
Settings → About → Architecture rendered `navigator.platform` — the *client
browser's* OS. In the Docker/web build that's the remote machine (e.g. "Win32"
when browsing from Windows), not the container, which is misleading.

Expose the server's `platform.machine()` as `arch` on /system/info and render
that instead, so the row reflects the machine OmniVoice actually runs on — for
both the desktop app (local backend) and Docker.

Note: the *blank* version/GPU/RAM/VRAM in the same report were the loopback-gate
403s fixed in v0.3.2 (#261); this PR fixes the remaining architecture row.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 07:06:30 +05:30

179 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Pydantic v2 schemas for request/response validation.
Shared across routers — import from here rather than defining inline.
Using ``model_config = ConfigDict(...)`` for Pydantic v2 compat.
"""
from __future__ import annotations
from pydantic import BaseModel, ConfigDict, Field
# ── System ────────────────────────────────────────────────────────────────
class SysinfoResponse(BaseModel):
"""GET /sysinfo"""
model_config = ConfigDict(extra="allow")
cpu: float = Field(description="CPU usage percentage (0100)")
ram: float = Field(description="Used RAM in GiB")
total_ram: float = Field(description="Total RAM in GiB")
vram: float = Field(0.0, description="Used VRAM in GiB")
gpu_active: bool = Field(False, description="Whether a GPU is actively used")
class SystemInfoResponse(BaseModel):
"""GET /system/info"""
model_config = ConfigDict(extra="allow")
app_version: str = ""
data_dir: str
outputs_dir: str
crash_log_path: str
idle_timeout_seconds: int
model_checkpoint: str = "unknown"
asr_model: str = "unknown"
translate_provider: str = "unknown"
has_hf_token: bool = False
device: str = "cpu"
python: str = ""
platform: str = ""
arch: str = ""
error: str | None = None
ffmpeg_ok: bool = False
ffmpeg_path: str = ""
proxy_url: str = ""
share_enabled: bool = False
share_port: int | None = None
lan_addresses: list[str] = []
pin_required: bool = False
backend_port: int = 3900
share_port_base: int = 3901
ui_port: int = 3901
class ModelStatusResponse(BaseModel):
"""GET /model/status"""
model_config = ConfigDict(extra="allow")
status: str = Field(description="idle | loading | ready")
checkpoint: str | None = None
loaded_at: str | None = None
sub_stage: str | None = Field(None, description="Current loading sub-stage: importing | loading_weights | loading_asr | compiling | ready | error")
detail: str | None = Field(None, description="Human-readable detail of current loading phase")
error: str | None = Field(None, description="Error message if loading failed")
class LogsResponse(BaseModel):
"""GET /system/logs"""
lines: list[str] = Field(default_factory=list)
path: str = ""
exists: bool = False
total_lines: int = 0
error: str | None = None
candidates: list[str] | None = None
class FlushMemoryResponse(BaseModel):
"""POST /system/flush-memory"""
flushed: bool = True
unloaded_model: bool = False
ram_after: float = 0.0
vram_after: float = 0.0
# ── Setup ─────────────────────────────────────────────────────────────────
class MissingModel(BaseModel):
repo_id: str
label: str
class SetupStatusResponse(BaseModel):
"""GET /setup/status"""
models_ready: bool
missing: list[MissingModel] = Field(default_factory=list)
hf_cache_dir: str
disk_free_gb: float
min_free_gb: int = 10
enough_disk: bool = True
class PreflightCheck(BaseModel):
"""One check in the preflight report."""
model_config = ConfigDict(extra="allow")
id: str
label: str
status: str = Field(description="pass | warn | fail")
detail: str = ""
fix: str | None = None
class DeviceInfo(BaseModel):
"""GPU/system device info from preflight."""
model_config = ConfigDict(extra="allow")
os: str
arch: str
gpu_vendor: str = "none"
gpu_backend: str = "cpu"
gpu_available: bool = False
gpu_driver: str | None = None
gpu_device_name: str | None = None
ram_gb: float = 0.0
disk_free_gb: float = 0.0
class PreflightResponse(BaseModel):
"""GET /setup/preflight"""
ok: bool
has_warnings: bool = False
checks: list[PreflightCheck] = Field(default_factory=list)
device: DeviceInfo
class InstallModelRequest(BaseModel):
"""POST /models/install"""
repo_id: str
class DeleteModelResponse(BaseModel):
"""DELETE /models/{repo_id}"""
deleted: bool = True
repo_id: str
freed_bytes: int = 0
# ── Models list ───────────────────────────────────────────────────────────
class ModelEntry(BaseModel):
"""One model in the GET /models response."""
model_config = ConfigDict(extra="allow")
repo_id: str
label: str
role: str
size: str = ""
required: bool = False
installed: bool = False
supported: bool = True
size_on_disk: int | None = None
nb_files: int | None = None
# ── Effect presets ─────────────────────────────────────────────────────
class EffectPresetEntry(BaseModel):
"""One DSP effect preset."""
model_config = ConfigDict(extra="allow")
id: str
label: str
icon: str
description: str
class EffectPresetsResponse(BaseModel):
"""GET /engines/effects/presets"""
presets: list[EffectPresetEntry] = Field(default_factory=list)