0.1.0:3 - Show Public Key layout + /api/endpoints service-discovery
- showPublicKey now uses result.group: install command and raw key are each their own one-click copy box; description is brief
- /api/endpoints returns stable shape { vllm, parakeet, magpie } with base_url + model + ready, for other LAN services to consume without hardcoding Spark IPs
- health.py: parakeet/magpie now also expose base_url
- README: documented /api/endpoints shape
This commit is contained in:
+20
-6
@@ -30,24 +30,38 @@ async def check_vllm(settings: Settings) -> dict:
|
||||
|
||||
|
||||
async def check_parakeet(settings: Settings) -> dict:
|
||||
base_url = (
|
||||
f"http://{settings.spark2_host}:{settings.parakeet_port}"
|
||||
if settings.spark2_host
|
||||
else None
|
||||
)
|
||||
if not settings.spark2_host:
|
||||
return {"ok": False, "error": "spark2 not configured"}
|
||||
return {"ok": False, "error": "spark2 not configured", "base_url": base_url}
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=_TIMEOUT) as c:
|
||||
r = await c.get(f"http://{settings.spark2_host}:{settings.parakeet_port}/health")
|
||||
r.raise_for_status()
|
||||
return {"ok": True, "detail": r.json()}
|
||||
return {"ok": True, "detail": r.json(), "base_url": base_url}
|
||||
except Exception as e:
|
||||
return {"ok": False, "error": str(e)}
|
||||
return {"ok": False, "error": str(e), "base_url": base_url}
|
||||
|
||||
|
||||
async def check_magpie(settings: Settings) -> dict:
|
||||
base_url = (
|
||||
f"http://{settings.spark2_host}:{settings.magpie_port}"
|
||||
if settings.spark2_host
|
||||
else None
|
||||
)
|
||||
if not settings.spark2_host:
|
||||
return {"ok": False, "error": "spark2 not configured"}
|
||||
return {"ok": False, "error": "spark2 not configured", "base_url": base_url}
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=_TIMEOUT) as c:
|
||||
r = await c.get(f"http://{settings.spark2_host}:{settings.magpie_port}/v1/health/ready")
|
||||
r.raise_for_status()
|
||||
return {"ok": True, "detail": r.json() if r.headers.get("content-type", "").startswith("application/json") else r.text}
|
||||
return {
|
||||
"ok": True,
|
||||
"detail": r.json() if r.headers.get("content-type", "").startswith("application/json") else r.text,
|
||||
"base_url": base_url,
|
||||
}
|
||||
except Exception as e:
|
||||
return {"ok": False, "error": str(e)}
|
||||
return {"ok": False, "error": str(e), "base_url": base_url}
|
||||
|
||||
@@ -48,6 +48,37 @@ async def get_models() -> dict:
|
||||
}
|
||||
|
||||
|
||||
@app.get("/api/endpoints")
|
||||
async def get_endpoints() -> dict:
|
||||
"""Service-discovery summary. Stable shape; other apps on the LAN can poll this
|
||||
to learn the OpenAI-compatible vLLM endpoint, the Parakeet STT endpoint, and the
|
||||
Magpie TTS endpoint without needing to know the individual Spark IPs."""
|
||||
vllm, parakeet, magpie = await asyncio.gather(
|
||||
check_vllm(settings),
|
||||
check_parakeet(settings),
|
||||
check_magpie(settings),
|
||||
)
|
||||
return {
|
||||
"vllm": {
|
||||
"ready": bool(vllm.get("ok")),
|
||||
"base_url": vllm.get("base_url"),
|
||||
"model": vllm.get("current_model"),
|
||||
"openai_compat": True,
|
||||
},
|
||||
"parakeet": {
|
||||
"ready": bool(parakeet.get("ok")),
|
||||
"base_url": parakeet.get("base_url"),
|
||||
"kind": "stt",
|
||||
"model": (parakeet.get("detail") or {}).get("model") if isinstance(parakeet.get("detail"), dict) else None,
|
||||
},
|
||||
"magpie": {
|
||||
"ready": bool(magpie.get("ok")),
|
||||
"base_url": magpie.get("base_url"),
|
||||
"kind": "tts",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@app.get("/api/status")
|
||||
async def get_status() -> dict:
|
||||
vllm, parakeet, magpie = await asyncio.gather(
|
||||
|
||||
Reference in New Issue
Block a user