sunbal7 commited on
Commit
11450ed
Β·
verified Β·
1 Parent(s): a219068

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +268 -99
app.py CHANGED
@@ -1,15 +1,18 @@
1
- # app.py - Final Working Version with Animation
2
  import streamlit as st
3
  import os
4
  import time
5
  import random
6
  import numpy as np
7
- import matplotlib.pyplot as plt
 
 
 
8
  import base64
9
  from PIL import Image
10
  import io
11
- import pandas as pd
12
- import plotly.express as px
13
 
14
  # Configure Streamlit page
15
  st.set_page_config(
@@ -136,6 +139,14 @@ st.markdown("""
136
  text-align: center;
137
  margin: 10px 0;
138
  }
 
 
 
 
 
 
 
 
139
  </style>
140
  """, unsafe_allow_html=True)
141
 
@@ -178,64 +189,93 @@ CONCEPTS = {
178
  }
179
  }
180
 
181
- # Character database
182
  CHARACTERS = [
183
- {"name": "rabbit", "emoji": "🐰", "color": "#FFB6C1"},
184
- {"name": "dragon", "emoji": "πŸ‰", "color": "#FF6347"},
185
- {"name": "cat", "emoji": "🐱", "color": "#DDA0DD"},
186
- {"name": "dog", "emoji": "🐢", "color": "#FFD700"},
187
- {"name": "knight", "emoji": "🀺", "color": "#87CEEB"},
188
- {"name": "wizard", "emoji": "πŸ§™", "color": "#98FB98"},
189
- {"name": "scientist", "emoji": "πŸ”¬", "color": "#20B2AA"},
190
- {"name": "pirate", "emoji": "πŸ΄β€β˜ οΈ", "color": "#FFA500"}
 
 
 
 
 
 
 
 
 
 
 
 
191
  ]
192
 
193
- # Animation templates
194
  ANIMATION_TEMPLATES = {
195
  "loop": {
196
  "description": "Character moving to a target multiple times",
 
197
  "code": """
198
  # Loop Animation
199
  import matplotlib.pyplot as plt
200
  import numpy as np
201
 
202
  fig, ax = plt.subplots(figsize=(10, 6))
 
203
  ax.set_xlim(0, 10)
204
  ax.set_ylim(0, 10)
205
- ax.axis('off')
206
 
207
- character = ax.text(1, 5, "{emoji}", fontsize=48, color='{color}')
208
- target = ax.text(9, 5, "🎯", fontsize=48)
209
- ax.text(5, 9, "{story}", ha='center', fontsize=14)
 
210
 
211
  for i in range({count}):
 
212
  for pos in np.linspace(1, 9, 20):
213
  character.set_position((pos, 5))
214
  plt.pause(0.05)
 
 
 
 
 
 
 
 
 
215
  plt.show()
216
  """
217
  },
218
  "conditional": {
219
  "description": "Character making a decision based on a condition",
 
220
  "code": """
221
  # Conditional Animation
222
  import matplotlib.pyplot as plt
223
  import numpy as np
 
224
 
225
  fig, ax = plt.subplots(figsize=(10, 6))
 
226
  ax.set_xlim(0, 10)
227
  ax.set_ylim(0, 10)
228
- ax.axis('off')
229
 
230
- character = ax.text(5, 5, "{emoji}", fontsize=48, color='{color}')
231
- ax.text(5, 9, "{story}", ha='center', fontsize=14)
 
 
232
 
233
- # Condition: {condition}
234
- if {condition}:
235
- decision = ax.text(7, 7, "βœ… Yes", fontsize=24, color='green')
236
  path = np.linspace(5, 8, 20)
237
  else:
238
- decision = ax.text(7, 7, "❌ No", fontsize=24, color='red')
 
239
  path = np.linspace(5, 2, 20)
240
 
241
  for pos in path:
@@ -246,29 +286,34 @@ plt.show()
246
  },
247
  "function": {
248
  "description": "Character performing an action multiple times",
 
249
  "code": """
250
  # Function Animation
251
  import matplotlib.pyplot as plt
252
  import numpy as np
253
 
254
  fig, ax = plt.subplots(figsize=(10, 6))
 
255
  ax.set_xlim(0, 10)
256
  ax.set_ylim(0, 10)
257
- ax.axis('off')
258
 
259
- character = ax.text(5, 5, "{emoji}", fontsize=48, color='{color}')
260
- ax.text(5, 9, "{story}", ha='center', fontsize=14)
 
261
 
262
- def perform_action():
263
- for _ in range(5):
264
- character.set_fontsize(60)
265
- plt.pause(0.1)
266
- character.set_fontsize(48)
267
- plt.pause(0.1)
 
 
268
 
269
  for i in range({count}):
270
- perform_action()
271
- character.set_position((5 + i, 5))
 
272
  plt.show()
273
  """
274
  }
@@ -308,12 +353,36 @@ def extract_count_from_story(story):
308
  return min(int(word), 10)
309
  return 3 # Default value
310
 
311
- def create_animation(story, concepts):
312
- """Create an animation visualization based on the story and concepts"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  try:
314
- # Choose a random character
315
- character = random.choice(CHARACTERS)
316
  count = extract_count_from_story(story)
 
 
317
 
318
  # Create figure
319
  fig, ax = plt.subplots(figsize=(10, 6))
@@ -323,7 +392,7 @@ def create_animation(story, concepts):
323
  ax.axis('off')
324
 
325
  # Add title
326
- ax.text(5, 9, '✨ Your Story Animation ✨',
327
  fontsize=20, ha='center', color='purple', fontweight='bold')
328
 
329
  # Add story text
@@ -332,23 +401,26 @@ def create_animation(story, concepts):
332
  fontsize=14, ha='center', color='#333')
333
 
334
  # Add character
335
- ax.text(5, 5, character["emoji"],
336
  fontsize=100, ha='center', color=character["color"])
337
 
 
 
 
 
 
 
 
 
338
  # Add concept visualization
339
- if "loop" in concepts:
340
- ax.text(5, 3, f"πŸ”„ Repeating {count} times",
341
- fontsize=18, ha='center', color=CONCEPTS["loop"]["color"])
342
- elif "conditional" in concepts:
343
- condition = random.choice(["sunny", "raining", "dark"])
344
- ax.text(5, 3, f"❓ Checking if it's {condition}",
345
- fontsize=18, ha='center', color=CONCEPTS["conditional"]["color"])
346
- elif "function" in concepts:
347
- ax.text(5, 3, f"✨ Performing action {count} times",
348
- fontsize=18, ha='center', color=CONCEPTS["function"]["color"])
349
- else:
350
- ax.text(5, 3, "πŸ“ Creating your story visualization",
351
- fontsize=18, ha='center', color=CONCEPTS["variable"]["color"])
352
 
353
  # Add footer
354
  ax.text(5, 1, "Created with StoryCoder",
@@ -362,29 +434,49 @@ def create_animation(story, concepts):
362
  return buf
363
 
364
  except Exception as e:
365
- st.error(f"Animation error: {str(e)}")
366
  return None
367
 
368
  def create_interactive_animation(story, concepts):
369
  """Create an interactive animation using Plotly"""
370
  try:
371
- # Choose a random character
372
- character = random.choice(CHARACTERS)
373
  count = extract_count_from_story(story)
 
 
374
 
375
  # Create animation data
376
  frames = []
377
  for i in range(count):
378
- frames.append({
379
- "frame": i,
380
- "x": np.random.uniform(1, 9),
381
- "y": np.random.uniform(1, 9),
382
- "size": np.random.uniform(10, 30),
383
- "character": character["emoji"]
384
- })
 
 
 
 
 
 
 
385
 
386
  df = pd.DataFrame(frames)
387
 
 
 
 
 
 
 
 
 
 
 
 
388
  # Create animated scatter plot
389
  fig = px.scatter(
390
  df,
@@ -396,38 +488,92 @@ def create_interactive_animation(story, concepts):
396
  size_max=45,
397
  color_discrete_sequence=[character["color"]],
398
  range_x=[0, 10],
399
- range_y=[0, 10]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  )
401
 
402
  # Customize layout
403
  fig.update_layout(
404
- title=f'Animation for: "{story[:50]}{"..." if len(story) > 50 else ""}"',
405
  showlegend=False,
406
  plot_bgcolor='rgba(240,248,255,1)',
407
  paper_bgcolor='rgba(240,248,255,1)',
408
  width=800,
409
- height=600
 
 
 
 
 
 
 
 
 
410
  )
411
 
412
  fig.update_traces(
413
- textfont_size=30,
414
- textposition='middle center'
 
415
  )
416
 
417
- fig.layout.updatemenus[0].buttons[0].args[1]["frame"]["duration"] = 1000
418
- fig.layout.updatemenus[0].buttons[0].args[1]["transition"]["duration"] = 500
419
-
420
  return fig
421
 
422
  except Exception as e:
423
  st.error(f"Interactive animation error: {str(e)}")
424
  return None
425
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
426
  def generate_animation_code(story, concepts):
427
  """Generate Python animation code based on story"""
428
  try:
429
- # Choose a random character
430
- character = random.choice(CHARACTERS)
431
  count = extract_count_from_story(story)
432
  concept = concepts[0] if concepts else "loop"
433
 
@@ -435,19 +581,21 @@ def generate_animation_code(story, concepts):
435
  template = ANIMATION_TEMPLATES.get(concept, ANIMATION_TEMPLATES["loop"])
436
 
437
  # Fill in the template
438
- condition = random.choice(["True", "False"])
439
  code = template["code"].format(
440
  emoji=character["emoji"],
441
  color=character["color"],
442
  story=story[:80] + ('...' if len(story) > 80 else ''),
443
  count=count,
444
- condition=condition
 
 
445
  )
446
 
447
- return code, template["description"]
448
 
449
  except Exception as e:
450
- return f"# Error generating code\nprint('Could not generate code: {str(e)}')", ""
451
 
452
  def create_story_image(story):
453
  """Create a story image with Matplotlib"""
@@ -508,14 +656,18 @@ def main():
508
  st.session_state.story = ""
509
  if 'concepts' not in st.session_state:
510
  st.session_state.concepts = []
511
- if 'animation' not in st.session_state:
512
- st.session_state.animation = None
513
  if 'interactive_animation' not in st.session_state:
514
  st.session_state.interactive_animation = None
515
  if 'animation_code' not in st.session_state:
516
  st.session_state.animation_code = ""
517
  if 'code_description' not in st.session_state:
518
  st.session_state.code_description = ""
 
 
 
 
519
  if 'active_tab' not in st.session_state:
520
  st.session_state.active_tab = "story"
521
 
@@ -538,10 +690,12 @@ def main():
538
  if st.button("πŸ”„ Reset"):
539
  st.session_state.story = ""
540
  st.session_state.concepts = []
541
- st.session_state.animation = None
542
  st.session_state.interactive_animation = None
543
  st.session_state.animation_code = ""
544
  st.session_state.code_description = ""
 
 
545
  st.session_state.active_tab = "story"
546
 
547
  # Story creation tab
@@ -566,19 +720,25 @@ def main():
566
  with st.spinner("🧠 Analyzing your story for coding concepts..."):
567
  st.session_state.concepts = analyze_story(story)
568
 
569
- with st.spinner("🎬 Creating your animation..."):
570
- st.session_state.animation = create_animation(
571
  story, st.session_state.concepts
572
  )
573
 
 
574
  st.session_state.interactive_animation = create_interactive_animation(
575
  story, st.session_state.concepts
576
  )
577
 
578
- st.session_state.animation_code, st.session_state.code_description = generate_animation_code(
 
579
  story, st.session_state.concepts
580
  )
581
 
 
 
 
 
582
  st.session_state.active_tab = "animation"
583
  st.rerun()
584
 
@@ -588,12 +748,15 @@ def main():
588
  with col1:
589
  st.caption("Loop Example")
590
  st.code('"A dragon breathes fire 5 times at the castle"', language="text")
 
591
  with col2:
592
  st.caption("Conditional Example")
593
  st.code('"If it rains, the cat stays inside, else it goes out"', language="text")
 
594
  with col3:
595
  st.caption("Function Example")
596
  st.code('"A wizard casts a spell to make flowers grow"', language="text")
 
597
 
598
  # Animation tab
599
  elif st.session_state.active_tab == "animation":
@@ -604,29 +767,34 @@ def main():
604
  st.session_state.active_tab = "story"
605
  st.rerun()
606
 
607
- # Display animation
608
- st.markdown(f"""
609
- <div class="animation-container">
610
- <h3 style="color: white; text-align: center;">"{st.session_state.story[:60]}{'...' if len(st.session_state.story) > 60 else ''}"</h3>
611
- </div>
612
- """, unsafe_allow_html=True)
613
-
614
- # Display static animation
615
- if st.session_state.animation:
616
- st.image(st.session_state.animation, use_container_width=True)
617
  else:
618
- st.warning("Static animation couldn't be generated. Showing story image instead.")
619
  story_img = create_story_image(st.session_state.story)
620
  if story_img:
621
  st.image(story_img, use_container_width=True)
622
 
623
  # Display interactive animation
624
- st.subheader("πŸ“Š Interactive Animation")
625
  if st.session_state.interactive_animation:
626
  st.plotly_chart(st.session_state.interactive_animation, use_container_width=True)
627
  else:
628
  st.info("Interactive animation preview. The real animation would run on your computer!")
629
- st.image("https://i.imgur.com/5X8jYAy.gif", use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
630
 
631
  st.success("✨ Animation created successfully!")
632
  st.caption("This animation was generated with Python code based on your story!")
@@ -667,7 +835,8 @@ def main():
667
  st.write("Here's the Python code that would create your animation:")
668
 
669
  if st.session_state.animation_code:
670
- st.markdown(f"**{st.session_state.code_description}**")
 
671
  st.code(st.session_state.animation_code, language="python")
672
 
673
  # Download button
 
1
+ # app.py - Final Version with Enhanced Animations
2
  import streamlit as st
3
  import os
4
  import time
5
  import random
6
  import numpy as np
7
+ import pandas as pd
8
+ import plotly.express as px
9
+ import plotly.graph_objects as go
10
+ from gtts import gTTS
11
  import base64
12
  from PIL import Image
13
  import io
14
+ import matplotlib.pyplot as plt
15
+ import requests
16
 
17
  # Configure Streamlit page
18
  st.set_page_config(
 
139
  text-align: center;
140
  margin: 10px 0;
141
  }
142
+
143
+ .audio-player {
144
+ width: 100%;
145
+ margin: 20px 0;
146
+ border-radius: 20px;
147
+ background: #f0f8ff;
148
+ padding: 15px;
149
+ }
150
  </style>
151
  """, unsafe_allow_html=True)
152
 
 
189
  }
190
  }
191
 
192
+ # Character database with enhanced visuals
193
  CHARACTERS = [
194
+ {"name": "rabbit", "emoji": "🐰", "color": "#FFB6C1", "speed": 1.5},
195
+ {"name": "dragon", "emoji": "πŸ‰", "color": "#FF6347", "speed": 0.8},
196
+ {"name": "cat", "emoji": "🐱", "color": "#DDA0DD", "speed": 2.0},
197
+ {"name": "dog", "emoji": "🐢", "color": "#FFD700", "speed": 2.5},
198
+ {"name": "knight", "emoji": "🀺", "color": "#87CEEB", "speed": 1.2},
199
+ {"name": "wizard", "emoji": "πŸ§™", "color": "#98FB98", "speed": 1.0},
200
+ {"name": "scientist", "emoji": "πŸ”¬", "color": "#20B2AA", "speed": 1.3},
201
+ {"name": "pirate", "emoji": "πŸ΄β€β˜ οΈ", "color": "#FFA500", "speed": 1.4}
202
+ ]
203
+
204
+ # Object database for stories
205
+ STORY_OBJECTS = [
206
+ {"name": "carrot", "emoji": "πŸ₯•", "color": "#FF8C00"},
207
+ {"name": "treasure", "emoji": "πŸ’°", "color": "#FFD700"},
208
+ {"name": "castle", "emoji": "🏰", "color": "#A9A9A9"},
209
+ {"name": "flower", "emoji": "🌸", "color": "#FF69B4"},
210
+ {"name": "book", "emoji": "πŸ“š", "color": "#8B4513"},
211
+ {"name": "star", "emoji": "⭐", "color": "#FFFF00"},
212
+ {"name": "key", "emoji": "πŸ”‘", "color": "#DAA520"},
213
+ {"name": "apple", "emoji": "🍎", "color": "#FF0000"}
214
  ]
215
 
216
+ # Animation templates with visual cues
217
  ANIMATION_TEMPLATES = {
218
  "loop": {
219
  "description": "Character moving to a target multiple times",
220
+ "visual_cue": "πŸ”„ Repeating action multiple times",
221
  "code": """
222
  # Loop Animation
223
  import matplotlib.pyplot as plt
224
  import numpy as np
225
 
226
  fig, ax = plt.subplots(figsize=(10, 6))
227
+ ax.set_title('Your Story: {story}')
228
  ax.set_xlim(0, 10)
229
  ax.set_ylim(0, 10)
 
230
 
231
+ character = ax.text(1, 5, '{emoji}', fontsize=48, color='{color}')
232
+ target = ax.text(9, 5, '{target_emoji}', fontsize=48)
233
+ info = ax.text(5, 8, 'Loop: Repeating {count} times',
234
+ fontsize=16, ha='center', color='{concept_color}')
235
 
236
  for i in range({count}):
237
+ # Update position
238
  for pos in np.linspace(1, 9, 20):
239
  character.set_position((pos, 5))
240
  plt.pause(0.05)
241
+
242
+ # Show loop counter
243
+ info.set_text(f'Loop: Completed {{i+1}}/{count}')
244
+ plt.pause(0.2)
245
+
246
+ # Return to start
247
+ for pos in np.linspace(9, 1, 20):
248
+ character.set_position((pos, 5))
249
+ plt.pause(0.05)
250
  plt.show()
251
  """
252
  },
253
  "conditional": {
254
  "description": "Character making a decision based on a condition",
255
+ "visual_cue": "❓ Making a decision based on a condition",
256
  "code": """
257
  # Conditional Animation
258
  import matplotlib.pyplot as plt
259
  import numpy as np
260
+ import random
261
 
262
  fig, ax = plt.subplots(figsize=(10, 6))
263
+ ax.set_title('Your Story: {story}')
264
  ax.set_xlim(0, 10)
265
  ax.set_ylim(0, 10)
 
266
 
267
+ character = ax.text(5, 5, '{emoji}', fontsize=48, color='{color}')
268
+ condition = random.choice([True, False])
269
+ info = ax.text(5, 8, 'Condition: {condition_desc}',
270
+ fontsize=16, ha='center', color='{concept_color}')
271
 
272
+ if condition:
273
+ # Path for True condition
274
+ decision = ax.text(8, 7, 'βœ… True Path', fontsize=20, color='green')
275
  path = np.linspace(5, 8, 20)
276
  else:
277
+ # Path for False condition
278
+ decision = ax.text(2, 7, '❌ False Path', fontsize=20, color='red')
279
  path = np.linspace(5, 2, 20)
280
 
281
  for pos in path:
 
286
  },
287
  "function": {
288
  "description": "Character performing an action multiple times",
289
+ "visual_cue": "✨ Performing action with a function",
290
  "code": """
291
  # Function Animation
292
  import matplotlib.pyplot as plt
293
  import numpy as np
294
 
295
  fig, ax = plt.subplots(figsize=(10, 6))
296
+ ax.set_title('Your Story: {story}')
297
  ax.set_xlim(0, 10)
298
  ax.set_ylim(0, 10)
 
299
 
300
+ character = ax.text(5, 5, '{emoji}', fontsize=48, color='{color}')
301
+ info = ax.text(5, 8, 'Function: Performing action {count} times',
302
+ fontsize=16, ha='center', color='{concept_color}')
303
 
304
+ def perform_action(position):
305
+ # Action animation
306
+ character.set_fontsize(60)
307
+ plt.pause(0.1)
308
+ character.set_fontsize(48)
309
+ plt.pause(0.1)
310
+ # Move to new position
311
+ character.set_position((position, 5))
312
 
313
  for i in range({count}):
314
+ perform_action(5 + i)
315
+ info.set_text(f'Function: Action {{i+1}}/{count}')
316
+ plt.pause(0.3)
317
  plt.show()
318
  """
319
  }
 
353
  return min(int(word), 10)
354
  return 3 # Default value
355
 
356
+ def extract_story_elements(story):
357
+ """Extract characters and objects from the story"""
358
+ # Choose a random character
359
+ character = random.choice(CHARACTERS)
360
+
361
+ # Choose a random object
362
+ story_object = random.choice(STORY_OBJECTS)
363
+
364
+ # Try to find character in story
365
+ for char in CHARACTERS:
366
+ if char["name"] in story.lower():
367
+ character = char
368
+ break
369
+
370
+ # Try to find object in story
371
+ for obj in STORY_OBJECTS:
372
+ if obj["name"] in story.lower():
373
+ story_object = obj
374
+ break
375
+
376
+ return character, story_object
377
+
378
+ def create_visualization(story, concepts):
379
+ """Create a visualization image based on the story and concepts"""
380
  try:
381
+ # Get story elements
382
+ character, story_object = extract_story_elements(story)
383
  count = extract_count_from_story(story)
384
+ concept = concepts[0] if concepts else "variable"
385
+ concept_color = CONCEPTS[concept]["color"]
386
 
387
  # Create figure
388
  fig, ax = plt.subplots(figsize=(10, 6))
 
392
  ax.axis('off')
393
 
394
  # Add title
395
+ ax.text(5, 9, '✨ Your Story Visualization ✨',
396
  fontsize=20, ha='center', color='purple', fontweight='bold')
397
 
398
  # Add story text
 
401
  fontsize=14, ha='center', color='#333')
402
 
403
  # Add character
404
+ ax.text(3, 5, character["emoji"],
405
  fontsize=100, ha='center', color=character["color"])
406
 
407
+ # Add object
408
+ ax.text(7, 5, story_object["emoji"],
409
+ fontsize=100, ha='center', color=story_object["color"])
410
+
411
+ # Add connection arrow
412
+ ax.annotate('', xy=(7, 5), xytext=(3, 5),
413
+ arrowprops=dict(arrowstyle='->', lw=3, color=concept_color))
414
+
415
  # Add concept visualization
416
+ concept_text = CONCEPTS[concept]["emoji"] + " " + CONCEPTS[concept]["name"]
417
+ ax.text(5, 3, concept_text,
418
+ fontsize=24, ha='center', color=concept_color, fontweight='bold')
419
+
420
+ # Add action text
421
+ action = f"Action: {character['name'].title()} moves toward {story_object['name']}"
422
+ ax.text(5, 2.5, action,
423
+ fontsize=16, ha='center', color='#333')
 
 
 
 
 
424
 
425
  # Add footer
426
  ax.text(5, 1, "Created with StoryCoder",
 
434
  return buf
435
 
436
  except Exception as e:
437
+ st.error(f"Visualization error: {str(e)}")
438
  return None
439
 
440
  def create_interactive_animation(story, concepts):
441
  """Create an interactive animation using Plotly"""
442
  try:
443
+ # Get story elements
444
+ character, story_object = extract_story_elements(story)
445
  count = extract_count_from_story(story)
446
+ concept = concepts[0] if concepts else "variable"
447
+ concept_color = CONCEPTS[concept]["color"]
448
 
449
  # Create animation data
450
  frames = []
451
  for i in range(count):
452
+ # Create a path for the character
453
+ path_length = 20
454
+ for step in range(path_length):
455
+ progress = (i * path_length + step) / (count * path_length)
456
+ frames.append({
457
+ "frame": i * path_length + step,
458
+ "x": 3 + 4 * progress,
459
+ "y": 5 + np.sin(progress * np.pi * 2) * 2, # Wave motion
460
+ "size": 20 + np.sin(step * 0.3) * 10, # Pulsing effect
461
+ "character": character["emoji"],
462
+ "color": character["color"],
463
+ "info": f"{character['name'].title()} moving to {story_object['name']}",
464
+ "step": f"Action {i+1}/{count}"
465
+ })
466
 
467
  df = pd.DataFrame(frames)
468
 
469
+ # Create the target object (static)
470
+ target_df = pd.DataFrame([{
471
+ "x": 7,
472
+ "y": 5,
473
+ "character": story_object["emoji"],
474
+ "color": story_object["color"],
475
+ "size": 30,
476
+ "info": f"Target: {story_object['name']}",
477
+ "step": "Target"
478
+ }])
479
+
480
  # Create animated scatter plot
481
  fig = px.scatter(
482
  df,
 
488
  size_max=45,
489
  color_discrete_sequence=[character["color"]],
490
  range_x=[0, 10],
491
+ range_y=[0, 10],
492
+ hover_name="info",
493
+ hover_data={"step": True}
494
+ )
495
+
496
+ # Add the target object
497
+ fig.add_trace(go.Scatter(
498
+ x=target_df["x"],
499
+ y=target_df["y"],
500
+ text=target_df["character"],
501
+ mode="text",
502
+ textfont=dict(size=40, color=story_object["color"]),
503
+ hoverinfo="text",
504
+ hovertext=target_df["info"],
505
+ showlegend=False
506
+ ))
507
+
508
+ # Add concept indicator
509
+ fig.add_annotation(
510
+ x=0.5,
511
+ y=1.05,
512
+ xref="paper",
513
+ yref="paper",
514
+ text=f"{CONCEPTS[concept]['emoji']} {CONCEPTS[concept]['name']}",
515
+ showarrow=False,
516
+ font=dict(size=24, color=concept_color)
517
  )
518
 
519
  # Customize layout
520
  fig.update_layout(
521
+ title=f'Animation: {story[:60]}{"..." if len(story) > 60 else ""}',
522
  showlegend=False,
523
  plot_bgcolor='rgba(240,248,255,1)',
524
  paper_bgcolor='rgba(240,248,255,1)',
525
  width=800,
526
+ height=600,
527
+ xaxis=dict(showgrid=False, zeroline=False, visible=False),
528
+ yaxis=dict(showgrid=False, zeroline=False, visible=False),
529
+ updatemenus=[dict(
530
+ type="buttons",
531
+ buttons=[dict(
532
+ label="Play",
533
+ method="animate",
534
+ args=[None, {"frame": {"duration": 100, "redraw": True}}]
535
+ )]
536
  )
537
 
538
  fig.update_traces(
539
+ textfont_size=40,
540
+ textposition='middle center',
541
+ hoverlabel=dict(bgcolor="white", font_size=16)
542
  )
543
 
 
 
 
544
  return fig
545
 
546
  except Exception as e:
547
  st.error(f"Interactive animation error: {str(e)}")
548
  return None
549
 
550
+ def text_to_speech(text, filename="story_audio.mp3"):
551
+ """Convert text to speech using gTTS"""
552
+ try:
553
+ tts = gTTS(text=text, lang='en')
554
+ tts.save(filename)
555
+ return filename
556
+ except Exception as e:
557
+ st.error(f"Audio creation error: {str(e)}")
558
+ return None
559
+
560
+ def autoplay_audio(file_path):
561
+ """Autoplay audio in Streamlit"""
562
+ with open(file_path, "rb") as f:
563
+ data = f.read()
564
+ b64 = base64.b64encode(data).decode()
565
+ md = f"""
566
+ <audio autoplay>
567
+ <source src="data:audio/mp3;base64,{b64}" type="audio/mp3">
568
+ </audio>
569
+ """
570
+ st.markdown(md, unsafe_allow_html=True)
571
+
572
  def generate_animation_code(story, concepts):
573
  """Generate Python animation code based on story"""
574
  try:
575
+ # Get story elements
576
+ character, story_object = extract_story_elements(story)
577
  count = extract_count_from_story(story)
578
  concept = concepts[0] if concepts else "loop"
579
 
 
581
  template = ANIMATION_TEMPLATES.get(concept, ANIMATION_TEMPLATES["loop"])
582
 
583
  # Fill in the template
584
+ condition_desc = random.choice(["sunny", "raining", "dark"])
585
  code = template["code"].format(
586
  emoji=character["emoji"],
587
  color=character["color"],
588
  story=story[:80] + ('...' if len(story) > 80 else ''),
589
  count=count,
590
+ condition_desc=condition_desc,
591
+ target_emoji=story_object["emoji"],
592
+ concept_color=CONCEPTS[concept]["color"]
593
  )
594
 
595
+ return code, template["description"], template["visual_cue"]
596
 
597
  except Exception as e:
598
+ return f"# Error generating code\nprint('Could not generate code: {str(e)}')", "", ""
599
 
600
  def create_story_image(story):
601
  """Create a story image with Matplotlib"""
 
656
  st.session_state.story = ""
657
  if 'concepts' not in st.session_state:
658
  st.session_state.concepts = []
659
+ if 'visualization' not in st.session_state:
660
+ st.session_state.visualization = None
661
  if 'interactive_animation' not in st.session_state:
662
  st.session_state.interactive_animation = None
663
  if 'animation_code' not in st.session_state:
664
  st.session_state.animation_code = ""
665
  if 'code_description' not in st.session_state:
666
  st.session_state.code_description = ""
667
+ if 'visual_cue' not in st.session_state:
668
+ st.session_state.visual_cue = ""
669
+ if 'audio_file' not in st.session_state:
670
+ st.session_state.audio_file = None
671
  if 'active_tab' not in st.session_state:
672
  st.session_state.active_tab = "story"
673
 
 
690
  if st.button("πŸ”„ Reset"):
691
  st.session_state.story = ""
692
  st.session_state.concepts = []
693
+ st.session_state.visualization = None
694
  st.session_state.interactive_animation = None
695
  st.session_state.animation_code = ""
696
  st.session_state.code_description = ""
697
+ st.session_state.visual_cue = ""
698
+ st.session_state.audio_file = None
699
  st.session_state.active_tab = "story"
700
 
701
  # Story creation tab
 
720
  with st.spinner("🧠 Analyzing your story for coding concepts..."):
721
  st.session_state.concepts = analyze_story(story)
722
 
723
+ with st.spinner("🎨 Creating your visualization..."):
724
+ st.session_state.visualization = create_visualization(
725
  story, st.session_state.concepts
726
  )
727
 
728
+ with st.spinner("πŸš€ Creating interactive animation..."):
729
  st.session_state.interactive_animation = create_interactive_animation(
730
  story, st.session_state.concepts
731
  )
732
 
733
+ with st.spinner("πŸ’» Generating animation code..."):
734
+ st.session_state.animation_code, st.session_state.code_description, st.session_state.visual_cue = generate_animation_code(
735
  story, st.session_state.concepts
736
  )
737
 
738
+ with st.spinner("πŸ”Š Creating audio narration..."):
739
+ audio_text = f"Your story: {story}. This demonstrates the programming concept: {st.session_state.code_description}"
740
+ st.session_state.audio_file = text_to_speech(audio_text)
741
+
742
  st.session_state.active_tab = "animation"
743
  st.rerun()
744
 
 
748
  with col1:
749
  st.caption("Loop Example")
750
  st.code('"A dragon breathes fire 5 times at the castle"', language="text")
751
+ st.image("https://i.imgur.com/7zQY1eE.png", width=200)
752
  with col2:
753
  st.caption("Conditional Example")
754
  st.code('"If it rains, the cat stays inside, else it goes out"', language="text")
755
+ st.image("https://i.imgur.com/5X8jYAy.png", width=200)
756
  with col3:
757
  st.caption("Function Example")
758
  st.code('"A wizard casts a spell to make flowers grow"', language="text")
759
+ st.image("https://i.imgur.com/9zJkQ7P.png", width=200)
760
 
761
  # Animation tab
762
  elif st.session_state.active_tab == "animation":
 
767
  st.session_state.active_tab = "story"
768
  st.rerun()
769
 
770
+ # Display visualization
771
+ st.subheader("🎨 Story Visualization")
772
+ if st.session_state.visualization:
773
+ st.image(st.session_state.visualization, use_container_width=True)
 
 
 
 
 
 
774
  else:
775
+ st.warning("Visualization couldn't be generated. Showing story image instead.")
776
  story_img = create_story_image(st.session_state.story)
777
  if story_img:
778
  st.image(story_img, use_container_width=True)
779
 
780
  # Display interactive animation
781
+ st.subheader("πŸš€ Interactive Animation")
782
  if st.session_state.interactive_animation:
783
  st.plotly_chart(st.session_state.interactive_animation, use_container_width=True)
784
  else:
785
  st.info("Interactive animation preview. The real animation would run on your computer!")
786
+ st.image("https://i.imgur.com/8LzQY7a.gif", use_container_width=True)
787
+
788
+ # Play audio narration
789
+ st.subheader("πŸ”Š Story Narration")
790
+ if st.session_state.audio_file:
791
+ audio_bytes = open(st.session_state.audio_file, 'rb').read()
792
+ st.audio(audio_bytes, format='audio/mp3')
793
+
794
+ if st.button("▢️ Play Automatically"):
795
+ autoplay_audio(st.session_state.audio_file)
796
+ else:
797
+ st.info("Audio narration would play automatically here")
798
 
799
  st.success("✨ Animation created successfully!")
800
  st.caption("This animation was generated with Python code based on your story!")
 
835
  st.write("Here's the Python code that would create your animation:")
836
 
837
  if st.session_state.animation_code:
838
+ st.subheader(st.session_state.code_description)
839
+ st.markdown(f"**Visual Cue:** {st.session_state.visual_cue}")
840
  st.code(st.session_state.animation_code, language="python")
841
 
842
  # Download button