Spaces:
Runtime error
Runtime error
File size: 7,490 Bytes
a932f1e 57db5c0 5272060 4571f68 a932f1e 1a64ad7 5272060 1a64ad7 a932f1e 1a64ad7 a932f1e 1a64ad7 5272060 bb72572 5272060 bb72572 a932f1e 1a64ad7 a932f1e 1a64ad7 a932f1e 1a64ad7 a932f1e 1a64ad7 5272060 1a64ad7 5272060 a932f1e 1a64ad7 5272060 1a64ad7 5272060 a932f1e 1a64ad7 a932f1e 1a64ad7 5272060 1a64ad7 a932f1e 1a64ad7 a932f1e 5272060 1a64ad7 5272060 1a64ad7 5272060 1a64ad7 5272060 1a64ad7 5272060 1a64ad7 5272060 a932f1e 5272060 |
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 183 184 185 186 187 188 189 190 191 192 |
import gradio as gr
import uuid
import httpx
import os
# FastAPI imports
from fastapi import FastAPI, Request, Body
from fastapi.responses import RedirectResponse
from RockPaperScissor.routes import game_router
from RockPaperScissor.services.service_instance import game_service
# Import the LLM service and GPU function
from RockPaperScissor.services.LLM_service import LLMService, generate_text_with_gpu, llm_service_instance
# Import spaces after the GPU function is defined
try:
import spaces
from spaces import GPU
print("[APP] spaces.GPU imported successfully")
except ImportError:
print("[APP] spaces.GPU not available")
def GPU(f):
return f
# --- Game Constants and Types ---
from enum import Enum
class Move(Enum):
ROCK = "rock"
PAPER = "paper"
SCISSORS = "scissors"
class GameResult(Enum):
PLAYER_WIN = "player_win"
AI_WIN = "ai_win"
DRAW = "draw"
# --- Gradio Interface ---
class RockPaperScissorsUI:
def __init__(self, game_service):
self.game_service = game_service
self.session_id = None # Will be set from State
self.ai_models = list(self.game_service.ai_models.keys())
self.ai_descriptions = {
"random": "Random AI: Makes completely random moves.",
"adaptive_markov": "Adaptive Markov AI: Uses entropy-weighted Markov and frequency models to predict your next move."
}
self.last_move = None
async def reset_session(self, session_id: str):
# Use environment variable for base URL, fallback to localhost
base_url = os.getenv("HF_SPACE_URL", "http://localhost:7860")
async with httpx.AsyncClient() as client:
response = await client.post(
f"{base_url}/api/game/end",
json={"session_id": session_id}
)
print("[DEBUG] /api/game/end response:", response.text)
# Optionally, also clear the session in-memory (if needed)
await self.game_service.clear_session(session_id)
return {"status": "ok"}
def create_interface(self):
with gr.Blocks(theme=gr.themes.Soft(), title="Rock Paper Scissors ๐ฎ") as demo:
gr.Markdown("# ๐ชจ๐โ๏ธ Rock Paper Scissors")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### ๐ฎ Game Setup")
ai_dropdown = gr.Dropdown(
choices=self.ai_models,
value=self.ai_models[0],
label="Select AI Opponent"
)
ai_description = gr.Markdown(self.ai_descriptions[self.ai_models[0]])
with gr.Row():
rock_btn = gr.Button("๐ชจ Rock", variant="secondary", elem_classes=["move-btn"])
paper_btn = gr.Button("๐ Paper", variant="secondary", elem_classes=["move-btn"])
scissors_btn = gr.Button("โ๏ธ Scissors", variant="secondary", elem_classes=["move-btn"])
# Add End Game button
end_btn = gr.Button("End Game", variant="stop", elem_id="end-game-btn")
# Add Help button
help_btn = gr.Button("๐ก Get Help", variant="primary", elem_id="help-btn")
# Add a dedicated box for the help answer, initially empty
help_answer_box = gr.Markdown("", visible=True)
with gr.Column(scale=2):
gr.Markdown("### ๐ Game Statistics")
stats_display = gr.Markdown()
result_display = gr.Markdown("Make your move!")
end_result_display = gr.Markdown(visible=False)
status_display = gr.Markdown(visible=True)
ai_dropdown.change(
fn=self.update_ai_description,
inputs=[ai_dropdown],
outputs=[ai_description]
)
# Use a Gradio State to store the session ID
move_state = gr.State("")
session_id_state = gr.State("")
async def play_rock(ai_type, session_id):
if not session_id:
session_id = f"session_{uuid.uuid4()}"
self.session_id = session_id
stats, result = await self.play_round(ai_type, "rock")
return stats, result, session_id
async def play_paper(ai_type, session_id):
if not session_id:
session_id = f"session_{uuid.uuid4()}"
self.session_id = session_id
stats, result = await self.play_round(ai_type, "paper")
return stats, result, session_id
async def play_scissors(ai_type, session_id):
if not session_id:
session_id = f"session_{uuid.uuid4()}"
self.session_id = session_id
stats, result = await self.play_round(ai_type, "scissors")
return stats, result, session_id
# Add a hidden HTML block with JS to auto-save on tab close
gr.HTML("""
<script>
// Store session ID in localStorage whenever it changes
window.setRpsSessionId = function(session_id) {
if (session_id) {
localStorage.setItem('rps_session_id', session_id);
}
};
// On tab close, send session end to backend
window.onbeforeunload = function() {
let session_id = localStorage.getItem('rps_session_id');
if (session_id) {
navigator.sendBeacon("/game/end", JSON.stringify({session_id: session_id}));
}
};
</script>
""")
# Inject JS to click End Game button on tab close
gr.HTML("""
<script>
window.onbeforeunload = function() {
var btn = document.getElementById('end-game-btn');
if (btn) {
btn.click();
}
};
</script>
""")
# After each move, update localStorage with the session ID
def update_session_id_js(session_id):
return f"window.setRpsSessionId('{session_id}');"
rock_btn.click(
fn=play_rock,
inputs=[ai_dropdown, session_id_state],
outputs=[stats_display, result_display, session_id_state],
js=update_session_id_js
)
paper_btn.click(
fn=play_paper,
inputs=[ai_dropdown, session_id_state],
outputs=[stats_display, result_display, session_id_state],
js=update_session_id_js
)
scissors_btn.click(
fn=play_scissors,
inputs=[ai_dropdown, session_id_state],
outputs=[stats_display, result_display, session_id_state],
js=update_session_id_js
)
# End Game button logic
async def end_game(session_id):
if not session_id:
return "No session to end. Play a round first!"
result = await self.reset_session(session_id)
return f"End Game: {result['status']} - {result.get('message', '')}"
end_btn.click(
fn=end_game,
inputs=[session_id_state],
outputs=[end_result_display],
)
end_result_display.visible = True
# Help button logic |