This commit is contained in:
h z
2026-02-12 15:45:48 +00:00
commit 343a4b8d67
34 changed files with 2321 additions and 0 deletions

158
api/debates.py Normal file
View File

@@ -0,0 +1,158 @@
from fastapi import APIRouter, Depends, HTTPException
from middleware.auth import require_auth
from sse_starlette.sse import EventSourceResponse
from typing import Dict, Any
import asyncio
import json
from orchestrator.debate_orchestrator import DebateOrchestrator
from models.debate import DebateRequest
from storage.session_manager import SessionManager
from db_models import get_db
router = APIRouter(tags=["debates"])
@router.post("/debate/create", dependencies=[Depends(require_auth)])
async def create_debate(debate_request: DebateRequest, db=Depends(get_db)) -> Dict[str, Any]:
"""
Create a new debate session with specified parameters
"""
try:
orchestrator = DebateOrchestrator(db)
session_id = await orchestrator.create_session(debate_request)
return {
"session_id": session_id,
"status": "created",
"message": f"Debate session {session_id} created successfully"
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/debate/{session_id}")
async def get_debate(session_id: str, db=Depends(get_db)) -> Dict[str, Any]:
"""
Get the current state of a debate session
"""
try:
orchestrator = DebateOrchestrator(db)
session = await orchestrator.get_session_status(session_id)
if not session:
raise HTTPException(status_code=404, detail=f"Debate session {session_id} not found")
return session.dict()
except HTTPException:
raise
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post("/debate/{session_id}/start", dependencies=[Depends(require_auth)])
async def start_debate(session_id: str, db=Depends(get_db)) -> Dict[str, Any]:
"""
Start a debate session and stream the results
"""
try:
orchestrator = DebateOrchestrator(db)
session = await orchestrator.run_debate(session_id)
return {
"session_id": session_id,
"status": session.status,
"message": f"Debate session {session_id} completed"
}
except Exception as e:
import traceback
traceback.print_exc()
raise HTTPException(status_code=500, detail=str(e))
@router.delete("/debate/{session_id}", dependencies=[Depends(require_auth)])
async def end_debate(session_id: str, db=Depends(get_db)) -> Dict[str, Any]:
"""
End a debate session prematurely
"""
try:
orchestrator = DebateOrchestrator(db)
await orchestrator.terminate_session(session_id)
return {"session_id": session_id, "status": "terminated"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.get("/debate/{session_id}/stream")
async def stream_debate(session_id: str, db=Depends(get_db)) -> EventSourceResponse:
"""
Stream debate updates in real-time using Server-Sent Events
"""
async def event_generator():
session_manager = SessionManager()
# Check if the session exists
session = await session_manager.get_session(db, session_id)
if not session:
yield {"event": "error", "data": json.dumps({"error": f"Session {session_id} not found"})}
return
# Yield initial state
yield {"event": "update", "data": json.dumps({
"session_id": session_id,
"status": session.status,
"rounds": [round.dict() for round in session.rounds],
"evidence_library": [e.dict() for e in session.evidence_library],
"message": "Debate session initialized"
}, default=str)}
last_round_count = len(session.rounds)
# Poll until debate completes or times out (max 5 min)
for _ in range(150): # 150 × 2s = 300s timeout
await asyncio.sleep(2)
# Reset transaction so we see commits from the run_debate request
db.commit()
updated_session = await session_manager.get_session(db, session_id)
if not updated_session:
break
# Only yield update when rounds actually changed
if len(updated_session.rounds) != last_round_count or updated_session.status != session.status:
last_round_count = len(updated_session.rounds)
session = updated_session
yield {"event": "update", "data": json.dumps({
"session_id": session_id,
"status": updated_session.status,
"rounds": [round.dict() for round in updated_session.rounds],
"evidence_library": [e.dict() for e in updated_session.evidence_library],
"current_round": len(updated_session.rounds)
}, default=str)}
if updated_session.status in ("completed", "terminated"):
yield {"event": "complete", "data": json.dumps({
"session_id": session_id,
"status": updated_session.status,
"summary": updated_session.summary,
"rounds": [round.dict() for round in updated_session.rounds],
"evidence_library": [e.dict() for e in updated_session.evidence_library]
}, default=str)}
break
return EventSourceResponse(event_generator())
@router.get("/sessions")
async def list_sessions(db=Depends(get_db)) -> Dict[str, Any]:
"""
List all debate sessions
"""
try:
session_manager = SessionManager()
sessions = await session_manager.list_sessions(db)
return {"sessions": sessions}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))