update docker
Browse files- client/src/hooks/usePageSound.js +2 -3
- client/src/hooks/useWritingSound.js +3 -4
- client/src/pages/Game.jsx +13 -15
- server/core/constants.py +1 -1
- server/core/prompts/system.py +2 -7
- server/server.py +12 -1
client/src/hooks/usePageSound.js
CHANGED
|
@@ -6,7 +6,7 @@ const PAGE_SOUNDS = Array.from(
|
|
| 6 |
(_, i) => `/sounds/page-flip-${i + 1}.mp3`
|
| 7 |
);
|
| 8 |
|
| 9 |
-
export function usePageSound() {
|
| 10 |
const [soundsLoaded, setSoundsLoaded] = useState(false);
|
| 11 |
|
| 12 |
// Créer un tableau de hooks useSound pour chaque son
|
|
@@ -29,8 +29,7 @@ export function usePageSound() {
|
|
| 29 |
}, [sounds]);
|
| 30 |
|
| 31 |
const playRandomPageSound = () => {
|
| 32 |
-
if (!soundsLoaded) {
|
| 33 |
-
console.warn("Page sounds not loaded yet");
|
| 34 |
return;
|
| 35 |
}
|
| 36 |
|
|
|
|
| 6 |
(_, i) => `/sounds/page-flip-${i + 1}.mp3`
|
| 7 |
);
|
| 8 |
|
| 9 |
+
export function usePageSound(isSoundEnabled = true) {
|
| 10 |
const [soundsLoaded, setSoundsLoaded] = useState(false);
|
| 11 |
|
| 12 |
// Créer un tableau de hooks useSound pour chaque son
|
|
|
|
| 29 |
}, [sounds]);
|
| 30 |
|
| 31 |
const playRandomPageSound = () => {
|
| 32 |
+
if (!isSoundEnabled || !soundsLoaded) {
|
|
|
|
| 33 |
return;
|
| 34 |
}
|
| 35 |
|
client/src/hooks/useWritingSound.js
CHANGED
|
@@ -6,13 +6,13 @@ const PAGE_SOUNDS = Array.from(
|
|
| 6 |
(_, i) => `/sounds/drawing-${i + 1}.mp3`
|
| 7 |
);
|
| 8 |
|
| 9 |
-
export function useWritingSound() {
|
| 10 |
const [soundsLoaded, setSoundsLoaded] = useState(false);
|
| 11 |
|
| 12 |
// Créer un tableau de hooks useSound pour chaque son
|
| 13 |
const sounds = PAGE_SOUNDS.map((soundPath) => {
|
| 14 |
const [play, { sound }] = useSound(soundPath, {
|
| 15 |
-
volume:
|
| 16 |
interrupt: true,
|
| 17 |
});
|
| 18 |
return { play, sound };
|
|
@@ -29,8 +29,7 @@ export function useWritingSound() {
|
|
| 29 |
}, [sounds]);
|
| 30 |
|
| 31 |
const playRandomPageSound = () => {
|
| 32 |
-
if (!soundsLoaded) {
|
| 33 |
-
console.warn("Page sounds not loaded yet");
|
| 34 |
return;
|
| 35 |
}
|
| 36 |
|
|
|
|
| 6 |
(_, i) => `/sounds/drawing-${i + 1}.mp3`
|
| 7 |
);
|
| 8 |
|
| 9 |
+
export function useWritingSound(isSoundEnabled = true) {
|
| 10 |
const [soundsLoaded, setSoundsLoaded] = useState(false);
|
| 11 |
|
| 12 |
// Créer un tableau de hooks useSound pour chaque son
|
| 13 |
const sounds = PAGE_SOUNDS.map((soundPath) => {
|
| 14 |
const [play, { sound }] = useSound(soundPath, {
|
| 15 |
+
volume: 0.3,
|
| 16 |
interrupt: true,
|
| 17 |
});
|
| 18 |
return { play, sound };
|
|
|
|
| 29 |
}, [sounds]);
|
| 30 |
|
| 31 |
const playRandomPageSound = () => {
|
| 32 |
+
if (!isSoundEnabled || !soundsLoaded) {
|
|
|
|
| 33 |
return;
|
| 34 |
}
|
| 35 |
|
client/src/pages/Game.jsx
CHANGED
|
@@ -17,7 +17,7 @@ import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
|
| 17 |
import { getNextLayoutType, LAYOUTS } from "../layouts/config";
|
| 18 |
|
| 19 |
// Constants
|
| 20 |
-
const
|
| 21 |
|
| 22 |
// Function to convert text with ** to Chip elements
|
| 23 |
const formatTextWithBold = (text, isInPanel = false) => {
|
|
@@ -45,20 +45,20 @@ export function Game() {
|
|
| 45 |
const [isLoading, setIsLoading] = useState(false);
|
| 46 |
const [showChoices, setShowChoices] = useState(true);
|
| 47 |
const [error, setError] = useState(null);
|
| 48 |
-
const [
|
| 49 |
-
|
| 50 |
-
const stored = localStorage.getItem(NARRATION_ENABLED_KEY);
|
| 51 |
return stored === null ? true : stored === "true";
|
| 52 |
});
|
|
|
|
| 53 |
const { isNarratorSpeaking, playNarration, stopNarration } =
|
| 54 |
-
useNarrator(
|
| 55 |
-
const playPageSound = usePageSound();
|
| 56 |
-
const playWritingSound = useWritingSound();
|
| 57 |
|
| 58 |
-
// Sauvegarder l'état
|
| 59 |
useEffect(() => {
|
| 60 |
-
localStorage.setItem(
|
| 61 |
-
}, [
|
| 62 |
|
| 63 |
// Start the story on first render
|
| 64 |
useEffect(() => {
|
|
@@ -397,12 +397,10 @@ export function Game() {
|
|
| 397 |
</IconButton>
|
| 398 |
</Tooltip>
|
| 399 |
<Tooltip
|
| 400 |
-
title={
|
| 401 |
-
isNarrationEnabled ? "Disable narration" : "Enable narration"
|
| 402 |
-
}
|
| 403 |
>
|
| 404 |
<IconButton
|
| 405 |
-
onClick={() =>
|
| 406 |
sx={{
|
| 407 |
color: "white",
|
| 408 |
"&:hover": {
|
|
@@ -410,7 +408,7 @@ export function Game() {
|
|
| 410 |
},
|
| 411 |
}}
|
| 412 |
>
|
| 413 |
-
{
|
| 414 |
</IconButton>
|
| 415 |
</Tooltip>
|
| 416 |
</Box>
|
|
|
|
| 17 |
import { getNextLayoutType, LAYOUTS } from "../layouts/config";
|
| 18 |
|
| 19 |
// Constants
|
| 20 |
+
const SOUND_ENABLED_KEY = "sound_enabled";
|
| 21 |
|
| 22 |
// Function to convert text with ** to Chip elements
|
| 23 |
const formatTextWithBold = (text, isInPanel = false) => {
|
|
|
|
| 45 |
const [isLoading, setIsLoading] = useState(false);
|
| 46 |
const [showChoices, setShowChoices] = useState(true);
|
| 47 |
const [error, setError] = useState(null);
|
| 48 |
+
const [isSoundEnabled, setIsSoundEnabled] = useState(() => {
|
| 49 |
+
const stored = localStorage.getItem(SOUND_ENABLED_KEY);
|
|
|
|
| 50 |
return stored === null ? true : stored === "true";
|
| 51 |
});
|
| 52 |
+
|
| 53 |
const { isNarratorSpeaking, playNarration, stopNarration } =
|
| 54 |
+
useNarrator(isSoundEnabled);
|
| 55 |
+
const playPageSound = usePageSound(isSoundEnabled);
|
| 56 |
+
const playWritingSound = useWritingSound(isSoundEnabled);
|
| 57 |
|
| 58 |
+
// Sauvegarder l'état du son dans le localStorage
|
| 59 |
useEffect(() => {
|
| 60 |
+
localStorage.setItem(SOUND_ENABLED_KEY, isSoundEnabled);
|
| 61 |
+
}, [isSoundEnabled]);
|
| 62 |
|
| 63 |
// Start the story on first render
|
| 64 |
useEffect(() => {
|
|
|
|
| 397 |
</IconButton>
|
| 398 |
</Tooltip>
|
| 399 |
<Tooltip
|
| 400 |
+
title={isSoundEnabled ? "Couper le son" : "Activer le son"}
|
|
|
|
|
|
|
| 401 |
>
|
| 402 |
<IconButton
|
| 403 |
+
onClick={() => setIsSoundEnabled(!isSoundEnabled)}
|
| 404 |
sx={{
|
| 405 |
color: "white",
|
| 406 |
"&:hover": {
|
|
|
|
| 408 |
},
|
| 409 |
}}
|
| 410 |
>
|
| 411 |
+
{isSoundEnabled ? <VolumeUpIcon /> : <VolumeOffIcon />}
|
| 412 |
</IconButton>
|
| 413 |
</Tooltip>
|
| 414 |
</Box>
|
server/core/constants.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
class GameConfig:
|
| 2 |
# Game state constants
|
| 3 |
-
MAX_RADIATION =
|
| 4 |
STARTING_TIME = "18:00"
|
| 5 |
STARTING_LOCATION = "Outskirts of New Haven"
|
| 6 |
|
|
|
|
| 1 |
class GameConfig:
|
| 2 |
# Game state constants
|
| 3 |
+
MAX_RADIATION = 30
|
| 4 |
STARTING_TIME = "18:00"
|
| 5 |
STARTING_LOCATION = "Outskirts of New Haven"
|
| 6 |
|
server/core/prompts/system.py
CHANGED
|
@@ -8,11 +8,6 @@ Sarah is a young woman in her late 20s with short dark hair, wearing a worn leat
|
|
| 8 |
|
| 9 |
FORMATTING_RULES = """
|
| 10 |
FORMATTING_RULES ( MANDATORY )
|
| 11 |
-
- Do not include any specific time information like "TIME: 18:30" in the story text
|
| 12 |
-
- Do not include any specific location information like "LOCATION: the city" in the story text
|
| 13 |
-
- Do not include any specific radiation information like "RADIATION: 10*" in the story text
|
| 14 |
-
- NEVER write "(15 words)" or "(radiation 10)" or any similar suffix at the end of the story
|
| 15 |
-
- NEVER WRITE SOMTHING LIKE THIS : Radiation level: 1.
|
| 16 |
- The story must consist ONLY of sentences
|
| 17 |
- NEVER USE BOLD FOR ANYTHING
|
| 18 |
"""
|
|
@@ -46,8 +41,8 @@ Never repeat the same descriptions or situations. No more than 15 words.
|
|
| 46 |
STORY PROGRESSION:
|
| 47 |
- story_beat 0: Introduction setting up the horror atmosphere
|
| 48 |
- story_beat 1-2: Early exploration and discovery of immediate threats
|
| 49 |
-
- story_beat 3-
|
| 50 |
-
- story_beat
|
| 51 |
|
| 52 |
IMPORTANT RULES FOR RADIATION (MANDATORY):
|
| 53 |
- Most segments should have 1 radiation increase
|
|
|
|
| 8 |
|
| 9 |
FORMATTING_RULES = """
|
| 10 |
FORMATTING_RULES ( MANDATORY )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
- The story must consist ONLY of sentences
|
| 12 |
- NEVER USE BOLD FOR ANYTHING
|
| 13 |
"""
|
|
|
|
| 41 |
STORY PROGRESSION:
|
| 42 |
- story_beat 0: Introduction setting up the horror atmosphere
|
| 43 |
- story_beat 1-2: Early exploration and discovery of immediate threats
|
| 44 |
+
- story_beat 3-5: Complications and increasing danger
|
| 45 |
+
- story_beat 6+: Complicated situations leading to potential victory or death
|
| 46 |
|
| 47 |
IMPORTANT RULES FOR RADIATION (MANDATORY):
|
| 48 |
- Most segments should have 1 radiation increase
|
server/server.py
CHANGED
|
@@ -21,6 +21,7 @@ API_PORT = int(os.getenv("API_PORT", "8000"))
|
|
| 21 |
STATIC_FILES_DIR = os.getenv("STATIC_FILES_DIR", "../client/dist")
|
| 22 |
HF_API_KEY = os.getenv("HF_API_KEY")
|
| 23 |
ELEVEN_LABS_API_KEY = os.getenv("ELEVEN_LABS_API_KEY")
|
|
|
|
| 24 |
|
| 25 |
app = FastAPI(title="Echoes of Influence")
|
| 26 |
|
|
@@ -74,7 +75,17 @@ async def shutdown_event():
|
|
| 74 |
await flux_client.close()
|
| 75 |
|
| 76 |
# Mount static files (this should be after all API routes)
|
| 77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
if __name__ == "__main__":
|
| 80 |
import uvicorn
|
|
|
|
| 21 |
STATIC_FILES_DIR = os.getenv("STATIC_FILES_DIR", "../client/dist")
|
| 22 |
HF_API_KEY = os.getenv("HF_API_KEY")
|
| 23 |
ELEVEN_LABS_API_KEY = os.getenv("ELEVEN_LABS_API_KEY")
|
| 24 |
+
IS_DOCKER = os.getenv("IS_DOCKER", "false").lower() == "true"
|
| 25 |
|
| 26 |
app = FastAPI(title="Echoes of Influence")
|
| 27 |
|
|
|
|
| 75 |
await flux_client.close()
|
| 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 sur un chemin spécifique
|
| 80 |
+
app.mount("/static", StaticFiles(directory=STATIC_FILES_DIR), name="static")
|
| 81 |
+
# Et on ajoute une route pour servir l'index.html
|
| 82 |
+
from fastapi.responses import FileResponse
|
| 83 |
+
@app.get("/{full_path:path}")
|
| 84 |
+
async def serve_spa(full_path: str):
|
| 85 |
+
return FileResponse(os.path.join(STATIC_FILES_DIR, "index.html"))
|
| 86 |
+
else:
|
| 87 |
+
# En local, on monte simplement à la racine
|
| 88 |
+
app.mount("/", StaticFiles(directory=STATIC_FILES_DIR, html=True), name="static")
|
| 89 |
|
| 90 |
if __name__ == "__main__":
|
| 91 |
import uvicorn
|