Download app.py from proti0070/vps1122: direct link, hf CLI and curl.
- Browser
- Download file 7.69 kB
-
https://huggingface.co/spaces/proti0070/vps1122/resolve/main/app.py
- Command line
-
hf download hf://spaces/proti0070/vps1122/app.py
-
curl -L -o app.py https://huggingface.co/spaces/proti0070/vps1122/resolve/main/app.py
7.69 kB
| import asyncio | |
| import time | |
| import httpx | |
| import subprocess | |
| from datetime import datetime, timedelta | |
| from typing import Optional | |
| from fastapi import FastAPI, Request, HTTPException | |
| from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| import uvicorn | |
| app = FastAPI(title="Ollama Gateway + Monitor") | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| OLLAMA_BASE = "http://127.0.0.1:11434" | |
| # βββ Uptime tracking ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| start_time = time.time() | |
| health_log: list[dict] = [] | |
| MAX_LOG = 100 | |
| async def check_ollama_health() -> bool: | |
| try: | |
| async with httpx.AsyncClient(timeout=5) as client: | |
| r = await client.get(f"{OLLAMA_BASE}/api/tags") | |
| return r.status_code == 200 | |
| except Exception: | |
| return False | |
| async def health_loop(): | |
| while True: | |
| ok = await check_ollama_health() | |
| health_log.append({"ts": time.time(), "ok": ok}) | |
| if len(health_log) > MAX_LOG: | |
| health_log.pop(0) | |
| await asyncio.sleep(30) | |
| async def startup(): | |
| asyncio.create_task(health_loop()) | |
| # βββ Monitoring endpoints βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def health(): | |
| ollama_ok = await check_ollama_health() | |
| uptime_sec = int(time.time() - start_time) | |
| total = len(health_log) | |
| good = sum(1 for h in health_log if h["ok"]) | |
| return { | |
| "status": "ok", | |
| "uptime_seconds": uptime_sec, | |
| "uptime_human": str(timedelta(seconds=uptime_sec)), | |
| "ollama": "up" if ollama_ok else "down", | |
| "ollama_uptime_pct": round(good / total * 100, 1) if total else None, | |
| "checks_recorded": total, | |
| } | |
| async def monitor_dashboard(): | |
| ollama_ok = await check_ollama_health() | |
| uptime_sec = int(time.time() - start_time) | |
| total = len(health_log) | |
| good = sum(1 for h in health_log if h["ok"]) | |
| pct = round(good / total * 100, 1) if total else 0 | |
| dots = "" | |
| for h in health_log[-50:]: | |
| color = "#22c55e" if h["ok"] else "#ef4444" | |
| ts = datetime.fromtimestamp(h["ts"]).strftime("%H:%M:%S") | |
| dots += f'<span title="{ts}" style="display:inline-block;width:10px;height:20px;background:{color};margin:1px;border-radius:2px"></span>' | |
| ollama_color = "#22c55e" if ollama_ok else "#ef4444" | |
| ollama_label = "π’ UP" if ollama_ok else "π΄ DOWN" | |
| html = f"""<!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta http-equiv="refresh" content="30"> | |
| <title>Server Monitor</title> | |
| <style> | |
| * {{ box-sizing: border-box; margin: 0; padding: 0; }} | |
| body {{ background: #0f172a; color: #e2e8f0; font-family: 'Segoe UI', sans-serif; padding: 2rem; }} | |
| h1 {{ font-size: 1.6rem; margin-bottom: 1.5rem; color: #38bdf8; }} | |
| .grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem; margin-bottom: 2rem; }} | |
| .card {{ background: #1e293b; border-radius: 12px; padding: 1.2rem; border: 1px solid #334155; }} | |
| .card .label {{ font-size: .75rem; color: #94a3b8; text-transform: uppercase; letter-spacing: .05em; }} | |
| .card .value {{ font-size: 1.6rem; font-weight: 700; margin-top: .3rem; }} | |
| .section-title {{ color: #94a3b8; font-size: .8rem; text-transform: uppercase; letter-spacing: .1em; margin-bottom: .5rem; }} | |
| .sparkline {{ background: #1e293b; border-radius: 12px; padding: 1.2rem; border: 1px solid #334155; }} | |
| .links {{ margin-top: 1.5rem; display: flex; gap: 1rem; flex-wrap: wrap; }} | |
| a.btn {{ background: #0ea5e9; color: #fff; padding: .5rem 1.2rem; border-radius: 8px; text-decoration: none; font-size: .85rem; }} | |
| a.btn:hover {{ background: #38bdf8; }} | |
| </style> | |
| </head> | |
| <body> | |
| <h1>π₯οΈ Server Monitor</h1> | |
| <div class="grid"> | |
| <div class="card"> | |
| <div class="label">Server Uptime</div> | |
| <div class="value" style="color:#38bdf8">{str(timedelta(seconds=uptime_sec))}</div> | |
| </div> | |
| <div class="card"> | |
| <div class="label">Ollama Status</div> | |
| <div class="value" style="color:{ollama_color}">{ollama_label}</div> | |
| </div> | |
| <div class="card"> | |
| <div class="label">Ollama Uptime %</div> | |
| <div class="value" style="color:#a78bfa">{pct}%</div> | |
| </div> | |
| <div class="card"> | |
| <div class="label">Checks Logged</div> | |
| <div class="value">{total}</div> | |
| </div> | |
| </div> | |
| <div class="sparkline"> | |
| <div class="section-title">Last {min(total,50)} checks (green=up, red=down) β auto-refreshes every 30s</div> | |
| <div style="margin-top:.6rem;line-height:0">{dots if dots else '<span style="color:#64748b">No data yet β checks run every 30s</span>'}</div> | |
| </div> | |
| <div class="links"> | |
| <a class="btn" href="/monitor">β» Refresh</a> | |
| <a class="btn" href="/health">JSON Health</a> | |
| <a class="btn" href="/api/tags">Ollama Models</a> | |
| <a class="btn" href="/">Terminal</a> | |
| </div> | |
| </body> | |
| </html>""" | |
| return html | |
| # βββ Ollama proxy βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| async def _ensure_ollama(): | |
| ok = await check_ollama_health() | |
| if not ok: | |
| subprocess.Popen( | |
| ["ollama", "serve"], | |
| stdout=subprocess.DEVNULL, | |
| stderr=subprocess.DEVNULL, | |
| ) | |
| for _ in range(20): | |
| await asyncio.sleep(0.5) | |
| if await check_ollama_health(): | |
| return | |
| raise HTTPException(502, "Ollama failed to start") | |
| async def ollama_proxy(path: str, request: Request): | |
| await _ensure_ollama() | |
| url = f"{OLLAMA_BASE}/api/{path}" | |
| body = await request.body() | |
| headers = { | |
| k: v for k, v in request.headers.items() | |
| if k.lower() not in ("host", "content-length") | |
| } | |
| async def stream_response(): | |
| async with httpx.AsyncClient(timeout=None) as client: | |
| async with client.stream( | |
| request.method, url, | |
| content=body, | |
| headers=headers, | |
| params=dict(request.query_params), | |
| ) as r: | |
| async for chunk in r.aiter_bytes(): | |
| yield chunk | |
| try: | |
| import json as _json | |
| body_json = _json.loads(body) if body else {} | |
| except Exception: | |
| body_json = {} | |
| if body_json.get("stream", True) and request.method == "POST": | |
| return StreamingResponse(stream_response(), media_type="application/x-ndjson") | |
| async with httpx.AsyncClient(timeout=120) as client: | |
| r = await client.request( | |
| request.method, url, | |
| content=body, | |
| headers=headers, | |
| params=dict(request.query_params), | |
| ) | |
| return JSONResponse(status_code=r.status_code, content=r.json()) | |
| # βββ Run ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| if name == "main": | |
| uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=False) | |