Files
foodlinkk-command-center/cockpit/app/main.py
T
Aissa 5d60d33db1 Platform bundle: marketing publish, IT ops, packaging, agents mesh.
Volledige Foodlinkk Command Center uitbreiding met social automatisering,
reclamefolder filters, Proxmox monitoring en documentatie.
2026-06-09 00:41:27 +00:00

135 lines
3.5 KiB
Python

import asyncio
import json
from pathlib import Path
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from app.db import close_pool, fetch_all, init_pool
from app.routes import (
retail,
agents,
analytics,
documents,
api,
clients,
dashboard,
deals,
herman,
studio,
marketing,
monitor,
products,
reports,
suppliers,
voice,
settings,
browser,
hermes,
beurs,
packaging,
ops,
ops_api,
)
from app.routes.admin_api import admin_router, ai_router, herman_api, voice_api
from app.routes.settings_api import settings_router
from app.routes.agents_api import router as agents_api_router
from app.routes.marketing_api import router as marketing_api_router
BASE_DIR = Path(__file__).resolve().parent.parent
templates = Jinja2Templates(directory=str(BASE_DIR / "templates"))
app = FastAPI(title="Foodlinkk Command Center", version="2.5.0")
app.mount("/static", StaticFiles(directory=str(BASE_DIR / "static")), name="static")
for r in (
dashboard.router,
beurs.router,
agents.router,
marketing.router,
retail.router,
clients.router,
deals.router,
products.router,
suppliers.router,
monitor.router,
analytics.router,
documents.router,
reports.router,
voice.router,
settings.router,
browser.router,
herman.router,
studio.router,
hermes.router,
packaging.router,
ops.router,
api.router,
ops_api.router,
admin_router,
ai_router,
herman_api,
voice_api,
settings_router,
agents_api_router,
marketing_api_router,
):
app.include_router(r)
@app.on_event("startup")
def on_startup() -> None:
init_pool()
@app.on_event("shutdown")
def on_shutdown() -> None:
close_pool()
@app.websocket("/ws/agents")
async def ws_agents(websocket: WebSocket) -> None:
await websocket.accept()
last_payload: str | None = None
try:
while True:
try:
rows = fetch_all(
"""SELECT id, agent_name, event_type, title, body, status, created_at
FROM agent_events ORDER BY created_at DESC LIMIT 50"""
)
for row in rows:
if row.get("created_at") is not None:
row["created_at"] = row["created_at"].isoformat()
payload = json.dumps({"events": rows})
except Exception as exc:
payload = json.dumps({"error": str(exc), "events": []})
if payload != last_payload:
await websocket.send_text(payload)
last_payload = payload
await asyncio.sleep(3)
except WebSocketDisconnect:
return
@app.websocket("/ws/feed")
async def ws_feed(websocket: WebSocket) -> None:
await websocket.accept()
try:
while True:
snapshot = {"type": "heartbeat", "events": []}
try:
snapshot["events"] = fetch_all(
"SELECT agent_name, event_type, title, status, created_at FROM agent_events ORDER BY created_at DESC LIMIT 15"
)
for row in snapshot["events"]:
if row.get("created_at"):
row["created_at"] = row["created_at"].isoformat()
except Exception as exc:
snapshot["error"] = str(exc)
await websocket.send_text(json.dumps(snapshot))
await asyncio.sleep(5)
except WebSocketDisconnect:
return