awacke1 commited on
Commit
8e5d581
·
verified ·
1 Parent(s): 51269cc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +166 -66
app.py CHANGED
@@ -35,20 +35,13 @@ sentence_templates = {
35
  # Pure Python function to augment word lists from user input
36
  def augment_word_lists(user_input):
37
  augmented_lists = {key: list(set(val)) for key, val in default_word_lists.items()}
38
-
39
- # Split input into words
40
  words = user_input.lower().split()
41
-
42
- # Simple heuristic lists for categorization
43
  location_keywords = ["town", "village", "city", "forest", "mountain", "place", "land"]
44
  action_keywords = ["walk", "run", "dance", "pedal", "explore", "move", "jump"]
45
  emotion_keywords = ["joy", "pain", "smile", "storm", "fear", "love", "anger"]
46
-
47
- # Extract dialogues with regex
48
  dialogues = re.findall(r'"[^"]*"', user_input)
49
  augmented_lists["Dialogue"].extend(dialogues)
50
 
51
- # Categorize words
52
  for word in words:
53
  if any(keyword in word for keyword in location_keywords):
54
  augmented_lists["Location"].append(word)
@@ -56,13 +49,11 @@ def augment_word_lists(user_input):
56
  augmented_lists["Actions"].append(word)
57
  elif any(keyword in word for keyword in emotion_keywords):
58
  augmented_lists["Emotions"].append(word)
59
- elif "?" in word or "what" in word or "why" in word: # Simple thought detection
60
  augmented_lists["Thoughts"].append(word)
61
 
62
- # Remove duplicates
63
  for key in augmented_lists:
64
  augmented_lists[key] = list(set(augmented_lists[key]))
65
-
66
  return augmented_lists
67
 
68
  # Create a 52-card deck
@@ -86,20 +77,163 @@ def assign_card_to_class(card_index):
86
  else:
87
  return "Dialogue"
88
 
89
- # Generate card image
90
- def generate_card_image(suit, rank, story_class, word, property):
91
- img = Image.new("RGB", (200, 300), color="white")
92
- draw = ImageDraw.Draw(img)
93
- font = ImageFont.load_default()
94
-
95
- draw.text((10, 10), f"{rank} of {suit}", fill="black", font=font)
96
- draw.text((10, 50), f"Class: {story_class}", fill="black", font=font)
97
- draw.text((10, 90), f"Word: {word}", fill="black", font=font)
98
- draw.text((10, 130), f"Property: {property}", fill="black", font=font)
99
 
100
- buffer = io.BytesIO()
101
- img.save(buffer, format="PNG")
102
- return buffer.getvalue()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
  # Generate story sentence
105
  def generate_story_sentence(story_class, word, property):
@@ -108,14 +242,14 @@ def generate_story_sentence(story_class, word, property):
108
  # Generate song lyrics
109
  def generate_song_lyrics(story_text):
110
  words = story_text.split()
111
- key_elements = [word for word in words if len(word) > 3][:12] # Simple filter for ~60 seconds
112
  lyrics = "\n".join([f"{key_elements[i]} {key_elements[i+1]}" for i in range(0, len(key_elements)-1, 2)])
113
  return lyrics
114
 
115
  # Main app
116
  def main():
117
- st.set_page_config(page_title="StoryForge: The Game", page_icon="🎴", layout="wide")
118
- st.title("🎴 StoryForge: A Storytelling Adventure 🎴")
119
 
120
  # User input
121
  st.markdown("## 📝 Your Story Seed")
@@ -140,8 +274,8 @@ def main():
140
  st.session_state.drawn_cards = 0
141
  st.success("Game started! Draw your first card.")
142
 
143
- # Draw card and story display
144
- col1, col2 = st.columns([1, 3])
145
  with col1:
146
  if st.button("Draw Card") and st.session_state.drawn_cards < 52:
147
  card_index = st.session_state.drawn_cards
@@ -150,9 +284,11 @@ def main():
150
  word = random.choice(st.session_state.augmented_lists[story_class])
151
  property = suit_properties[suit]
152
 
153
- card_image = generate_card_image(suit, rank, story_class, word, property)
154
- st.image(card_image, caption=f"Card {card_index + 1}")
 
155
 
 
156
  sentence = generate_story_sentence(story_class, word, property)
157
  st.session_state.story.append(sentence)
158
  st.session_state.drawn_cards += 1
@@ -173,42 +309,6 @@ def main():
173
  audio_file = "story_song.mp3"
174
  tts.save(audio_file)
175
  st.audio(audio_file, format="audio/mp3")
176
-
177
- # Enhanced UI with HTML/CSS
178
- st.markdown("""
179
- ## 🎮 Game Board
180
- <div style="background-color: #f0f0f0; padding: 20px; border-radius: 10px; text-align: center;">
181
- <h3 style="color: #333;">Draw cards to weave your epic tale!</h3>
182
- <button style="background-color: #ff9900; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer;"
183
- onmouseover="this.style.backgroundColor='#cc7700'"
184
- onmouseout="this.style.backgroundColor='#ff9900'">
185
- Hover for a surprise!
186
- </button>
187
- </div>
188
- """, unsafe_allow_html=True)
189
-
190
- # Star layout
191
- st.markdown("## ⭐ Five Pillars of Storytelling ⭐")
192
- star_html = """
193
- <div style="position: relative; width: 400px; height: 400px; margin: auto; border: 1px dashed #aaa; border-radius: 50%;">
194
- <div style="position: absolute; top: 50px; left: 200px; transform: translate(-50%, -50%); text-align: center;">
195
- <div style="font-size: 2em;">🏠</div><div><b>Location</b></div>
196
- </div>
197
- <div style="position: absolute; top: 154px; left: 57px; transform: translate(-50%, -50%); text-align: center;">
198
- <div style="font-size: 2em;">🏃</div><div><b>Actions</b></div>
199
- </div>
200
- <div style="position: absolute; top: 321px; left: 112px; transform: translate(-50%, -50%); text-align: center;">
201
- <div style="font-size: 2em;">🧠</div><div><b>Thoughts</b></div>
202
- </div>
203
- <div style="position: absolute; top: 321px; left: 288px; transform: translate(-50%, -50%); text-align: center;">
204
- <div style="font-size: 2em;">😲</div><div><b>Emotions</b></div>
205
- </div>
206
- <div style="position: absolute; top: 154px; left: 343px; transform: translate(-50%, -50%); text-align: center;">
207
- <div style="font-size: 2em;">💬</div><div><b>Dialogue</b></div>
208
- </div>
209
- </div>
210
- """
211
- st.markdown(star_html, unsafe_allow_html=True)
212
 
213
  if __name__ == "__main__":
214
  main()
 
35
  # Pure Python function to augment word lists from user input
36
  def augment_word_lists(user_input):
37
  augmented_lists = {key: list(set(val)) for key, val in default_word_lists.items()}
 
 
38
  words = user_input.lower().split()
 
 
39
  location_keywords = ["town", "village", "city", "forest", "mountain", "place", "land"]
40
  action_keywords = ["walk", "run", "dance", "pedal", "explore", "move", "jump"]
41
  emotion_keywords = ["joy", "pain", "smile", "storm", "fear", "love", "anger"]
 
 
42
  dialogues = re.findall(r'"[^"]*"', user_input)
43
  augmented_lists["Dialogue"].extend(dialogues)
44
 
 
45
  for word in words:
46
  if any(keyword in word for keyword in location_keywords):
47
  augmented_lists["Location"].append(word)
 
49
  augmented_lists["Actions"].append(word)
50
  elif any(keyword in word for keyword in emotion_keywords):
51
  augmented_lists["Emotions"].append(word)
52
+ elif "?" in word or "what" in word or "why" in word:
53
  augmented_lists["Thoughts"].append(word)
54
 
 
55
  for key in augmented_lists:
56
  augmented_lists[key] = list(set(augmented_lists[key]))
 
57
  return augmented_lists
58
 
59
  # Create a 52-card deck
 
77
  else:
78
  return "Dialogue"
79
 
80
+ # Generate card visualization with p5.js
81
+ def generate_card_visualization(suit, rank, story_class, word, property):
82
+ # Parameterize animation based on card properties
83
+ num_balls = rank * 5 # More balls for higher rank
84
+ jelly_size = {"Hearts": 40, "Diamonds": 50, "Clubs": 30, "Spades": 60}[suit] # Suit affects jellyfish size
85
+ rotation_speed = {"Location": 0.005, "Actions": 0.01, "Thoughts": 0.003, "Emotions": 0.007, "Dialogue": 0.009}[story_class]
86
+ hue_base = {"Hearts": 0, "Diamonds": 120, "Clubs": 240, "Spades": 300}[suit] # Suit affects color
 
 
 
87
 
88
+ html_code = f"""
89
+ <!DOCTYPE html>
90
+ <html>
91
+ <head>
92
+ <meta charset="UTF-8">
93
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js"></script>
94
+ <style>
95
+ body {{ margin: 0; padding: 0; overflow: hidden; background: black; }}
96
+ #p5-container {{ display: flex; justify-content: center; align-items: center; }}
97
+ </style>
98
+ </head>
99
+ <body>
100
+ <div id="p5-container"></div>
101
+ <script>
102
+ let balls = [];
103
+ let jellyfish;
104
+ const sphereRadius = 150;
105
+ let sphereCenter;
106
+ let rotationAngle = 0;
107
+ const numBalls = {num_balls};
108
+
109
+ function setup() {{
110
+ let canvas = createCanvas(400, 400);
111
+ canvas.parent('p5-container');
112
+ sphereCenter = createVector(width/2, height/2);
113
+ colorMode(HSB, 360, 100, 100, 1);
114
+ for (let i = 0; i < numBalls; i++) {{
115
+ balls.push(new Ball());
116
+ }}
117
+ jellyfish = new Jellyfish();
118
+ }}
119
+
120
+ function draw() {{
121
+ background(0, 0, 0, 0.1);
122
+ rotationAngle += {rotation_speed};
123
+ push();
124
+ translate(sphereCenter.x, sphereCenter.y);
125
+ rotate(rotationAngle);
126
+ noFill();
127
+ stroke(255);
128
+ strokeWeight(2);
129
+ ellipse(0, 0, sphereRadius * 2, sphereRadius * 2);
130
+
131
+ for (let ball of balls) {{
132
+ ball.update();
133
+ ball.checkBoundaryCollision();
134
+ ball.display();
135
+ }}
136
+ jellyfish.update();
137
+ jellyfish.checkBoundaryCollision();
138
+ jellyfish.display();
139
+ pop();
140
+
141
+ // Card info overlay
142
+ fill(255, 255, 255, 0.8);
143
+ noStroke();
144
+ rect(0, 0, width, 60);
145
+ fill(0);
146
+ textSize(16);
147
+ textAlign(CENTER);
148
+ text("{rank} of {suit} - {story_class}: {word} ({property})", width/2, 30);
149
+ }}
150
+
151
+ class Ball {{
152
+ constructor() {{
153
+ this.r = 5;
154
+ let angle = random(TWO_PI);
155
+ let rad = random(sphereRadius - this.r);
156
+ this.pos = createVector(rad * cos(angle), rad * sin(angle));
157
+ let speed = random(1, 3);
158
+ let vAngle = random(TWO_PI);
159
+ this.vel = createVector(speed * cos(vAngle), speed * vAngle);
160
+ this.col = color({hue_base}, 100, 100);
161
+ }}
162
+ update() {{ this.pos.add(this.vel); }}
163
+ checkBoundaryCollision() {{
164
+ let d = this.pos.mag();
165
+ if (d + this.r > sphereRadius) {{
166
+ let normal = this.pos.copy().normalize();
167
+ let dot = this.vel.dot(normal);
168
+ this.vel.sub(p5.Vector.mult(normal, 2 * dot));
169
+ this.pos = normal.mult(sphereRadius - this.r);
170
+ }}
171
+ }}
172
+ display() {{
173
+ noStroke();
174
+ fill(this.col);
175
+ ellipse(this.pos.x, this.pos.y, this.r * 2, this.r * 2);
176
+ }}
177
+ }}
178
+
179
+ class Jellyfish {{
180
+ constructor() {{
181
+ this.size = {jelly_size};
182
+ this.pos = createVector(random(-sphereRadius + this.size, sphereRadius - this.size),
183
+ random(-sphereRadius + this.size, sphereRadius - this.size));
184
+ let speed = random(1, 2);
185
+ let angle = random(TWO_PI);
186
+ this.vel = createVector(speed * cos(angle), speed * sin(angle));
187
+ this.t = 0;
188
+ }}
189
+ update() {{ this.pos.add(this.vel); this.t += 0.05; }}
190
+ checkBoundaryCollision() {{
191
+ if (this.pos.mag() + this.size > sphereRadius) {{
192
+ let normal = this.pos.copy().normalize();
193
+ let dot = this.vel.dot(normal);
194
+ this.vel.sub(p5.Vector.mult(normal, 2 * dot));
195
+ this.pos = normal.mult(sphereRadius - this.size);
196
+ }}
197
+ }}
198
+ display() {{
199
+ push();
200
+ translate(this.pos.x, this.pos.y);
201
+ strokeWeight(1.5);
202
+ for (let y = 99; y < 300; y += 4) {{
203
+ for (let x = 99; x < 300; x += 2) {{
204
+ let res = jellyA(x, y, this.t);
205
+ let px = res[0] - 200;
206
+ let py = res[1] - 200;
207
+ stroke(getJellyColor(x, y, this.t));
208
+ point(px, py);
209
+ }}
210
+ }}
211
+ pop();
212
+ }}
213
+ }}
214
+
215
+ function jellyA(x, y, t) {{
216
+ let k = x / 8 - 25;
217
+ let e = y / 8 - 25;
218
+ let d = (k * k + e * e) / 99;
219
+ let q = x / 3 + k * 0.5 / cos(y * 5) * sin(d * d - t);
220
+ let c = d / 2 - t / 8;
221
+ let xPos = q * sin(c) + e * sin(d + k - t) + 200;
222
+ let yPos = (q + y / 8 + d * 9) * cos(c) + 200;
223
+ return [xPos, yPos];
224
+ }}
225
+
226
+ function getJellyColor(x, y, t) {{
227
+ let hue = (sin(t / 2) * 360 + x / 3 + y / 3) % 360;
228
+ let saturation = 70 + sin(t) * 30;
229
+ let brightness = 50 + cos(t / 2) * 20;
230
+ return color(hue, saturation, brightness, 0.5);
231
+ }}
232
+ </script>
233
+ </body>
234
+ </html>
235
+ """
236
+ return html_code
237
 
238
  # Generate story sentence
239
  def generate_story_sentence(story_class, word, property):
 
242
  # Generate song lyrics
243
  def generate_song_lyrics(story_text):
244
  words = story_text.split()
245
+ key_elements = [word for word in words if len(word) > 3][:12]
246
  lyrics = "\n".join([f"{key_elements[i]} {key_elements[i+1]}" for i in range(0, len(key_elements)-1, 2)])
247
  return lyrics
248
 
249
  # Main app
250
  def main():
251
+ st.set_page_config(page_title="StoryForge: The Animated Game", page_icon="🎴", layout="wide")
252
+ st.title("🎴 StoryForge: An Animated Storytelling Adventure 🎴")
253
 
254
  # User input
255
  st.markdown("## 📝 Your Story Seed")
 
274
  st.session_state.drawn_cards = 0
275
  st.success("Game started! Draw your first card.")
276
 
277
+ # Draw card and visualization
278
+ col1, col2 = st.columns([2, 3])
279
  with col1:
280
  if st.button("Draw Card") and st.session_state.drawn_cards < 52:
281
  card_index = st.session_state.drawn_cards
 
284
  word = random.choice(st.session_state.augmented_lists[story_class])
285
  property = suit_properties[suit]
286
 
287
+ # Generate and display animated visualization
288
+ viz_html = generate_card_visualization(suit, rank, story_class, word, property)
289
+ st.components.v1.html(viz_html, height=420, scrolling=False)
290
 
291
+ # Generate story sentence
292
  sentence = generate_story_sentence(story_class, word, property)
293
  st.session_state.story.append(sentence)
294
  st.session_state.drawn_cards += 1
 
309
  audio_file = "story_song.mp3"
310
  tts.save(audio_file)
311
  st.audio(audio_file, format="audio/mp3")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
 
313
  if __name__ == "__main__":
314
  main()