Files
foodlinkk-command-center/cockpit/app/routes/analytics.py
T
Aissa 5e43b6b246 Ship Herman chat, Hermes KPI explorer, and intelligence analytics.
Adds floating Herman assistant with voice, Hermes technical KPI dashboard with file explorer, and a wins/kansen analytics pulse with Hermes findings hooks. Includes optional local HTTPS via Caddy for mic permissions (public certs only).
2026-08-01 17:50:45 +00:00

65 lines
2.0 KiB
Python

from pathlib import Path
from typing import Any, Optional
from fastapi import APIRouter, Body, Query, Request
from fastapi.responses import JSONResponse
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel, Field
from app.services.analytics_data import add_finding, collect_analytics, list_hermes_findings
router = APIRouter(prefix="/analytics", tags=["analytics"])
BASE_DIR = Path(__file__).resolve().parent.parent.parent
templates = Jinja2Templates(directory=str(BASE_DIR / "templates"))
class FindingIn(BaseModel):
kind: str = Field(default="insight", description="win|opportunity|attention|insight")
title: str
body: str = ""
score: float | None = None
source: str = "hermes"
href: str | None = None
meta: dict[str, Any] | None = None
@router.get("")
async def analytics_page(request: Request):
initial = collect_analytics({})
return templates.TemplateResponse(
"analytics.html",
{"request": request, "page_title": "Analytics", "initial_data": initial},
)
@router.get("/api/data")
async def analytics_api(
chain: Optional[str] = None,
province: Optional[str] = None,
stage: Optional[str] = None,
agent: Optional[str] = None,
days: int = Query(90, ge=7, le=365),
):
filters = {"chain": chain, "province": province, "stage": stage, "agent": agent, "days": days}
return JSONResponse(collect_analytics(filters))
@router.get("/api/findings")
async def analytics_findings(limit: int = Query(20, ge=1, le=100)):
return {"items": list_hermes_findings(limit)}
@router.post("/api/findings")
async def analytics_findings_create(payload: FindingIn = Body(...)):
"""Hermes (of admin) kan bevindingen pushen naar het intelligence dashboard."""
row = add_finding(
kind=payload.kind,
title=payload.title,
body=payload.body,
score=payload.score,
source=payload.source,
href=payload.href,
meta=payload.meta,
)
return {"ok": True, "finding": row}