| from __future__ import annotations |
|
|
| import os |
| from typing import Any, Dict |
|
|
| from fastapi import FastAPI, Request |
| from fastapi.middleware.cors import CORSMiddleware |
| from fastapi.responses import HTMLResponse, JSONResponse |
|
|
| from context_parser import detect_intent, extract_game_context_fields, intent_to_help_mode, split_unity_message |
| from conversation_logic import ConversationEngine |
| from generator_engine import GeneratorEngine |
| from logging_store import LoggingStore |
| from models import ChatRequest, EventLogRequest, SessionFinalizeRequest, SessionStartRequest |
| from retrieval_engine import RetrievalEngine |
| from ui_html import HOME_HTML |
| from utils import clamp01, get_user_text |
|
|
| retriever = RetrievalEngine() |
| generator = GeneratorEngine() |
| engine = ConversationEngine(retriever=retriever, generator=generator) |
| store = LoggingStore() |
|
|
| app = FastAPI(title="GameAI") |
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_credentials=True, |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
|
|
| @app.get("/health") |
| def health() -> Dict[str, Any]: |
| return { |
| "ok": True, |
| "app": "GameAI", |
| "generator_available": generator.available(), |
| } |
|
|
|
|
| @app.get("/", response_class=HTMLResponse) |
| def home() -> str: |
| return HOME_HTML |
|
|
|
|
| @app.post("/chat") |
| async def chat(request: Request) -> JSONResponse: |
| try: |
| raw_body: Any = None |
| try: |
| raw_body = await request.json() |
| except Exception: |
| try: |
| raw_body = (await request.body()).decode("utf-8", errors="ignore") |
| except Exception: |
| raw_body = None |
|
|
| req_data: Dict[str, Any] = raw_body if isinstance(raw_body, dict) else {} |
| req = ChatRequest(**req_data) if isinstance(req_data, dict) else ChatRequest() |
|
|
| full_text = get_user_text(req, raw_body) |
| hidden_context, actual_user_message = split_unity_message(full_text) |
| game_fields = extract_game_context_fields(hidden_context) |
|
|
| question_text = (getattr(req, "question_text", None) or "").strip() or game_fields["question"] |
| options_text = getattr(req, "options_text", None) or game_fields["options"] |
| category = ( |
| req_data.get("category") |
| or getattr(req, "category", None) |
| or game_fields.get("category") |
| ) |
|
|
| tone = clamp01(req_data.get("tone", getattr(req, "tone", 0.5)), 0.5) |
| verbosity = clamp01(req_data.get("verbosity", getattr(req, "verbosity", 0.5)), 0.5) |
| transparency = clamp01(req_data.get("transparency", getattr(req, "transparency", 0.5)), 0.5) |
|
|
| incoming_help_mode = req_data.get("help_mode", getattr(req, "help_mode", None)) |
| explicit_intent = req_data.get("intent", getattr(req, "intent", None)) |
| intent = explicit_intent or detect_intent(actual_user_message or full_text, incoming_help_mode) |
| help_mode = intent_to_help_mode(intent) |
|
|
| result = engine.generate_response( |
| raw_user_text=actual_user_message or full_text, |
| tone=tone, |
| verbosity=verbosity, |
| transparency=transparency, |
| intent=intent, |
| help_mode=help_mode, |
| chat_history=getattr(req, "chat_history", None) or getattr(req, "history", None) or [], |
| question_text=question_text, |
| options_text=options_text, |
| category=category, |
| ) |
|
|
| return JSONResponse( |
| { |
| "reply": result.reply, |
| "meta": { |
| "domain": result.domain, |
| "solved": result.solved, |
| "help_mode": result.help_mode, |
| "answer_letter": result.answer_letter, |
| "answer_value": result.answer_value, |
| "topic": result.topic, |
| "used_retrieval": result.used_retrieval, |
| "used_generator": result.used_generator, |
| }, |
| } |
| ) |
| except Exception as e: |
| return JSONResponse( |
| { |
| "error": type(e).__name__, |
| "detail": str(e), |
| }, |
| status_code=500, |
| ) |
|
|
|
|
| @app.post("/log/session/start") |
| def log_session_start(payload: SessionStartRequest) -> Dict[str, Any]: |
| return store.start_session(payload.session_id, payload.user_id, payload.condition, payload.metadata) |
|
|
|
|
| @app.post("/log/event") |
| def log_event(payload: EventLogRequest) -> Dict[str, Any]: |
| return store.log_event(payload.session_id, payload.event_type, payload.payload, payload.timestamp) |
|
|
|
|
| @app.post("/log/session/finalize") |
| def log_session_finalize(payload: SessionFinalizeRequest) -> Dict[str, Any]: |
| return store.finalize_session(payload.session_id, payload.summary) |
|
|
|
|
| @app.get("/research/sessions") |
| def research_sessions() -> Dict[str, Any]: |
| return {"sessions": store.list_sessions()} |
|
|
|
|
| @app.get("/research/session/{session_id}") |
| def research_session(session_id: str) -> Dict[str, Any]: |
| return store.get_session(session_id) |