tfrere commited on
Commit
a402ff7
·
1 Parent(s): e3dae5e
client/src/components/StoryChoices.jsx CHANGED
@@ -31,6 +31,8 @@ export function StoryChoices({
31
  disabled = false,
32
  isLastStep = false,
33
  isGameOver = false,
 
 
34
  containerRef,
35
  }) {
36
  const navigate = useNavigate();
@@ -53,13 +55,13 @@ export function StoryChoices({
53
  <Typography
54
  variant="h3"
55
  sx={{
56
- color: "white",
57
  textAlign: "center",
58
  mb: 2,
59
  textTransform: "uppercase",
60
  }}
61
  >
62
- The End
63
  </Typography>
64
  <Button
65
  variant="outlined"
 
31
  disabled = false,
32
  isLastStep = false,
33
  isGameOver = false,
34
+ isDeath = false,
35
+ isVictory = false,
36
  containerRef,
37
  }) {
38
  const navigate = useNavigate();
 
55
  <Typography
56
  variant="h3"
57
  sx={{
58
+ color: isVictory ? "#4CAF50" : "#f44336",
59
  textAlign: "center",
60
  mb: 2,
61
  textTransform: "uppercase",
62
  }}
63
  >
64
+ {isVictory ? "VICTORY" : "DEFEAT"}
65
  </Typography>
66
  <Button
67
  variant="outlined"
client/src/layouts/ComicLayout.jsx CHANGED
@@ -125,6 +125,8 @@ function ComicPage({
125
  layout.segments[layout.segments.length - 1]?.isDeath ||
126
  layout.segments[layout.segments.length - 1]?.isVictory
127
  }
 
 
128
  />
129
  </Box>
130
  )}
 
125
  layout.segments[layout.segments.length - 1]?.isDeath ||
126
  layout.segments[layout.segments.length - 1]?.isVictory
127
  }
128
+ isDeath={layout.segments[layout.segments.length - 1]?.isDeath}
129
+ isVictory={layout.segments[layout.segments.length - 1]?.isVictory}
130
  />
131
  </Box>
132
  )}
server/core/constants.py CHANGED
@@ -6,6 +6,10 @@ class GameConfig:
6
  # Story constraints
7
  MIN_PANELS = 1
8
  MAX_PANELS = 4
 
 
 
 
9
 
10
  # Story progression
11
  STORY_BEAT_INTRO = 0
 
6
  # Story constraints
7
  MIN_PANELS = 1
8
  MAX_PANELS = 4
9
+
10
+ MIN_SEGMENTS_BEFORE_END = 2
11
+ MAX_SEGMENTS_BEFORE_END = 4
12
+ WINNING_STORY_CHANCE = 0.2
13
 
14
  # Story progression
15
  STORY_BEAT_INTRO = 0
server/core/generators/image_prompt_generator.py CHANGED
@@ -70,9 +70,6 @@ class ImagePromptGenerator(BaseGenerator):
70
  IMPORTANT RULES FOR IMAGE PROMPTS:
71
  - If you are prompting only one panel, it must be an important panel. Dont use only one panel often. It should be a key moment in the story.
72
  - If you are prompting more than one panel, they must be distinct and meaningful.
73
- - For death scenes: Focus on the dramatic and emotional impact, not the gore or violence
74
- - For victory scenes: Emphasize triumph, relief, and accomplishment
75
- - For victory and death scenes, you MUST use 1 panel only
76
 
77
  RESPONSE FORMAT:
78
  You must return a valid JSON object that matches this Pydantic schema:
@@ -102,6 +99,13 @@ Story text: {story_text}
102
 
103
  Generate panel descriptions that capture the key moments of this scene.
104
 
 
 
 
 
 
 
 
105
  Story state: {is_end}
106
  """
107
 
@@ -162,7 +166,7 @@ Story state: {is_end}
162
  metadata = f"[{time} - {location}] "
163
  return f"{self.artist_style} -- {metadata}{prompt}"
164
 
165
- async def generate(self, story_text: str, time: str, location: str, is_death: bool = False, is_victory: bool = False) -> ImagePromptResponse:
166
  """Generate image prompts based on story text.
167
 
168
  Args:
@@ -178,9 +182,10 @@ Story state: {is_end}
178
 
179
  is_end=""
180
  if is_death:
181
- is_end = "this is a death to represent"
182
  elif is_victory:
183
- is_end = "this is a victory to represent"
 
184
 
185
  response = await super().generate(
186
  story_text=story_text,
 
70
  IMPORTANT RULES FOR IMAGE PROMPTS:
71
  - If you are prompting only one panel, it must be an important panel. Dont use only one panel often. It should be a key moment in the story.
72
  - If you are prompting more than one panel, they must be distinct and meaningful.
 
 
 
73
 
74
  RESPONSE FORMAT:
75
  You must return a valid JSON object that matches this Pydantic schema:
 
99
 
100
  Generate panel descriptions that capture the key moments of this scene.
101
 
102
+
103
+
104
+ - For death scenes: Focus on the dramatic and emotional impact, not the gore or violence
105
+ - For victory scenes: Emphasize triumph, relief, and accomplishment
106
+ - For victory and death scenes, you MUST use 1 panel only
107
+
108
+
109
  Story state: {is_end}
110
  """
111
 
 
166
  metadata = f"[{time} - {location}] "
167
  return f"{self.artist_style} -- {metadata}{prompt}"
168
 
169
+ async def generate(self, story_text: str, time: str, location: str, is_death: bool = False, is_victory: bool = False, turn_before_end: int = 0, is_winning_story: bool = False) -> ImagePromptResponse:
170
  """Generate image prompts based on story text.
171
 
172
  Args:
 
182
 
183
  is_end=""
184
  if is_death:
185
+ is_end = "this is a death. just one panel, MANDATORY."
186
  elif is_victory:
187
+ is_end = "this is a victory. just one panel, MANDATORY."
188
+
189
 
190
  response = await super().generate(
191
  story_text=story_text,
server/core/generators/metadata_generator.py CHANGED
@@ -85,7 +85,7 @@ Current game state:
85
  except ValueError as e:
86
  raise ValueError(str(e))
87
 
88
- async def generate(self, story_text: str, current_time: str, current_location: str, story_beat: int, error_feedback: str = "") -> StoryMetadataResponse:
89
  """Surcharge de generate pour inclure le error_feedback par défaut."""
90
 
91
  is_end = "This should be close to the end of the story." if story_beat >= 5 else ""
@@ -95,5 +95,7 @@ Current game state:
95
  current_location=current_location,
96
  story_beat=story_beat,
97
  error_feedback=error_feedback,
98
- is_end=is_end
 
 
99
  )
 
85
  except ValueError as e:
86
  raise ValueError(str(e))
87
 
88
+ async def generate(self, story_text: str, current_time: str, current_location: str, story_beat: int, error_feedback: str = "", turn_before_end: int = 0, is_winning_story: bool = False) -> StoryMetadataResponse:
89
  """Surcharge de generate pour inclure le error_feedback par défaut."""
90
 
91
  is_end = "This should be close to the end of the story." if story_beat >= 5 else ""
 
95
  current_location=current_location,
96
  story_beat=story_beat,
97
  error_feedback=error_feedback,
98
+ is_end=is_end,
99
+ turn_before_end=turn_before_end,
100
+ is_winning_story=is_winning_story
101
  )
server/core/generators/story_segment_generator.py CHANGED
@@ -57,7 +57,7 @@ Rules: {FORMATTING_RULES}
57
 
58
  You must return a JSON object with the following format:
59
  {{
60
- "story_text": "Your story segment here (15 words)"
61
  }}
62
  """
63
 
@@ -72,10 +72,6 @@ Current game state :
72
  - Story beat: {story_beat}
73
 
74
  {is_end}
75
- You must return a JSON object with the following format:
76
- {{
77
- "story_text": "Your story segment here (15 words)"
78
- }}
79
  """
80
  return ChatPromptTemplate(
81
  messages=[
@@ -109,10 +105,11 @@ You must return a JSON object with the following format:
109
  "Example: {'story_text': 'Your story segment here'}"
110
  )
111
 
112
- async def generate(self, story_beat: int, current_time: str, current_location: str, previous_choice: str, story_history: str = "") -> StorySegmentResponse:
113
  """Generate the next story segment."""
114
 
115
- is_end = "Generate the END of the story. Reminder: 30 words." if story_beat >= random.randint(5, 10) else "Generate the next segment of the story. REMINDER: 15 words."
 
116
 
117
  return await super().generate(
118
  HERO_DESCRIPTION=HERO_DESCRIPTION,
 
57
 
58
  You must return a JSON object with the following format:
59
  {{
60
+ "story_text": "Your story segment here"
61
  }}
62
  """
63
 
 
72
  - Story beat: {story_beat}
73
 
74
  {is_end}
 
 
 
 
75
  """
76
  return ChatPromptTemplate(
77
  messages=[
 
105
  "Example: {'story_text': 'Your story segment here'}"
106
  )
107
 
108
+ async def generate(self, story_beat: int, current_time: str, current_location: str, previous_choice: str, story_history: str = "", turn_before_end: int = 0, is_winning_story: bool = False) -> StorySegmentResponse:
109
  """Generate the next story segment."""
110
 
111
+ what_to_represent =" this is a victory !" if is_winning_story else "this is a death !"
112
+ is_end = f"Generate the END of the story. {what_to_represent} in 30 words. THIS IS MANDATORY." if story_beat == turn_before_end else "Generate the next segment of the story in 15 words."
113
 
114
  return await super().generate(
115
  HERO_DESCRIPTION=HERO_DESCRIPTION,
server/core/story_generator.py CHANGED
@@ -6,6 +6,8 @@ from core.generators.story_segment_generator import StorySegmentGenerator
6
  from core.generators.image_prompt_generator import ImagePromptGenerator
7
  from core.generators.metadata_generator import MetadataGenerator
8
  from core.game_state import GameState
 
 
9
 
10
  class StoryGenerator:
11
  _instance = None
@@ -22,6 +24,8 @@ class StoryGenerator:
22
  print("Initializing StoryGenerator singleton")
23
  self.api_key = api_key
24
  self.model_name = model_name
 
 
25
  self.mistral_client = MistralClient(api_key=api_key, model_name=model_name)
26
  self.image_prompt_generator = None # Will be initialized with the first universe style
27
  self.metadata_generator = MetadataGenerator(self.mistral_client)
@@ -76,7 +80,9 @@ class StoryGenerator:
76
  current_time=game_state.current_time,
77
  current_location=game_state.current_location,
78
  previous_choice=previous_choice,
79
- story_history=story_history
 
 
80
  )
81
 
82
  # print(f"Generated story text: {segment_response}")
@@ -86,7 +92,9 @@ class StoryGenerator:
86
  story_text=segment_response.story_text,
87
  current_time=game_state.current_time,
88
  current_location=game_state.current_location,
89
- story_beat=game_state.story_beat
 
 
90
  )
91
  # print(f"Generated metadata_response: {metadata_response}")
92
 
@@ -96,7 +104,9 @@ class StoryGenerator:
96
  time=metadata_response.time,
97
  location=metadata_response.location,
98
  is_death=metadata_response.is_death,
99
- is_victory=metadata_response.is_victory
 
 
100
  )
101
  # print(f"Generated image prompts: {prompts_response}")
102
 
 
6
  from core.generators.image_prompt_generator import ImagePromptGenerator
7
  from core.generators.metadata_generator import MetadataGenerator
8
  from core.game_state import GameState
9
+ import random
10
+ from core.constants import GameConfig
11
 
12
  class StoryGenerator:
13
  _instance = None
 
24
  print("Initializing StoryGenerator singleton")
25
  self.api_key = api_key
26
  self.model_name = model_name
27
+ self.turn_before_end = random.randint(GameConfig.MIN_SEGMENTS_BEFORE_END, GameConfig.MAX_SEGMENTS_BEFORE_END)
28
+ self.is_winning_story = random.random() < GameConfig.WINNING_STORY_CHANCE
29
  self.mistral_client = MistralClient(api_key=api_key, model_name=model_name)
30
  self.image_prompt_generator = None # Will be initialized with the first universe style
31
  self.metadata_generator = MetadataGenerator(self.mistral_client)
 
80
  current_time=game_state.current_time,
81
  current_location=game_state.current_location,
82
  previous_choice=previous_choice,
83
+ story_history=story_history,
84
+ turn_before_end=self.turn_before_end,
85
+ is_winning_story=self.is_winning_story
86
  )
87
 
88
  # print(f"Generated story text: {segment_response}")
 
92
  story_text=segment_response.story_text,
93
  current_time=game_state.current_time,
94
  current_location=game_state.current_location,
95
+ story_beat=game_state.story_beat,
96
+ turn_before_end=self.turn_before_end,
97
+ is_winning_story=self.is_winning_story
98
  )
99
  # print(f"Generated metadata_response: {metadata_response}")
100
 
 
104
  time=metadata_response.time,
105
  location=metadata_response.location,
106
  is_death=metadata_response.is_death,
107
+ is_victory=metadata_response.is_victory,
108
+ turn_before_end=self.turn_before_end,
109
+ is_winning_story=self.is_winning_story
110
  )
111
  # print(f"Generated image prompts: {prompts_response}")
112