update
Browse files- client/src/components/StoryChoices.jsx +3 -3
- client/src/pages/Game.jsx +1 -0
- server/api/models.py +1 -1
- server/core/game_logic.py +1 -1
- server/server.py +21 -5
client/src/components/StoryChoices.jsx
CHANGED
|
@@ -59,12 +59,12 @@ export function StoryChoices({
|
|
| 59 |
>
|
| 60 |
The End
|
| 61 |
</Typography>
|
| 62 |
-
<Button
|
| 63 |
variant="outlined"
|
| 64 |
size="large"
|
| 65 |
onClick={() => {
|
| 66 |
// Simulate a button click on another button with the id "targetButton"
|
| 67 |
-
document.getElementById("
|
| 68 |
}}
|
| 69 |
sx={{
|
| 70 |
width: "100%",
|
|
@@ -83,7 +83,7 @@ export function StoryChoices({
|
|
| 83 |
}}
|
| 84 |
>
|
| 85 |
Save your story
|
| 86 |
-
</Button>
|
| 87 |
<Button
|
| 88 |
variant="outlined"
|
| 89 |
size="large"
|
|
|
|
| 59 |
>
|
| 60 |
The End
|
| 61 |
</Typography>
|
| 62 |
+
{/* <Button
|
| 63 |
variant="outlined"
|
| 64 |
size="large"
|
| 65 |
onClick={() => {
|
| 66 |
// Simulate a button click on another button with the id "targetButton"
|
| 67 |
+
document.getElementById("screenshot-button").click();
|
| 68 |
}}
|
| 69 |
sx={{
|
| 70 |
width: "100%",
|
|
|
|
| 83 |
}}
|
| 84 |
>
|
| 85 |
Save your story
|
| 86 |
+
</Button> */}
|
| 87 |
<Button
|
| 88 |
variant="outlined"
|
| 89 |
size="large"
|
client/src/pages/Game.jsx
CHANGED
|
@@ -385,6 +385,7 @@ export function Game() {
|
|
| 385 |
>
|
| 386 |
<Tooltip title="Save your story">
|
| 387 |
<IconButton
|
|
|
|
| 388 |
onClick={handleCaptureStory}
|
| 389 |
sx={{
|
| 390 |
color: "white",
|
|
|
|
| 385 |
>
|
| 386 |
<Tooltip title="Save your story">
|
| 387 |
<IconButton
|
| 388 |
+
id="screenshot-button"
|
| 389 |
onClick={handleCaptureStory}
|
| 390 |
sx={{
|
| 391 |
color: "white",
|
server/api/models.py
CHANGED
|
@@ -8,7 +8,7 @@ class Choice(BaseModel):
|
|
| 8 |
|
| 9 |
class StorySegmentBase(BaseModel):
|
| 10 |
"""Base model for story segments with common validation logic"""
|
| 11 |
-
story_text: str = Field(description="The story text. Never mention story beat or radiation level directly. ")
|
| 12 |
is_victory: bool = Field(description="Whether this segment ends in Sarah's victory", default=False)
|
| 13 |
is_death: bool = Field(description="Whether this segment ends in Sarah's death", default=False)
|
| 14 |
|
|
|
|
| 8 |
|
| 9 |
class StorySegmentBase(BaseModel):
|
| 10 |
"""Base model for story segments with common validation logic"""
|
| 11 |
+
story_text: str = Field(description="The story text. No more than 15 words THIS IS MANDATORY. Never mention story beat or radiation level directly. ")
|
| 12 |
is_victory: bool = Field(description="Whether this segment ends in Sarah's victory", default=False)
|
| 13 |
is_death: bool = Field(description="Whether this segment ends in Sarah's death", default=False)
|
| 14 |
|
server/core/game_logic.py
CHANGED
|
@@ -56,7 +56,7 @@ class GameState:
|
|
| 56 |
|
| 57 |
# Story output structure
|
| 58 |
class StoryLLMResponse(BaseModel):
|
| 59 |
-
story_text: str = Field(description="The next segment of the story. No more than
|
| 60 |
choices: List[str] = Field(description="One or two possible choices for the player. Each choice should be a clear path to folow in the story", min_items=1, max_items=2)
|
| 61 |
is_victory: bool = Field(description="Whether this segment ends in Sarah's victory", default=False)
|
| 62 |
is_death: bool = Field(description="Whether this segment ends in Sarah's death", default=False)
|
|
|
|
| 56 |
|
| 57 |
# Story output structure
|
| 58 |
class StoryLLMResponse(BaseModel):
|
| 59 |
+
story_text: str = Field(description="The next segment of the story. No more than 15 words THIS IS MANDATORY. Never mention story beat or radiation level directly. ")
|
| 60 |
choices: List[str] = Field(description="One or two possible choices for the player. Each choice should be a clear path to folow in the story", min_items=1, max_items=2)
|
| 61 |
is_victory: bool = Field(description="Whether this segment ends in Sarah's victory", default=False)
|
| 62 |
is_death: bool = Field(description="Whether this segment ends in Sarah's death", default=False)
|
server/server.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
from fastapi import FastAPI
|
| 2 |
from fastapi.middleware.cors import CORSMiddleware
|
| 3 |
from fastapi.staticfiles import StaticFiles
|
|
|
|
| 4 |
import os
|
| 5 |
from dotenv import load_dotenv
|
| 6 |
|
|
@@ -76,13 +77,28 @@ async def shutdown_event():
|
|
| 76 |
|
| 77 |
# Mount static files (this should be after all API routes)
|
| 78 |
if IS_DOCKER:
|
| 79 |
-
# En mode Docker (HF Space), on monte les fichiers statiques
|
| 80 |
-
app.mount("/
|
| 81 |
-
|
| 82 |
-
from fastapi.responses import FileResponse
|
| 83 |
@app.get("/{full_path:path}")
|
| 84 |
async def serve_spa(full_path: str):
|
| 85 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
else:
|
| 87 |
# En local, on monte simplement à la racine
|
| 88 |
app.mount("/", StaticFiles(directory=STATIC_FILES_DIR, html=True), name="static")
|
|
|
|
| 1 |
from fastapi import FastAPI
|
| 2 |
from fastapi.middleware.cors import CORSMiddleware
|
| 3 |
from fastapi.staticfiles import StaticFiles
|
| 4 |
+
from fastapi.responses import FileResponse
|
| 5 |
import os
|
| 6 |
from dotenv import load_dotenv
|
| 7 |
|
|
|
|
| 77 |
|
| 78 |
# Mount static files (this should be after all API routes)
|
| 79 |
if IS_DOCKER:
|
| 80 |
+
# En mode Docker (HF Space), on monte les fichiers statiques avec des types MIME spécifiques
|
| 81 |
+
app.mount("/assets", StaticFiles(directory=os.path.join(STATIC_FILES_DIR, "assets"), html=False), name="assets")
|
| 82 |
+
|
|
|
|
| 83 |
@app.get("/{full_path:path}")
|
| 84 |
async def serve_spa(full_path: str):
|
| 85 |
+
# Si le chemin pointe vers un fichier JavaScript
|
| 86 |
+
if full_path.endswith('.js'):
|
| 87 |
+
return FileResponse(
|
| 88 |
+
os.path.join(STATIC_FILES_DIR, full_path),
|
| 89 |
+
media_type='application/javascript'
|
| 90 |
+
)
|
| 91 |
+
# Si le chemin pointe vers un fichier CSS
|
| 92 |
+
elif full_path.endswith('.css'):
|
| 93 |
+
return FileResponse(
|
| 94 |
+
os.path.join(STATIC_FILES_DIR, full_path),
|
| 95 |
+
media_type='text/css'
|
| 96 |
+
)
|
| 97 |
+
# Pour tous les autres chemins, servir index.html
|
| 98 |
+
return FileResponse(
|
| 99 |
+
os.path.join(STATIC_FILES_DIR, "index.html"),
|
| 100 |
+
media_type='text/html'
|
| 101 |
+
)
|
| 102 |
else:
|
| 103 |
# En local, on monte simplement à la racine
|
| 104 |
app.mount("/", StaticFiles(directory=STATIC_FILES_DIR, html=True), name="static")
|