Spaces:
Running
Running
File size: 5,052 Bytes
2ae624c 1f49ca6 2ae624c 70a705d 2ae624c 267d20c 2ae624c 1f49ca6 2ae624c 1f49ca6 2ae624c 45a5f35 2ae624c 70a705d 2ae624c 2ea6ddc 2ae624c 1f49ca6 267d20c 2ae624c 1f49ca6 2ae624c 1f49ca6 2ae624c 1f49ca6 267d20c 2ae624c 2ea6ddc 2ae624c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | from __future__ import annotations
import os
import re
from typing import Any, Dict, Tuple
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse, JSONResponse
from context_parser import detect_help_mode
from conversation_logic import generate_response
from models import ChatRequest
from ui_html import HOME_HTML
from utils import clamp01, get_user_text
from retrieval_engine import RetrievalEngine
retriever = RetrievalEngine()
app = FastAPI(title="GMAT Solver v3", version="3.1.0")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
def split_unity_message(full_text: str) -> Tuple[str, str]:
"""
Splits the Unity payload into:
- hidden_context
- actual_user_message
Expected Unity format:
<hidden context>
USER_MESSAGE:
<user text>
Falls back safely if marker is missing.
"""
if not full_text:
return "", ""
marker = "USER_MESSAGE:"
idx = full_text.find(marker)
if idx == -1:
return "", full_text.strip()
hidden_context = full_text[:idx].strip()
actual_user_message = full_text[idx + len(marker):].strip()
return hidden_context, actual_user_message
def extract_game_context_fields(hidden_context: str) -> Dict[str, str]:
"""
Pull simple fields out of the hidden Unity context so downstream logic
can use the real question/options instead of the whole raw blob.
"""
fields = {
"category": "",
"difficulty": "",
"question": "",
"options": "",
}
if not hidden_context:
return fields
category_match = re.search(r"Category:\s*(.+)", hidden_context)
difficulty_match = re.search(r"Difficulty:\s*(.+)", hidden_context)
question_match = re.search(r"Question:\s*(.+)", hidden_context, re.DOTALL)
options_match = re.search(
r"Options:\s*(.+?)(?:\nPlayer balance:|\nLast outcome:|$)",
hidden_context,
re.DOTALL,
)
if category_match:
fields["category"] = category_match.group(1).strip()
if difficulty_match:
fields["difficulty"] = difficulty_match.group(1).strip()
if question_match:
question_text = question_match.group(1).strip()
question_text = question_text.split("\nOptions:")[0].strip()
question_text = question_text.split("\nPlayer balance:")[0].strip()
question_text = question_text.split("\nLast outcome:")[0].strip()
fields["question"] = question_text
if options_match:
fields["options"] = options_match.group(1).strip()
return fields
@app.get("/health")
def health() -> Dict[str, Any]:
return {"ok": True, "app": "GMAT Solver v3 LIVE CHECK 777"}
@app.get("/", response_class=HTMLResponse)
def home() -> str:
return HOME_HTML
@app.post("/chat")
async def chat(request: Request) -> JSONResponse:
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 {}
try:
req = ChatRequest(**req_data)
except Exception:
req = 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)
# NEW
context = retriever.search(actual_user_message)
context_text = "\n".join(context)
tone = clamp01(req_data.get("tone", req.tone), 0.5)
verbosity = clamp01(req_data.get("verbosity", req.verbosity), 0.5)
transparency = clamp01(req_data.get("transparency", req.transparency), 0.5)
help_mode = detect_help_mode(
actual_user_message,
req_data.get("help_mode", req.help_mode),
)
result = generate_response(
raw_user_text=actual_user_message,
tone=tone,
verbosity=verbosity,
transparency=transparency,
help_mode=help_mode,
hidden_context=hidden_context,
chat_history=req_data.get("chat_history", []),
question_text=game_fields["question"],
options_text=game_fields["options"],
question_category=game_fields["category"],
question_difficulty=game_fields["difficulty"],
retrieval_context=context_text,
)
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,
},
}
)
if __name__ == "__main__":
import uvicorn
port = int(os.getenv("PORT", "7860"))
uvicorn.run(app, host="0.0.0.0", port=port) |