File size: 3,771 Bytes
1d0b04b
e6970ed
 
 
1984ea6
 
1d0b04b
2df7867
1d0b04b
 
e6970ed
 
 
1d0b04b
 
e6970ed
a2d1173
1d0b04b
 
 
7e810ce
1984ea6
 
e6970ed
7e810ce
 
1984ea6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f316f5a
e6970ed
f316f5a
 
1c2dd4b
e6970ed
 
 
1984ea6
f316f5a
2df7867
f316f5a
 
 
 
23040f5
f316f5a
 
 
 
 
1d0b04b
 
1984ea6
f316f5a
 
 
 
11853b1
f316f5a
11853b1
f316f5a
 
 
1d0b04b
 
1984ea6
f316f5a
 
 
11853b1
f316f5a
11853b1
f316f5a
11853b1
 
 
 
 
 
f316f5a
1d0b04b
 
1984ea6
 
 
 
 
 
 
 
 
 
 
 
e6970ed
 
1984ea6
 
 
 
 
e6970ed
 
 
1d0b04b
e6970ed
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
"""
Retro Alpha - 90s Indian Stock Market Survival Game
Gradio app for HuggingFace Spaces (Build Small Hackathon).

Serves a self-contained HTML page at root via an ASGI wrapper.
Gradio handles the API routes; root GET bypasses Gradio entirely.
"""
import os
from pathlib import Path

import gradio as gr
from fastapi import Request
from fastapi.responses import JSONResponse, HTMLResponse

import agents
import mentor as _mentor

ROOT = Path(__file__).resolve().parent
STATIC_DIR = ROOT / "static"


def _read(p: str) -> str:
    with open(STATIC_DIR / p, "r", encoding="utf-8") as f:
        return f.read()


_CSS = _read("style.css")
_HTML_BODY = _read("index.html")
_ENGINE_JS = _read("engine.js")
_EVENTS_JS = _read("events.js")
_APP_JS = _read("app.js")

PAGE = f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Retro Alpha - 90s Market Terminal</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=VT323&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet" />
<style>
{_CSS}
</style>
</head>
<body>
{_HTML_BODY}
<script>
{_EVENTS_JS}
</script>
<script>
{_ENGINE_JS}
</script>
<script>
{_APP_JS}
</script>
</body>
</html>"""


with gr.Blocks(title="Retro Alpha") as demo:
    pass

api = demo.app


@api.get("/game-api/health")
def health() -> JSONResponse:
    return JSONResponse({
        "status": "ok",
        "llm": agents.llm_status(),
        "llm_error": agents.llm_error(),
    })


@api.post("/game-api/chat")
async def chat(request: Request) -> JSONResponse:
    data = await request.json()
    user_message = str(data.get("message", "")).strip()
    if not user_message:
        return JSONResponse({"error": "Empty message"}, status_code=400)
    snapshot = data.get("snapshot") or {}
    try:
        reply = agents.chat_reply(user_message, snapshot)
    except Exception as e:
        print(f"Chat error: {e}")
        reply = "I'm having trouble thinking right now. Try again in a moment."
    return JSONResponse({"reply": reply})


@api.post("/game-api/insight")
async def insight(request: Request) -> JSONResponse:
    data = await request.json()
    event = data.get("event") or {}
    snapshot = data.get("snapshot") or {}
    try:
        text = agents.generate_insight(event, snapshot)
    except Exception as e:
        print(f"Insight error: {e}")
        text = ""
    return JSONResponse({"insight": text})


@api.post("/game-api/mentor")
async def mentor_review(request: Request) -> JSONResponse:
    data = await request.json()
    summary = data.get("summary") or {}
    try:
        review = _mentor.generate_review(summary)
    except Exception as e:
        print(f"Mentor error: {e}")
        review = {
            "roast": "Markets are noisy; so is my parser.",
            "sharpe_ratio": 0.0,
            "lesson": "Sharpe ratio measures risk-adjusted return.",
            "suggestion": "Diversify across asset classes.",
        }
    return JSONResponse({"review": review})


# ASGI wrapper: intercept root GET before Gradio's router
_gradio_app = api


async def app(scope, receive, send):
    if scope["type"] == "http" and scope["method"] == "GET" and scope["path"] == "/":
        response = HTMLResponse(PAGE)
        await response(scope, receive, send)
        return
    await _gradio_app(scope, receive, send)


def launch():
    agents.start_background_load()
    import uvicorn
    uvicorn.run(
        app,
        host="0.0.0.0",
        port=int(os.environ.get("PORT", "7860")),
    )


if __name__ == "__main__":
    launch()