Standalone Shonar Desktop: vendor portable sources + local engine; decouple from ~/Projects/Shonar
- 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
This commit is contained in:
commit
76c867fca4
136 changed files with 21099 additions and 0 deletions
65
backend/shonar/api/v1/health.py
Normal file
65
backend/shonar/api/v1/health.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
"""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(),
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue