people_counter/main.py
2025-08-02 03:25:54 +02:00

75 lines
2.1 KiB
Python

from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, StreamingResponse, PlainTextResponse
from tracker import start_all_streams, get_metrics, get_latest_frame, STREAMS
from prometheus_client import generate_latest, CONTENT_TYPE_LATEST
import time
app = FastAPI()
@app.on_event("startup")
def startup_event():
start_all_streams()
@app.get("/", response_class=HTMLResponse)
def index(request: Request):
current_stream = request.query_params.get("stream")
stream_options = "\n".join(
[
f'<option value="{stream_id}" {"selected" if stream_id == current_stream else ""}>{stream_id}</option>'
for stream_id in STREAMS.keys()
]
)
return f"""
<html>
<body>
<h1>People Counter Dashboard</h1>
<form action="/" method="get">
<label>Select Stream:</label>
<select name="stream" onchange="this.form.submit()">
{stream_options}
</select>
</form>
<img src="/video_feed/{current_stream}" />
<p><a href="/metrics">Prometheus Metrics</a></p>
</body>
</html>
"""
@app.get("/metrics")
def metrics():
return PlainTextResponse(
generate_latest(get_metrics()), media_type=CONTENT_TYPE_LATEST
)
@app.get("/video_feed/{stream_id}")
def video_feed(stream_id: str):
boundary = "--boundarydonotcross"
def generate():
last_version = time.time()
while True:
frame, version = get_latest_frame(stream_id)
if frame is not None and version > last_version:
last_version = version
print(f"yielding new frame @{version}")
yield (
boundary.encode()
+ b"\r\n"
+ b"Content-Type: image/jpeg\r\n\r\n"
+ frame
+ b"\r\n"
)
else:
# wait for new frame
time.sleep(0.05)
return StreamingResponse(
generate(), media_type=f"multipart/x-mixed-replace; boundary={boundary}"
)