Initial commit — GeoOptions Intelligence Cockpit v2.0
Stack: FastAPI + React/TypeScript + SQLite + GPT-4o Features: Radar géopolitique, Marchés, Régime Macro, Journal de Bord MTM, Rapport IA, Super Contexte (base de raisonnement évolutive), Boucle feedback IA. Deploy: Docker + docker-compose + nginx pour openfin.open-squared.tech Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
74
backend/routers/cycle.py
Normal file
74
backend/routers/cycle.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
from services.database import get_cycle_runs, get_cycle_run, set_config, get_config
|
||||
from services.auto_cycle import get_status, trigger_manual, restart_scheduler
|
||||
|
||||
router = APIRouter(prefix="/api/cycle", tags=["cycle"])
|
||||
|
||||
|
||||
@router.get("/status")
|
||||
def cycle_status():
|
||||
"""Current scheduler state + last cycle summary."""
|
||||
return get_status()
|
||||
|
||||
|
||||
@router.get("/history")
|
||||
def cycle_history(limit: int = 20):
|
||||
"""List recent cycle runs."""
|
||||
runs = get_cycle_runs(limit=limit)
|
||||
# Parse commentary JSON for frontend
|
||||
import json
|
||||
for r in runs:
|
||||
if r.get("commentary"):
|
||||
try:
|
||||
r["commentary_parsed"] = json.loads(r["commentary"])
|
||||
except Exception:
|
||||
r["commentary_parsed"] = {"commentary": r["commentary"]}
|
||||
return {"runs": runs, "count": len(runs)}
|
||||
|
||||
|
||||
@router.post("/trigger")
|
||||
def trigger_cycle():
|
||||
"""Manually trigger one cycle immediately (non-blocking)."""
|
||||
key = get_config("openai_api_key") or ""
|
||||
if not key:
|
||||
raise HTTPException(400, "Clé OpenAI non configurée")
|
||||
trigger_manual()
|
||||
return {"triggered": True, "message": "Cycle lancé en arrière-plan"}
|
||||
|
||||
|
||||
class CycleConfigRequest(BaseModel):
|
||||
enabled: Optional[bool] = None
|
||||
interval_hours: Optional[float] = None
|
||||
similarity_threshold: Optional[float] = None
|
||||
min_ev_threshold: Optional[float] = None
|
||||
min_score_threshold: Optional[int] = None
|
||||
|
||||
|
||||
@router.post("/config")
|
||||
def update_cycle_config(req: CycleConfigRequest):
|
||||
"""Update auto-cycle + filter configuration and restart scheduler."""
|
||||
if req.enabled is not None:
|
||||
set_config("auto_cycle_enabled", "true" if req.enabled else "false")
|
||||
if req.interval_hours is not None:
|
||||
if not (0.5 <= req.interval_hours <= 24):
|
||||
raise HTTPException(400, "interval_hours must be between 0.5 and 24")
|
||||
set_config("auto_cycle_hours", str(req.interval_hours))
|
||||
if req.similarity_threshold is not None:
|
||||
if not (0.0 <= req.similarity_threshold <= 1.0):
|
||||
raise HTTPException(400, "similarity_threshold must be between 0 and 1")
|
||||
set_config("auto_cycle_similarity_threshold", str(req.similarity_threshold))
|
||||
if req.min_ev_threshold is not None:
|
||||
if not (0.0 <= req.min_ev_threshold <= 1.0):
|
||||
raise HTTPException(400, "min_ev_threshold must be between 0 and 1")
|
||||
set_config("min_ev_threshold", str(req.min_ev_threshold))
|
||||
if req.min_score_threshold is not None:
|
||||
if not (0 <= req.min_score_threshold <= 100):
|
||||
raise HTTPException(400, "min_score_threshold must be between 0 and 100")
|
||||
set_config("min_score_threshold", str(req.min_score_threshold))
|
||||
|
||||
# Restart scheduler to pick up changes
|
||||
restart_scheduler()
|
||||
|
||||
return get_status()
|
||||
Reference in New Issue
Block a user