137 lines
3.6 KiB
Python
137 lines
3.6 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
|
|
from app.routes.projects_api import router as projects_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,
|
|
projects_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
|