sunbal7 commited on
Commit
9f919e1
ยท
verified ยท
1 Parent(s): d4f137e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +246 -336
app.py CHANGED
@@ -6,10 +6,9 @@ import textwrap
6
  from io import BytesIO
7
  from PIL import Image, ImageDraw, ImageFont
8
  import numpy as np
9
- from gtts import gTTS
10
  from transformers import pipeline
11
  import base64
12
- import os
13
 
14
  # Set up the page
15
  st.set_page_config(
@@ -128,51 +127,61 @@ st.markdown("""
128
  margin: 0 auto;
129
  }
130
 
131
- .character-option {
132
- border: 3px solid transparent;
 
133
  border-radius: 10px;
134
- padding: 5px;
135
- margin: 5px;
136
- cursor: pointer;
137
- transition: all 0.3s;
 
138
  }
139
 
140
- .character-option:hover {
141
- transform: scale(1.05);
 
 
 
 
 
 
 
142
  }
143
 
144
- .character-option.selected {
145
- border-color: #ff5722;
 
 
146
  }
147
 
148
- .tab-content {
149
- padding: 1rem;
150
- border: 2px solid #4caf50;
151
  border-radius: 10px;
152
- background: rgba(255, 255, 255, 0.8);
153
- margin-top: 1rem;
 
 
154
  }
155
 
156
- .level-indicator {
157
- background: #4caf50;
158
- color: white;
159
- border-radius: 20px;
160
- padding: 0.5rem 1rem;
161
- display: inline-block;
162
  font-weight: bold;
163
- margin-bottom: 1rem;
 
 
 
 
 
 
 
 
164
  }
165
 
166
  /* Progress bar styling */
167
  .stProgress > div > div > div {
168
  background-color: #ff5722 !important;
169
  }
170
-
171
- /* Audio player styling */
172
- .audio-player {
173
- width: 100%;
174
- margin-top: 10px;
175
- }
176
  </style>
177
  """, unsafe_allow_html=True)
178
 
@@ -181,22 +190,19 @@ st.markdown("""
181
  def load_models():
182
  """Load open-source AI models"""
183
  try:
184
- # Text generation model for code explanations
185
- story_to_code = pipeline("text-generation", model="gpt2", max_length=100)
186
-
187
- # Sentiment analysis for story understanding
188
- sentiment_analyzer = pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english")
189
-
190
  # Named entity recognition for identifying objects
191
  ner_model = pipeline("ner", model="dbmdz/bert-large-cased-finetuned-conll03-english")
192
 
193
- # Text-to-text generation for better explanations
194
- explanation_generator = pipeline("text2text-generation", model="google/flan-t5-base")
 
 
 
195
 
196
- return story_to_code, sentiment_analyzer, ner_model, explanation_generator
197
  except Exception as e:
198
  st.error(f"Error loading models: {e}")
199
- return None, None, None, None
200
 
201
  # Image generation functions
202
  def create_storyboard_image(text, width=400, height=300):
@@ -244,6 +250,9 @@ def generate_sprite_animation(story, character="spaceship", theme="space", num_f
244
  elif theme == "medieval":
245
  bg_color = (139, 69, 19)
246
  star_color = None
 
 
 
247
  else:
248
  bg_color = (0, 0, 30)
249
  star_color = (255, 255, 255)
@@ -304,6 +313,23 @@ def generate_sprite_animation(story, character="spaceship", theme="space", num_f
304
  # Draw sword swing
305
  draw.line([(knight_x+25, knight_y+12), (knight_x+45, knight_y-10)], fill=(255, 255, 0), width=2)
306
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  # Draw enemies based on theme
308
  if theme == "space" and "alien" in story.lower():
309
  alien_x = 200
@@ -325,6 +351,14 @@ def generate_sprite_animation(story, character="spaceship", theme="space", num_f
325
  draw.ellipse([dragon_x, dragon_y, dragon_x+40, dragon_y+20], fill=(178, 34, 34))
326
  draw.line([(dragon_x+40, dragon_y+10), (dragon_x+60, dragon_y)], fill=(178, 34, 34), width=3)
327
 
 
 
 
 
 
 
 
 
328
  frames.append(img)
329
 
330
  return frames
@@ -333,12 +367,12 @@ def generate_code_explanation(story, explanation_generator):
333
  """Generate code explanation using open-source model"""
334
  try:
335
  # Create a prompt for the model
336
- prompt = f"Explain to a child how this story would become code: '{story}'"
337
 
338
  # Generate text
339
  result = explanation_generator(
340
  prompt,
341
- max_length=200,
342
  num_return_sequences=1,
343
  )
344
 
@@ -348,71 +382,85 @@ def generate_code_explanation(story, explanation_generator):
348
  return f"""See how your story became real code? For example, when you wrote "{story.split()[0]}",
349
  we used code like: character.move(). That's how we turn words into actions!"""
350
 
351
- def text_to_speech(text, lang='en'):
352
- """Convert text to speech and return as base64 encoded audio"""
353
  try:
354
- # Create gTTS object
355
- tts = gTTS(text=text, lang=lang, slow=False)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356
 
357
- # Save to in-memory bytes buffer
358
- audio_bytes = BytesIO()
359
- tts.write_to_fp(audio_bytes)
360
- audio_bytes.seek(0)
 
 
 
 
361
 
362
- # Encode as base64
363
- b64 = base64.b64encode(audio_bytes.read()).decode()
 
364
 
365
- # Create data URI for HTML5 audio
366
- data_url = f"data:audio/mp3;base64,{b64}"
 
 
 
 
 
 
 
367
 
368
- return data_url
 
369
  except Exception as e:
370
- st.error(f"Text-to-speech error: {e}")
371
- return None
372
-
373
- # Achievement system
374
- ACHIEVEMENTS = {
375
- "first_story": {"name": "Storyteller", "icon": "๐Ÿ“–", "description": "Created your first story!"},
376
- "code_master": {"name": "Code Master", "icon": "๐Ÿ’ป", "description": "Used 5 different coding concepts"},
377
- "animator": {"name": "Animator", "icon": "๐ŸŽฌ", "description": "Created 3 animations"},
378
- "voice_artist": {"name": "Voice Artist", "icon": "๐ŸŽค", "description": "Used text-to-speech feature"},
379
- "character_designer": {"name": "Character Designer", "icon": "๐Ÿ‘พ", "description": "Created a custom character"}
380
- }
381
-
382
- def unlock_achievement(achievement_id):
383
- """Unlock an achievement for the user"""
384
- if achievement_id not in st.session_state.achievements_unlocked:
385
- st.session_state.achievements_unlocked.append(achievement_id)
386
- st.session_state.new_achievement = achievement_id
387
- return True
388
- return False
389
 
390
  # Header section
391
  st.markdown('<div class="header">CodeTales โœจ</div>', unsafe_allow_html=True)
392
  st.markdown('<div class="subheader">Storytime + Coding Magic</div>', unsafe_allow_html=True)
393
- st.markdown('<div style="text-align:center; color:white; font-size:1.2rem; margin-bottom:2rem;">Turn wild stories into playable games with open-source AI magic!</div>', unsafe_allow_html=True)
394
 
395
  # How it works section
396
- with st.expander("โœจ How It Works (Like Baking a Cake) ๐ŸŽ‚"):
397
- st.markdown("""
398
- **1. Kids Write a Story (The Recipe)**
399
- Example: *"The spaceship zooms past aliens and shoots lasers!"*
400
-
401
- **2. AI is the Magic Oven ๐Ÿ”ฎ**
402
- We turn words into code using open-source AI models
403
-
404
- **3. Animation Pops Out (The Cake!) ๐ŸŽฎ**
405
- See your story come to life with custom animations!
406
-
407
- **4. Robot Teacher Explains ๐Ÿค–**
408
- Tavus shows: *"See? 'spaceship.move_right()' makes it fly! That's coding!"*
409
-
410
- **5. Level Up! ๐Ÿ†**
411
- Earn achievements as you learn and create!
412
- """)
413
 
414
  # Load models
415
- story_to_code, sentiment_analyzer, ner_model, explanation_generator = load_models()
416
 
417
  # Initialize session state
418
  if 'animation_generated' not in st.session_state:
@@ -427,29 +475,28 @@ if 'selected_character' not in st.session_state:
427
  st.session_state.selected_character = "spaceship"
428
  if 'selected_theme' not in st.session_state:
429
  st.session_state.selected_theme = "space"
430
- if 'sound_enabled' not in st.session_state:
431
- st.session_state.sound_enabled = True
432
- if 'achievements_unlocked' not in st.session_state:
433
- st.session_state.achievements_unlocked = []
434
- if 'new_achievement' not in st.session_state:
435
- st.session_state.new_achievement = None
436
  if 'story_count' not in st.session_state:
437
  st.session_state.story_count = 0
438
  if 'level' not in st.session_state:
439
  st.session_state.level = 1
440
  if 'xp' not in st.session_state:
441
  st.session_state.xp = 0
442
- if 'voice_enabled' not in st.session_state:
443
- st.session_state.voice_enabled = False
444
- if 'custom_character' not in st.session_state:
445
- st.session_state.custom_character = None
 
 
 
 
 
 
446
 
447
- # Story templates
448
- story_templates = {
449
- "None": "",
450
- "Space Adventure": "A brave spaceship zooms through space, shooting lasers at alien spaceships!",
451
- "Dragon Quest": "A knight fights a fire-breathing dragon to save the princess in the castle.",
452
- "Jungle Explorer": "An explorer runs through the jungle, jumping over snakes and swinging on vines."
453
  }
454
 
455
  # Main content
@@ -460,75 +507,45 @@ col1, col2 = st.columns([1, 1])
460
 
461
  with col1:
462
  st.markdown('<div class="story-box">', unsafe_allow_html=True)
463
- st.markdown("### ๐Ÿ“– Write Your Story Here:")
464
-
465
- # Story template selector
466
- selected_template = st.selectbox(
467
- "Or choose a story template to start with:",
468
- list(story_templates.keys()),
469
- index=0
470
- )
471
 
472
  story_text = st.text_area(
473
  "Tell your adventure story...",
474
  height=200,
475
  placeholder="Once upon a time, a brave spaceship zoomed through space, shooting lasers at alien spaceships...",
476
  label_visibility="collapsed",
477
- value=story_templates[selected_template] if selected_template != "None" else st.session_state.story_text
478
  )
479
 
480
- # Character selection
481
- st.markdown("### ๐Ÿง™ Choose Your Hero")
482
- char_cols = st.columns(3)
483
- characters = {
484
- "spaceship": "๐Ÿš€ Spaceship",
485
- "dragon": "๐Ÿ‰ Dragon",
486
- "knight": "๐Ÿ›ก๏ธ Knight"
487
- }
488
-
489
- for i, (char_key, char_label) in enumerate(characters.items()):
490
- with char_cols[i]:
491
- if st.button(
492
- char_label,
493
- key=f"char_{char_key}",
494
- use_container_width=True,
495
- type="primary" if st.session_state.selected_character == char_key else "secondary"
496
- ):
497
- st.session_state.selected_character = char_key
498
-
499
- # Theme selection
500
- st.markdown("### ๐ŸŽจ Choose Your World")
501
- theme_cols = st.columns(3)
502
- themes = {
503
- "space": "๐ŸŒŒ Space",
504
- "jungle": "๐ŸŒฟ Jungle",
505
- "medieval": "๐Ÿฐ Medieval"
506
- }
507
-
508
- for i, (theme_key, theme_label) in enumerate(themes.items()):
509
- with theme_cols[i]:
510
- if st.button(
511
- theme_label,
512
- key=f"theme_{theme_key}",
513
- use_container_width=True,
514
- type="primary" if st.session_state.selected_theme == theme_key else "secondary"
515
- ):
516
- st.session_state.selected_theme = theme_key
517
-
518
- # Voice options
519
- st.session_state.voice_enabled = st.toggle(
520
- "๐Ÿ—ฃ๏ธ Enable Tavus Voice",
521
- value=st.session_state.voice_enabled,
522
- help="Hear Tavus explain coding concepts with text-to-speech"
523
- )
524
-
525
- # Generate button with animation
526
- if st.button("โœจ Generate Animation!", use_container_width=True, key="generate", type="primary"):
527
  if story_text.strip():
528
  st.session_state.story_text = story_text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
529
  st.session_state.animation_generated = True
530
-
531
- with st.spinner("๐Ÿง™โ€โ™‚๏ธ Cooking your story in the magic oven..."):
532
  # Generate animation frames
533
  st.session_state.animation_frames = generate_sprite_animation(
534
  story_text,
@@ -541,38 +558,21 @@ with col1:
541
 
542
  # Update user progress
543
  st.session_state.story_count += 1
544
- st.session_state.xp += 15
545
 
546
  # Check for level up
547
  if st.session_state.xp >= 100:
548
  st.session_state.level += 1
549
  st.session_state.xp = st.session_state.xp - 100
550
  st.session_state.new_level = True
551
-
552
- # Unlock achievements
553
- if st.session_state.story_count == 1:
554
- unlock_achievement("first_story")
555
-
556
- # Generate speech if enabled
557
- if st.session_state.voice_enabled:
558
- st.session_state.speech_data = text_to_speech(st.session_state.code_explanation)
559
- if st.session_state.speech_data:
560
- unlock_achievement("voice_artist")
561
-
562
- # Simulate sound effect
563
- if st.session_state.sound_enabled:
564
- st.session_state.sound_message = "๐Ÿ”Š Sound effects added: Laser blasts, explosions, and more!"
565
- else:
566
- st.session_state.sound_message = ""
567
- else:
568
- st.warning("Please enter a story first!")
569
  st.markdown('</div>', unsafe_allow_html=True)
570
 
571
  with col2:
572
  st.markdown('<div class="story-box">', unsafe_allow_html=True)
573
- st.markdown("### ๐ŸŽฎ Your Game Animation")
574
 
575
  if st.session_state.animation_generated and st.session_state.animation_frames:
 
576
  # Display animation frames
577
  st.markdown("**Your Story Comes to Life!**")
578
  cols = st.columns(len(st.session_state.animation_frames))
@@ -599,195 +599,105 @@ with col2:
599
  use_container_width=True
600
  )
601
 
602
- # Display sound message
603
- if st.session_state.sound_enabled and 'sound_message' in st.session_state:
604
- st.info(st.session_state.sound_message)
605
-
606
  # Display character and theme info
607
  st.success(f"โœจ Your {characters[st.session_state.selected_character]} in the {themes[st.session_state.selected_theme]} world!")
608
 
609
- # Play voice explanation
610
- if st.session_state.voice_enabled and 'speech_data' in st.session_state and st.session_state.speech_data:
611
- st.markdown("### ๐Ÿ”Š Tavus Explanation")
612
- st.markdown(f"""
613
- <audio controls autoplay style="width:100%">
614
- <source src="{st.session_state.speech_data}" type="audio/mp3">
615
- Your browser does not support the audio element.
616
- </audio>
617
- """, unsafe_allow_html=True)
618
-
619
- elif st.session_state.animation_generated:
620
- st.warning("Couldn't generate animation. Try a different story!")
621
  st.image("https://img.freepik.com/free-vector/hand-drawn-colorful-space-background_23-2148821798.jpg",
622
  use_container_width=True)
 
623
  elif story_text:
624
- # Show storyboard preview
625
  preview_img = create_storyboard_image(story_text)
626
  st.image(preview_img, caption="Your Story Preview", use_container_width=True)
627
- st.info("๐Ÿ‘† Click Generate to bring your story to life!")
628
  else:
629
  st.image("https://img.freepik.com/free-vector/hand-drawn-colorful-space-background_23-2148821798.jpg",
630
  use_container_width=True)
631
- st.info("๐Ÿ‘† Write your story and click Generate to see the magic!")
632
 
633
  st.markdown('</div>', unsafe_allow_html=True)
634
 
635
  # Tavus explanation section
636
  if st.session_state.animation_generated and st.session_state.story_text:
637
  st.markdown('<div class="robot-speech">', unsafe_allow_html=True)
638
- st.markdown("### ๐Ÿค– Tavus the Robot Teacher says:")
639
 
640
  # Extract action words from story
641
- action_words = ["zoom", "shoot", "fly", "move", "jump", "run", "attack", "laser", "alien", "spaceship",
642
- "dragon", "fire", "hero", "sword", "castle", "run", "escape", "fight", "win"]
643
- found_actions = [word for word in action_words if word in st.session_state.story_text.lower()]
 
644
 
645
  if found_actions:
646
  # Create explanation based on found words
647
- explanations = []
648
- code_snippets = []
649
-
650
- for action in found_actions[:3]: # Limit to 3 explanations
651
- if action == "zoom":
652
- explanations.append("makes your spaceship move super fast!")
653
- code_snippets.append("spaceship.accelerate(speed=10)")
654
- elif action == "shoot":
655
- explanations.append("creates laser beams to defeat enemies!")
656
- code_snippets.append("laser = spaceship.fire_weapon()")
657
- elif action == "fly":
658
- explanations.append("keeps your character moving through the air!")
659
- code_snippets.append("character.apply_gravity(False)")
660
- elif action == "move":
661
- explanations.append("changes position on the screen!")
662
- code_snippets.append("player.move(direction='right')")
663
- elif action == "jump":
664
- explanations.append("makes your character leap upwards!")
665
- code_snippets.append("hero.jump(height=100)")
666
- elif action == "run":
667
- explanations.append("makes your character move faster!")
668
- code_snippets.append("player.speed = player.speed * 2")
669
- elif action == "attack":
670
- explanations.append("lets your hero fight the bad guys!")
671
- code_snippets.append("sword.swing(damage=15)")
672
- elif action == "laser":
673
- explanations.append("creates powerful energy beams!")
674
- code_snippets.append("weapon = Laser(color='red', damage=20)")
675
- elif action == "alien":
676
- explanations.append("adds enemies to your game!")
677
- code_snippets.append("enemy = Alien(position=(100, 200))")
678
- elif action == "spaceship":
679
- explanations.append("creates your main character!")
680
- code_snippets.append("player = Spaceship(image='spaceship.png')")
681
- elif action == "dragon":
682
- explanations.append("adds a fire-breathing challenge!")
683
- code_snippets.append("boss = Dragon(health=100, damage=25)")
684
- elif action == "fire":
685
- explanations.append("creates dangerous fire effects!")
686
- code_snippets.append("flame = FireEffect(position, size=30)")
687
- elif action == "hero":
688
- explanations.append("creates the main player character!")
689
- code_snippets.append("player = Hero(name='Your Hero')")
690
- elif action == "castle":
691
- explanations.append("adds a majestic building to your world!")
692
- code_snippets.append("castle = Building(type='castle', position=(300, 150))")
693
- elif action == "escape":
694
- explanations.append("creates exciting chase sequences!")
695
- code_snippets.append("player.start_escape_sequence(speed=15)")
696
- elif action == "fight":
697
- explanations.append("initiates battle mechanics!")
698
- code_snippets.append("initiate_combat(enemy)")
699
- elif action == "win":
700
- explanations.append("creates victory conditions!")
701
- code_snippets.append("if player.score > 100: show_victory_screen()")
702
 
703
- st.markdown("See how your story became real code? Here's what happened:")
704
-
705
- for i, (action, explanation, snippet) in enumerate(zip(found_actions, explanations, code_snippets)):
706
- st.markdown(f"**{i+1}. When you said '{action}'**:")
707
- st.markdown(f'<div class="code-block">{snippet}</div>', unsafe_allow_html=True)
708
- st.markdown(f"This code {explanation}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
709
 
710
- st.markdown("That's the magic of coding - turning words into actions!")
711
- else:
712
- st.markdown("I see you created an awesome story! Every word you write can become game code. Try adding action words like 'jump', 'run', or 'shoot' next time!")
713
 
714
  # Show AI-generated explanation
715
  st.markdown("### ๐Ÿง  AI-Powered Explanation:")
716
  st.write(st.session_state.code_explanation)
717
 
 
 
 
 
 
 
 
718
  st.markdown("</div>", unsafe_allow_html=True)
719
 
720
- # Achievements section
721
- if st.session_state.achievements_unlocked:
722
- st.markdown("### ๐Ÿ† Your Achievements")
723
- achievement_cols = st.columns(5)
724
- for i, ach_id in enumerate(st.session_state.achievements_unlocked):
725
- with achievement_cols[i % 5]:
726
- ach = ACHIEVEMENTS[ach_id]
727
- st.markdown(f'<div class="achievement-badge">{ach["icon"]}</div>', unsafe_allow_html=True)
728
- st.markdown(f"**{ach['name']}**")
729
- st.caption(ach['description'])
730
-
731
- # New achievement notification
732
- if 'new_achievement' in st.session_state and st.session_state.new_achievement:
733
- ach = ACHIEVEMENTS[st.session_state.new_achievement]
734
- st.success(f"๐ŸŽ‰ Achievement Unlocked: {ach['name']} - {ach['description']}")
735
- st.session_state.new_achievement = None
736
-
737
  # New level notification
738
  if 'new_level' in st.session_state and st.session_state.new_level:
739
  st.balloons()
740
  st.success(f"๐ŸŒŸ Level Up! You're now Level {st.session_state.level}!")
741
  st.session_state.new_level = False
742
 
743
- # Coding challenges section
744
- st.markdown("### ๐Ÿ’ป Coding Challenges")
745
- with st.expander("Complete challenges to earn XP!"):
746
- challenge_cols = st.columns(3)
747
-
748
- with challenge_cols[0]:
749
- st.markdown("#### Challenge 1: The Mover")
750
- st.code("""
751
- # Make the character move to the right
752
- character.move_right(10)
753
- """)
754
- if st.button("Run Challenge 1", key="challenge1"):
755
- st.session_state.xp += 5
756
- st.success("+5 XP! Character moved right!")
757
-
758
- with challenge_cols[1]:
759
- st.markdown("#### Challenge 2: The Jumper")
760
- st.code("""
761
- # Make the character jump
762
- character.jump(20)
763
- """)
764
- if st.button("Run Challenge 2", key="challenge2"):
765
- st.session_state.xp += 5
766
- st.success("+5 XP! Character jumped!")
767
-
768
- with challenge_cols[2]:
769
- st.markdown("#### Challenge 3: The Shooter")
770
- st.code("""
771
- # Make the character shoot a laser
772
- laser = character.shoot()
773
- """)
774
- if st.button("Run Challenge 3", key="challenge3"):
775
- st.session_state.xp += 5
776
- st.success("+5 XP! Laser fired!")
777
-
778
  # Benefits section
779
  st.markdown("""
780
- ## โค Why Everyone Will Love CodeTales
781
 
782
  | For Kids ๐Ÿ‘ง๐Ÿ‘ฆ | For Parents & Teachers ๐Ÿ‘ช๐Ÿ‘ฉโ€๐Ÿซ |
783
  |--------------|----------------------------|
784
- | โœจ Feels like playing, not learning | ๐Ÿง  Secretly teaches programming concepts |
785
- | ๐Ÿš€ Brings imagination to life | ๐Ÿ” Develops logical thinking skills |
786
- | ๐ŸŽฎ Creates personal video games | โž— Reinforces math fundamentals |
787
- | ๐Ÿ˜„ Makes learning fun and exciting | ๐Ÿงฉ Encourages problem-solving abilities |
788
- | ๐ŸŒŸ 100% private with no API keys | ๐Ÿ’ฐ Completely free and open-source |
789
- | ๐Ÿ† Achievement system motivates learning | ๐Ÿ“ˆ Progress tracking shows growth |
790
- | ๐Ÿ—ฃ๏ธ Voice explanations for accessibility | ๐ŸŽจ Creative expression through stories |
791
  """)
792
 
793
  # Footer
@@ -795,8 +705,8 @@ st.markdown("---")
795
  st.markdown("""
796
  <center>
797
  <p style="color:white; font-size:1.1rem;">
798
- โœจ Made with open-source magic by CodeTales Team โœจ<br>
799
- Transforming stories into games since 2023 | No API Keys Required!
800
  </p>
801
  </center>
802
  """, unsafe_allow_html=True)
 
6
  from io import BytesIO
7
  from PIL import Image, ImageDraw, ImageFont
8
  import numpy as np
 
9
  from transformers import pipeline
10
  import base64
11
+ import re
12
 
13
  # Set up the page
14
  st.set_page_config(
 
127
  margin: 0 auto;
128
  }
129
 
130
+ .hero-suggestion {
131
+ background: #ffeb3b;
132
+ color: #333;
133
  border-radius: 10px;
134
+ padding: 1rem;
135
+ margin: 1rem 0;
136
+ text-align: center;
137
+ font-weight: bold;
138
+ border: 2px dashed #ff9800;
139
  }
140
 
141
+ .world-suggestion {
142
+ background: #4caf50;
143
+ color: white;
144
+ border-radius: 10px;
145
+ padding: 1rem;
146
+ margin: 1rem 0;
147
+ text-align: center;
148
+ font-weight: bold;
149
+ border: 2px dashed #2e7d32;
150
  }
151
 
152
+ .step-container {
153
+ display: flex;
154
+ justify-content: space-between;
155
+ margin-bottom: 2rem;
156
  }
157
 
158
+ .step {
159
+ background: rgba(255, 255, 255, 0.9);
 
160
  border-radius: 10px;
161
+ padding: 1rem;
162
+ width: 23%;
163
+ text-align: center;
164
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
165
  }
166
 
167
+ .step-number {
168
+ font-size: 1.5rem;
 
 
 
 
169
  font-weight: bold;
170
+ background: #ff5722;
171
+ color: white;
172
+ border-radius: 50%;
173
+ width: 30px;
174
+ height: 30px;
175
+ display: flex;
176
+ align-items: center;
177
+ justify-content: center;
178
+ margin: 0 auto 10px;
179
  }
180
 
181
  /* Progress bar styling */
182
  .stProgress > div > div > div {
183
  background-color: #ff5722 !important;
184
  }
 
 
 
 
 
 
185
  </style>
186
  """, unsafe_allow_html=True)
187
 
 
190
  def load_models():
191
  """Load open-source AI models"""
192
  try:
 
 
 
 
 
 
193
  # Named entity recognition for identifying objects
194
  ner_model = pipeline("ner", model="dbmdz/bert-large-cased-finetuned-conll03-english")
195
 
196
+ # Text classification for theme detection
197
+ classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
198
+
199
+ # Text generation for code explanations
200
+ explanation_generator = pipeline("text2text-generation", model="google/flan-t5-large")
201
 
202
+ return ner_model, classifier, explanation_generator
203
  except Exception as e:
204
  st.error(f"Error loading models: {e}")
205
+ return None, None, None
206
 
207
  # Image generation functions
208
  def create_storyboard_image(text, width=400, height=300):
 
250
  elif theme == "medieval":
251
  bg_color = (139, 69, 19)
252
  star_color = None
253
+ elif theme == "underwater":
254
+ bg_color = (0, 105, 148)
255
+ star_color = None
256
  else:
257
  bg_color = (0, 0, 30)
258
  star_color = (255, 255, 255)
 
313
  # Draw sword swing
314
  draw.line([(knight_x+25, knight_y+12), (knight_x+45, knight_y-10)], fill=(255, 255, 0), width=2)
315
 
316
+ elif character == "mermaid":
317
+ mermaid_x = 50 + i * 40
318
+ mermaid_y = 120
319
+ # Draw mermaid tail
320
+ draw.ellipse([mermaid_x, mermaid_y, mermaid_x+30, mermaid_y+20], fill=(255, 105, 180))
321
+ # Draw mermaid body
322
+ draw.ellipse([mermaid_x+5, mermaid_y-20, mermaid_x+25, mermaid_y], fill=(255, 218, 185))
323
+ # Draw hair
324
+ draw.ellipse([mermaid_x-5, mermaid_y-25, mermaid_x+30, mermaid_y-15], fill=(255, 215, 0))
325
+
326
+ if "swim" in story.lower() and i > 0:
327
+ # Draw bubbles
328
+ for j in range(3):
329
+ bubble_x = mermaid_x + random.randint(0, 30)
330
+ bubble_y = mermaid_y - random.randint(10, 30)
331
+ draw.ellipse([bubble_x, bubble_y, bubble_x+5, bubble_y+5], fill=(173, 216, 230))
332
+
333
  # Draw enemies based on theme
334
  if theme == "space" and "alien" in story.lower():
335
  alien_x = 200
 
351
  draw.ellipse([dragon_x, dragon_y, dragon_x+40, dragon_y+20], fill=(178, 34, 34))
352
  draw.line([(dragon_x+40, dragon_y+10), (dragon_x+60, dragon_y)], fill=(178, 34, 34), width=3)
353
 
354
+ elif theme == "underwater" and "shark" in story.lower():
355
+ shark_x = 220
356
+ shark_y = 80 + i*10
357
+ # Draw shark body
358
+ draw.ellipse([shark_x, shark_y, shark_x+60, shark_y+30], fill=(169, 169, 169))
359
+ # Draw shark fin
360
+ draw.polygon([(shark_x+40, shark_y), (shark_x+50, shark_y-20), (shark_x+60, shark_y)], fill=(169, 169, 169))
361
+
362
  frames.append(img)
363
 
364
  return frames
 
367
  """Generate code explanation using open-source model"""
368
  try:
369
  # Create a prompt for the model
370
+ prompt = f"Explain to a child how this story would become code: '{story}'. Use simple analogies and relate to real-world objects."
371
 
372
  # Generate text
373
  result = explanation_generator(
374
  prompt,
375
+ max_length=250,
376
  num_return_sequences=1,
377
  )
378
 
 
382
  return f"""See how your story became real code? For example, when you wrote "{story.split()[0]}",
383
  we used code like: character.move(). That's how we turn words into actions!"""
384
 
385
+ def extract_story_elements(story, ner_model, classifier):
386
+ """Extract hero and world from the story using AI models"""
387
  try:
388
+ # Default values
389
+ hero = "spaceship"
390
+ world = "space"
391
+
392
+ # Find hero based on keywords and entities
393
+ hero_keywords = {
394
+ "spaceship": ["spaceship", "rocket", "ship", "alien", "planet", "star"],
395
+ "dragon": ["dragon", "monster", "creature", "beast", "wyvern"],
396
+ "knight": ["knight", "warrior", "prince", "princess", "king", "queen", "sword"],
397
+ "mermaid": ["mermaid", "merman", "sea", "ocean", "underwater", "fish"]
398
+ }
399
+
400
+ # Find world based on keywords and classification
401
+ world_labels = ["space", "jungle", "medieval", "underwater"]
402
+
403
+ # Find hero by keywords
404
+ story_lower = story.lower()
405
+ for candidate, keywords in hero_keywords.items():
406
+ if any(keyword in story_lower for keyword in keywords):
407
+ hero = candidate
408
+ break
409
+
410
+ # Use NER to find entities
411
+ entities = ner_model(story)
412
+ person_entities = [e['word'] for e in entities if e['entity'] in ['B-PER', 'I-PER']]
413
 
414
+ # If we found specific character names, adjust hero
415
+ if person_entities:
416
+ if "dragon" in story_lower:
417
+ hero = "dragon"
418
+ elif "knight" in story_lower or "king" in story_lower or "queen" in story_lower:
419
+ hero = "knight"
420
+ elif "mermaid" in story_lower or "sea" in story_lower:
421
+ hero = "mermaid"
422
 
423
+ # Classify world
424
+ result = classifier(story, world_labels)
425
+ world = result['labels'][0]
426
 
427
+ # Override based on specific keywords
428
+ if "underwater" in story_lower or "ocean" in story_lower or "sea" in story_lower:
429
+ world = "underwater"
430
+ if "forest" in story_lower or "jungle" in story_lower:
431
+ world = "jungle"
432
+ if "castle" in story_lower or "kingdom" in story_lower or "dragon" in story_lower:
433
+ world = "medieval"
434
+ if "space" in story_lower or "alien" in story_lower or "planet" in story_lower:
435
+ world = "space"
436
 
437
+ return hero, world
438
+
439
  except Exception as e:
440
+ st.error(f"Error analyzing story: {str(e)}")
441
+ return "spaceship", "space"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442
 
443
  # Header section
444
  st.markdown('<div class="header">CodeTales โœจ</div>', unsafe_allow_html=True)
445
  st.markdown('<div class="subheader">Storytime + Coding Magic</div>', unsafe_allow_html=True)
446
+ st.markdown('<div style="text-align:center; color:white; font-size:1.2rem; margin-bottom:2rem;">Turn wild stories into playable games with AI magic!</div>', unsafe_allow_html=True)
447
 
448
  # How it works section
449
+ st.markdown("### โœจ How It Works")
450
+ step_container = st.container()
451
+ with step_container:
452
+ cols = st.columns(4)
453
+ with cols[0]:
454
+ st.markdown('<div class="step"><div class="step-number">1</div>Write Your Story</div>', unsafe_allow_html=True)
455
+ with cols[1]:
456
+ st.markdown('<div class="step"><div class="step-number">2</div>AI Chooses Hero & World</div>', unsafe_allow_html=True)
457
+ with cols[2]:
458
+ st.markdown('<div class="step"><div class="step-number">3</div>Watch Animation</div>', unsafe_allow_html=True)
459
+ with cols[3]:
460
+ st.markdown('<div class="step"><div class="step-number">4</div>Learn Coding</div>', unsafe_allow_html=True)
 
 
 
 
 
461
 
462
  # Load models
463
+ ner_model, classifier, explanation_generator = load_models()
464
 
465
  # Initialize session state
466
  if 'animation_generated' not in st.session_state:
 
475
  st.session_state.selected_character = "spaceship"
476
  if 'selected_theme' not in st.session_state:
477
  st.session_state.selected_theme = "space"
 
 
 
 
 
 
478
  if 'story_count' not in st.session_state:
479
  st.session_state.story_count = 0
480
  if 'level' not in st.session_state:
481
  st.session_state.level = 1
482
  if 'xp' not in st.session_state:
483
  st.session_state.xp = 0
484
+ if 'analyzed' not in st.session_state:
485
+ st.session_state.analyzed = False
486
+
487
+ # Character and theme mapping
488
+ characters = {
489
+ "spaceship": "๐Ÿš€ Spaceship",
490
+ "dragon": "๐Ÿ‰ Dragon",
491
+ "knight": "๐Ÿ›ก๏ธ Knight",
492
+ "mermaid": "๐Ÿงœโ€โ™€๏ธ Mermaid"
493
+ }
494
 
495
+ themes = {
496
+ "space": "๐ŸŒŒ Space",
497
+ "jungle": "๐ŸŒฟ Jungle",
498
+ "medieval": "๐Ÿฐ Medieval",
499
+ "underwater": "๐ŸŒŠ Underwater"
 
500
  }
501
 
502
  # Main content
 
507
 
508
  with col1:
509
  st.markdown('<div class="story-box">', unsafe_allow_html=True)
510
+ st.markdown("### ๐Ÿ“– Step 1: Write Your Story")
 
 
 
 
 
 
 
511
 
512
  story_text = st.text_area(
513
  "Tell your adventure story...",
514
  height=200,
515
  placeholder="Once upon a time, a brave spaceship zoomed through space, shooting lasers at alien spaceships...",
516
  label_visibility="collapsed",
517
+ value=st.session_state.story_text
518
  )
519
 
520
+ if st.button("โœจ Analyze My Story!", use_container_width=True, key="analyze", type="primary"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
521
  if story_text.strip():
522
  st.session_state.story_text = story_text
523
+ with st.spinner("๐Ÿ” AI is reading your story to find the perfect hero and world..."):
524
+ # Extract story elements using AI
525
+ hero, world = extract_story_elements(story_text, ner_model, classifier)
526
+ st.session_state.selected_character = hero
527
+ st.session_state.selected_theme = world
528
+ st.session_state.analyzed = True
529
+
530
+ # Show suggestions
531
+ st.success(f"๐ŸŽฏ AI found a {characters[hero]} hero in a {themes[world]} world!")
532
+ else:
533
+ st.warning("Please enter a story first!")
534
+
535
+ if st.session_state.analyzed:
536
+ st.markdown("### ๐Ÿง™ Step 2: Your Hero & World")
537
+
538
+ st.markdown(f'<div class="hero-suggestion">Your Hero: {characters[st.session_state.selected_character]}</div>',
539
+ unsafe_allow_html=True)
540
+ st.markdown(f'<div class="world-suggestion">Your World: {themes[st.session_state.selected_theme]}</div>',
541
+ unsafe_allow_html=True)
542
+
543
+ st.info("๐Ÿ’ก The AI chose these based on your story! Click Generate Animation when ready.")
544
+
545
+ # Generate animation button
546
+ if st.button("๐ŸŽฌ Generate Animation!", use_container_width=True, key="generate", type="primary"):
547
  st.session_state.animation_generated = True
548
+ with st.spinner("๐Ÿง™โ€โ™‚๏ธ Creating your animation..."):
 
549
  # Generate animation frames
550
  st.session_state.animation_frames = generate_sprite_animation(
551
  story_text,
 
558
 
559
  # Update user progress
560
  st.session_state.story_count += 1
561
+ st.session_state.xp += 20
562
 
563
  # Check for level up
564
  if st.session_state.xp >= 100:
565
  st.session_state.level += 1
566
  st.session_state.xp = st.session_state.xp - 100
567
  st.session_state.new_level = True
568
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
569
  st.markdown('</div>', unsafe_allow_html=True)
570
 
571
  with col2:
572
  st.markdown('<div class="story-box">', unsafe_allow_html=True)
 
573
 
574
  if st.session_state.animation_generated and st.session_state.animation_frames:
575
+ st.markdown("### ๐ŸŽฎ Step 3: Your Animation")
576
  # Display animation frames
577
  st.markdown("**Your Story Comes to Life!**")
578
  cols = st.columns(len(st.session_state.animation_frames))
 
599
  use_container_width=True
600
  )
601
 
 
 
 
 
602
  # Display character and theme info
603
  st.success(f"โœจ Your {characters[st.session_state.selected_character]} in the {themes[st.session_state.selected_theme]} world!")
604
 
605
+ elif st.session_state.analyzed:
606
+ st.markdown("### ๐ŸŽฎ Step 3: Your Animation")
 
 
 
 
 
 
 
 
 
 
607
  st.image("https://img.freepik.com/free-vector/hand-drawn-colorful-space-background_23-2148821798.jpg",
608
  use_container_width=True)
609
+ st.info("๐Ÿ‘† Click 'Generate Animation' to bring your story to life!")
610
  elif story_text:
611
+ st.markdown("### ๐ŸŽฎ Your Animation Will Appear Here")
612
  preview_img = create_storyboard_image(story_text)
613
  st.image(preview_img, caption="Your Story Preview", use_container_width=True)
614
+ st.info("๐Ÿ‘† Click 'Analyze My Story' to begin the magic!")
615
  else:
616
  st.image("https://img.freepik.com/free-vector/hand-drawn-colorful-space-background_23-2148821798.jpg",
617
  use_container_width=True)
618
+ st.info("๐Ÿ‘† Write your story and click 'Analyze My Story' to begin!")
619
 
620
  st.markdown('</div>', unsafe_allow_html=True)
621
 
622
  # Tavus explanation section
623
  if st.session_state.animation_generated and st.session_state.story_text:
624
  st.markdown('<div class="robot-speech">', unsafe_allow_html=True)
625
+ st.markdown("### ๐Ÿค– Step 4: Tavus the Robot Teacher Explains Coding")
626
 
627
  # Extract action words from story
628
+ action_words = ["zoom", "shoot", "fly", "move", "jump", "run", "attack",
629
+ "laser", "alien", "spaceship", "dragon", "fire", "hero",
630
+ "sword", "castle", "escape", "fight", "win", "swim", "dive"]
631
+ found_actions = [word for word in action_words if re.search(r'\b' + word + r'\b', st.session_state.story_text.lower())]
632
 
633
  if found_actions:
634
  # Create explanation based on found words
635
+ st.markdown("#### ๐Ÿงฉ Story Actions to Code Concepts")
636
+ cols = st.columns(3)
637
+ action_colors = ["#ff6b6b", "#4ecdc4", "#ffd166", "#06d6a0", "#118ab2"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638
 
639
+ for i, action in enumerate(found_actions[:6]):
640
+ with cols[i % 3]:
641
+ color = action_colors[i % len(action_colors)]
642
+ st.markdown(f'<div style="background:{color}; color:white; border-radius:10px; padding:10px; text-align:center;">', unsafe_allow_html=True)
643
+ st.markdown(f"**{action.capitalize()}**")
644
+
645
+ # Add code snippets based on action
646
+ if action == "zoom":
647
+ st.code("hero.move_fast(10)", language="python")
648
+ elif action == "shoot":
649
+ st.code("laser = hero.create_weapon()", language="python")
650
+ elif action == "fly":
651
+ st.code("hero.fly(height=100)", language="python")
652
+ elif action == "move":
653
+ st.code("hero.move(direction='right')", language="python")
654
+ elif action == "jump":
655
+ st.code("hero.jump(power=20)", language="python")
656
+ elif action == "run":
657
+ st.code("hero.speed = hero.speed * 2", language="python")
658
+ elif action == "attack":
659
+ st.code("hero.attack(enemy)", language="python")
660
+ elif action == "swim":
661
+ st.code("hero.swim(speed=5)", language="python")
662
+ elif action == "dive":
663
+ st.code("hero.dive(depth=30)", language="python")
664
+ else:
665
+ st.code(f"hero.{action}()", language="python")
666
+
667
+ st.markdown("</div>", unsafe_allow_html=True)
668
 
669
+ st.markdown("---")
 
 
670
 
671
  # Show AI-generated explanation
672
  st.markdown("### ๐Ÿง  AI-Powered Explanation:")
673
  st.write(st.session_state.code_explanation)
674
 
675
+ st.markdown("#### ๐Ÿ’ก Remember:")
676
+ st.markdown("""
677
+ - Every action in your story becomes code
678
+ - Code is just instructions for computers
679
+ - You're already thinking like a coder!
680
+ """)
681
+
682
  st.markdown("</div>", unsafe_allow_html=True)
683
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
684
  # New level notification
685
  if 'new_level' in st.session_state and st.session_state.new_level:
686
  st.balloons()
687
  st.success(f"๐ŸŒŸ Level Up! You're now Level {st.session_state.level}!")
688
  st.session_state.new_level = False
689
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
690
  # Benefits section
691
  st.markdown("""
692
+ ## โค Why Kids & Parents Love CodeTales
693
 
694
  | For Kids ๐Ÿ‘ง๐Ÿ‘ฆ | For Parents & Teachers ๐Ÿ‘ช๐Ÿ‘ฉโ€๐Ÿซ |
695
  |--------------|----------------------------|
696
+ | โœจ Create your own animated stories | ๐Ÿง  Teaches computational thinking |
697
+ | ๐Ÿš€ See imagination come to life | ๐Ÿ” Develops problem-solving skills |
698
+ | ๐ŸŽฎ Interactive game creation | โž— Reinforces STEM fundamentals |
699
+ | ๐Ÿ˜„ Fun characters and worlds | ๐Ÿงฉ Encourages logical reasoning |
700
+ | ๐ŸŒŸ Unlock new levels | ๐Ÿ“ˆ Tracks learning progress |
 
 
701
  """)
702
 
703
  # Footer
 
705
  st.markdown("""
706
  <center>
707
  <p style="color:white; font-size:1.1rem;">
708
+ โœจ Made with magic by CodeTales Team โœจ<br>
709
+ Transforming stories into games since 2023
710
  </p>
711
  </center>
712
  """, unsafe_allow_html=True)