Add files via upload
Adding: - health endpoint - extended /api/config - frontend extension of backend server viz
This commit is contained in:
parent
d577099845
commit
cb7224c030
2 changed files with 93 additions and 8 deletions
68
router.py
68
router.py
|
|
@ -11,7 +11,7 @@ from pathlib import Path
|
|||
from typing import Dict, Set, List
|
||||
from fastapi import FastAPI, Request, HTTPException
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from starlette.responses import StreamingResponse, JSONResponse, Response, HTMLResponse
|
||||
from starlette.responses import StreamingResponse, JSONResponse, Response, HTMLResponse, RedirectResponse
|
||||
from pydantic import Field
|
||||
from pydantic_settings import BaseSettings
|
||||
from collections import defaultdict
|
||||
|
|
@ -821,7 +821,24 @@ async def config_proxy(request: Request):
|
|||
Ollama endpoints. The front‑end uses this to display
|
||||
which endpoints are being proxied.
|
||||
"""
|
||||
return {"endpoints": config.endpoints}
|
||||
async def check_endpoint(url: str):
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=1) as client:
|
||||
if "/v1" in url:
|
||||
r = await client.get(f"{url}/models")
|
||||
else:
|
||||
r = await client.get(f"{url}/api/version")
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
if "/v1" in url:
|
||||
return {"url": url, "status": "ok", "version": "latest"}
|
||||
else:
|
||||
return {"url": url, "status": "ok", "version": data.get("version")}
|
||||
except Exception as exc:
|
||||
return {"url": url, "status": "error", "detail": str(exc)}
|
||||
|
||||
results = await asyncio.gather(*[check_endpoint(ep) for ep in config.endpoints])
|
||||
return {"endpoints": results}
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# 21. API route – OpenAI compatible Embedding
|
||||
|
|
@ -1093,6 +1110,10 @@ async def openai_models_proxy(request: Request):
|
|||
# -------------------------------------------------------------
|
||||
app.mount("/static", StaticFiles(directory="static"), name="static")
|
||||
|
||||
@app.get("/favicon.ico")
|
||||
async def redirect_favicon():
|
||||
return RedirectResponse(url="/static/favicon.ico")
|
||||
|
||||
@app.get("/", response_class=HTMLResponse)
|
||||
async def index(request: Request):
|
||||
"""
|
||||
|
|
@ -1102,7 +1123,48 @@ async def index(request: Request):
|
|||
return HTMLResponse(content=open("static/index.html", "r").read(), status_code=200)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# 26. FastAPI startup event – load configuration
|
||||
# 26. Healthendpoint
|
||||
# -------------------------------------------------------------
|
||||
@app.get("/health")
|
||||
async def health_proxy(request: Request):
|
||||
"""
|
||||
Health‑check endpoint for monitoring the proxy.
|
||||
|
||||
* Queries each configured endpoint for its `/api/version` response.
|
||||
* Returns a JSON object containing:
|
||||
- `status`: "ok" if every endpoint replied, otherwise "error".
|
||||
- `endpoints`: a mapping of endpoint URL → `{status, version|detail}`.
|
||||
* The HTTP status code is 200 when everything is healthy, 503 otherwise.
|
||||
"""
|
||||
# Run all health checks in parallel
|
||||
tasks = [
|
||||
fetch_endpoint_details(ep, "/api/version", "version") for ep in config.endpoints
|
||||
]
|
||||
|
||||
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||
|
||||
health_summary = {}
|
||||
overall_ok = True
|
||||
|
||||
for ep, result in zip(config.endpoints, results):
|
||||
if isinstance(result, Exception):
|
||||
# Endpoint did not respond / returned an error
|
||||
health_summary[ep] = {"status": "error", "detail": str(result)}
|
||||
overall_ok = False
|
||||
else:
|
||||
# Successful response – report the reported version
|
||||
health_summary[ep] = {"status": "ok", "version": result}
|
||||
|
||||
response_payload = {
|
||||
"status": "ok" if overall_ok else "error",
|
||||
"endpoints": health_summary,
|
||||
}
|
||||
|
||||
http_status = 200 if overall_ok else 503
|
||||
return JSONResponse(content=response_payload, status_code=http_status)
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# 27. FastAPI startup event – load configuration
|
||||
# -------------------------------------------------------------
|
||||
@app.on_event("startup")
|
||||
async def startup_event() -> None:
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@
|
|||
order: 0;
|
||||
}
|
||||
}
|
||||
/* Add a tiny status‑style section */
|
||||
.status-ok { color: #006400; font-weight: bold; } /* dark green */
|
||||
.status-error{ color: #8B0000; font-weight: bold; } /* dark red */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -74,9 +77,15 @@
|
|||
|
||||
<h2>Configured Endpoints</h2>
|
||||
<table id="endpoints-table">
|
||||
<thead><tr><th>Endpoint</th></tr></thead>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Endpoint</th>
|
||||
<th>Status</th>
|
||||
<th>Version</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="endpoints-body">
|
||||
<tr><td class="loading">Loading…</td></tr>
|
||||
<tr><td colspan="3" class="loading">Loading…</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
|
@ -91,8 +100,22 @@ async function loadEndpoints(){
|
|||
try{
|
||||
const data = await fetchJSON('/api/config');
|
||||
const body = document.getElementById('endpoints-body');
|
||||
body.innerHTML = data.endpoints.map(e=>`<tr><td class="endpoint">${e}</td></tr>`).join('');
|
||||
}catch(e){ console.error(e); }
|
||||
// Map each endpoint object to a table row
|
||||
body.innerHTML = data.endpoints.map(e => {
|
||||
const statusClass = e.status === 'ok' ? 'status-ok' : 'status-error';
|
||||
const version = e.version || 'N/A';
|
||||
return `
|
||||
<tr>
|
||||
<td class="endpoint">${e.url}</td>
|
||||
<td class="status ${statusClass}">${e.status}</td>
|
||||
<td class="version">${version}</td>
|
||||
</tr>`;
|
||||
}).join('');
|
||||
}catch(e){
|
||||
console.error(e);
|
||||
const body = document.getElementById('endpoints-body');
|
||||
body.innerHTML = `<tr><td colspan="3" class="loading">Failed to load endpoints</td></tr>`;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadTags(){
|
||||
|
|
@ -118,4 +141,4 @@ window.addEventListener('load', ()=>{
|
|||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue