- shared/ = portable Android-origin sources vendored from deferred/desktop-server (app/build.gradle.kts srcDir repointed; PlaybackController.kt excluded as Android-only) - backend/ = bundled-lite engine (SQLite + inline queue); .venv symlinked from the old checkout, PYTHONPATH pins THIS backend's code over any editable install - repoRoot() resolves this project dir (env SHONAR_REPO still wins); desktop-dev.sh watches shared/ + backend/ - Verified: :app:compileKotlin + :app:test green (23 tests); engine boots on :8010, self-migrates, /healthz ok
65 lines
2.3 KiB
Python
65 lines
2.3 KiB
Python
"""Health and system endpoints."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import time
|
|
|
|
from fastapi import APIRouter
|
|
from sqlalchemy import text
|
|
|
|
from shonar.api.deps import SessionDep
|
|
from shonar.core.config import get_settings
|
|
|
|
router = APIRouter(tags=["health"])
|
|
|
|
_STARTED = time.monotonic()
|
|
|
|
|
|
@router.get("/healthz")
|
|
async def healthz() -> dict:
|
|
"""Liveness: process up. No auth, no dependencies."""
|
|
return {"status": "ok", "uptime_seconds": round(time.monotonic() - _STARTED, 1)}
|
|
|
|
|
|
@router.get("/readyz")
|
|
async def readyz(session: SessionDep) -> dict:
|
|
"""Readiness: database reachable. Config warnings surfaced for admins
|
|
via /api/v1/system/status instead of failing readiness."""
|
|
try:
|
|
await session.execute(text("SELECT 1"))
|
|
db_ok = True
|
|
except Exception:
|
|
db_ok = False
|
|
status_code_body = {"status": "ok" if db_ok else "degraded", "database": db_ok}
|
|
return status_code_body
|
|
|
|
|
|
@router.get("/system/status")
|
|
async def system_status() -> dict:
|
|
"""Public-ish status: which AI features are enabled (never any secrets).
|
|
The app uses this to show honest AI-processing state to users."""
|
|
settings = get_settings()
|
|
return {
|
|
"app": settings.app_name,
|
|
"registration_enabled": settings.allow_registration,
|
|
"ai": {
|
|
"transcription_provider": settings.transcription_provider,
|
|
"transcription_enabled": settings.transcription_provider != "none",
|
|
"llm_provider": settings.llm_provider,
|
|
"llm_enabled": settings.llm_provider != "none",
|
|
# Explicit disclosure: are any external (non-local) calls made?
|
|
"external_ai_in_use": (
|
|
settings.transcription_provider == "whisper_http"
|
|
and "localhost" not in settings.transcription_base_url
|
|
and "127.0.0.1" not in settings.transcription_base_url
|
|
)
|
|
or (
|
|
settings.llm_provider == "openai_compat"
|
|
and "localhost" not in settings.llm_base_url
|
|
and "127.0.0.1" not in settings.llm_base_url
|
|
),
|
|
},
|
|
"storage_backend": settings.storage_backend,
|
|
"audio_conversion_enabled": settings.audio_conversion_enabled,
|
|
"config_warnings": settings.validate_production(),
|
|
}
|