sunbal7 commited on
Commit
b59006d
·
verified ·
1 Parent(s): 67aee2f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +491 -1142
app.py CHANGED
@@ -1,1196 +1,545 @@
1
- # app.py
2
  import streamlit as st
 
 
3
  import time
 
4
  import random
5
- import textwrap
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
- import pygame
13
- import sys
14
- import os
15
- import tempfile
16
 
17
- # Set up the page
18
  st.set_page_config(
19
- page_title="CodeTales ",
20
- page_icon="🚀",
21
  layout="wide",
22
  initial_sidebar_state="expanded"
23
  )
24
 
25
- # Custom CSS
26
  st.markdown("""
27
  <style>
28
- @import url('https://fonts.googleapis.com/css2?family=Comic+Neue:wght@700&family=Press+Start+2P&display=swap');
29
-
30
- .stApp {
31
- background: linear-gradient(135deg, #6e8efb, #a777e3);
32
- }
33
-
34
- .header {
35
- font-family: 'Press Start 2P', cursive;
36
- color: white;
37
- text-align: center;
38
- font-size: 2.5rem;
39
- text-shadow: 3px 3px 0 #000;
40
- padding: 1rem;
41
- letter-spacing: 2px;
42
- }
43
-
44
- .subheader {
45
- font-family: 'Comic Neue', cursive;
46
- color: #ffeb3b;
47
- text-align: center;
48
- font-size: 1.8rem;
49
- margin-bottom: 2rem;
50
- }
51
-
52
- .story-box {
53
- background-color: rgba(255, 255, 255, 0.9);
54
- border-radius: 20px;
55
- padding: 2rem;
56
- box-shadow: 0 8px 16px rgba(0,0,0,0.2);
57
- margin-bottom: 2rem;
58
- border: 4px solid #ff6b6b;
59
- }
60
-
61
- .robot-speech {
62
- background-color: #4caf50;
63
- color: white;
64
- border-radius: 20px;
65
- padding: 1.5rem;
66
- font-size: 1.2rem;
67
- position: relative;
68
- margin-top: 2rem;
69
- border: 3px solid #2e7d32;
70
- }
71
-
72
- .robot-speech:after {
73
- content: '';
74
- position: absolute;
75
- top: -20px;
76
- left: 50px;
77
- border: 10px solid transparent;
78
- border-bottom-color: #4caf50;
79
- }
80
-
81
- .generate-btn {
82
- background: linear-gradient(135deg, #ff5722, #ff9800) !important;
83
- color: white !important;
84
- font-weight: bold !important;
85
- font-size: 1.2rem !important;
86
- padding: 0.7rem 2rem !important;
87
- border-radius: 50px !important;
88
- border: none !important;
89
- box-shadow: 0 4px 8px rgba(0,0,0,0.3) !important;
90
- transition: all 0.3s !important;
91
- margin-top: 1rem;
92
- font-family: 'Press Start 2P', cursive !important;
93
- letter-spacing: 1px;
94
- }
95
-
96
- .generate-btn:hover {
97
- transform: scale(1.05) !important;
98
- box-shadow: 0 6px 12px rgba(0,0,0,0.4) !important;
99
- background: linear-gradient(135deg, #ff7043, #ffa726) !important;
100
- }
101
-
102
- .code-block {
103
- background: #2d2d2d;
104
- color: #f8f8f2;
105
- padding: 1rem;
106
- border-radius: 10px;
107
- font-family: 'Courier New', monospace;
108
- font-size: 1.1rem;
109
- margin: 1rem 0;
110
- overflow-x: auto;
111
- border-left: 4px solid #ff9800;
112
- }
113
-
114
- .animation-frame {
115
- border: 3px solid #ffeb3b;
116
- border-radius: 10px;
117
- margin: 5px;
118
- }
119
-
120
- .achievement-badge {
121
- background: #ffd54f;
122
- color: #333;
123
- border-radius: 50%;
124
- width: 60px;
125
- height: 60px;
126
- display: flex;
127
- align-items: center;
128
- justify-content: center;
129
- font-size: 1.5rem;
130
- box-shadow: 0 4px 8px rgba(0,0,0,0.2);
131
- margin: 0 auto;
132
- }
133
-
134
- .hero-suggestion {
135
- background: #ffeb3b;
136
- color: #333;
137
- border-radius: 10px;
138
- padding: 1rem;
139
- margin: 1rem 0;
140
- text-align: center;
141
- font-weight: bold;
142
- border: 2px dashed #ff9800;
143
- }
144
-
145
- .world-suggestion {
146
- background: #4caf50;
147
- color: white;
148
- border-radius: 10px;
149
- padding: 1rem;
150
- margin: 1rem 0;
151
- text-align: center;
152
- font-weight: bold;
153
- border: 2px dashed #2e7d32;
154
- }
155
-
156
- .step-container {
157
- display: flex;
158
- justify-content: space-between;
159
- margin-bottom: 2rem;
160
- }
161
-
162
- .step {
163
- background: rgba(255, 255, 255, 0.9);
164
- border-radius: 10px;
165
- padding: 1rem;
166
- width: 23%;
167
- text-align: center;
168
- box-shadow: 0 4px 8px rgba(0,0,0,0.1);
169
- }
170
-
171
- .step-number {
172
- font-size: 1.5rem;
173
- font-weight: bold;
174
- background: #ff5722;
175
- color: white;
176
- border-radius: 50%;
177
- width: 30px;
178
- height: 30px;
179
- display: flex;
180
- align-items: center;
181
- justify-content: center;
182
- margin: 0 auto 10px;
183
- }
184
-
185
- .coding-tutorial {
186
- background: rgba(41, 128, 185, 0.9);
187
- border-radius: 20px;
188
- padding: 1.5rem;
189
- margin-top: 2rem;
190
- color: white;
191
- border: 3px solid #2980b9;
192
- }
193
-
194
- .code-playground {
195
- background: rgba(44, 62, 80, 0.9);
196
- border-radius: 15px;
197
- padding: 1.5rem;
198
- margin-top: 1.5rem;
199
- }
200
-
201
- /* Progress bar styling */
202
- .stProgress > div > div > div {
203
- background-color: #ff5722 !important;
204
- }
205
-
206
- .level-indicator {
207
- background: rgba(52, 152, 219, 0.9);
208
- color: white;
209
- border-radius: 50px;
210
- padding: 0.5rem 1rem;
211
- display: inline-block;
212
- margin-bottom: 1rem;
213
- font-weight: bold;
214
- border: 2px solid #2c3e50;
215
- }
216
- </style>
217
- """, unsafe_allow_html=True)
218
-
219
- # Initialize AI models
220
- @st.cache_resource
221
- def load_models():
222
- """Load open-source AI models"""
223
- try:
224
- # Named entity recognition for identifying objects
225
- ner_model = pipeline("ner", model="dbmdz/bert-large-cased-finetuned-conll03-english")
226
-
227
- # Text classification for theme detection
228
- classifier = pipeline("zero-shot-classification", model="facebook/bart-large-mnli")
229
-
230
- # Text generation for code explanations
231
- explanation_generator = pipeline("text2text-generation", model="google/flan-t5-large")
232
-
233
- return ner_model, classifier, explanation_generator
234
- except Exception as e:
235
- st.error(f"Error loading models: {e}")
236
- return None, None, None
237
-
238
- # Image generation functions
239
- def create_storyboard_image(text, width=400, height=300):
240
- """Create a storyboard image from text"""
241
- # Create blank image
242
- img = Image.new('RGB', (width, height), color=(25, 25, 112)) # Dark blue background
243
-
244
- # Load a comic-style font (fallback to default if not available)
245
- try:
246
- font = ImageFont.truetype("comic.ttf", 16)
247
- except:
248
- font = ImageFont.load_default()
249
-
250
- draw = ImageDraw.Draw(img)
251
 
252
- # Draw title
253
- draw.text((10, 10), "Your Story Comes to Life!", fill=(255, 215, 0), font=font)
 
 
254
 
255
- # Draw text box
256
- draw.rectangle([10, 40, width-10, height-40], fill=(240, 248, 255), outline=(255, 215, 0), width=2)
 
257
 
258
- # Wrap text
259
- wrapped_text = textwrap.fill(text, width=40)
260
- draw.text((20, 50), wrapped_text, fill=(25, 25, 112), font=font)
 
 
 
 
 
261
 
262
- # Draw decorations
263
- draw.rectangle([width-50, height-30, width-30, height-10], fill=(220, 20, 60), outline=(255, 215, 0), width=1)
264
- draw.ellipse([20, height-50, 70, height], fill=(30, 144, 255), outline=(255, 215, 0), width=1)
 
265
 
266
- return img
267
-
268
- def generate_sprite_animation(story, character="spaceship", theme="space", num_frames=8):
269
- """Generate a sprite-based animation from story"""
270
- frames = []
271
- width, height = 400, 300
 
 
272
 
273
- for i in range(num_frames):
274
- # Create base image with theme
275
- if theme == "space":
276
- bg_color = (0, 0, 30)
277
- star_color = (255, 255, 255)
278
- elif theme == "jungle":
279
- bg_color = (34, 139, 34)
280
- star_color = None
281
- elif theme == "medieval":
282
- bg_color = (139, 69, 19)
283
- star_color = None
284
- elif theme == "underwater":
285
- bg_color = (0, 105, 148)
286
- star_color = None
287
- elif theme == "desert":
288
- bg_color = (210, 180, 140)
289
- star_color = None
290
- elif theme == "arctic":
291
- bg_color = (240, 248, 255)
292
- star_color = None
293
- else:
294
- bg_color = (0, 0, 30)
295
- star_color = (255, 255, 255)
296
-
297
- img = Image.new('RGB', (width, height), color=bg_color)
298
- draw = ImageDraw.Draw(img)
299
-
300
- # Draw background elements
301
- if theme == "space":
302
- # Stars
303
- for _ in range(50):
304
- x = random.randint(0, width)
305
- y = random.randint(0, height)
306
- draw.ellipse([x, y, x+2, y+2], fill=star_color)
307
-
308
- # Planets
309
- draw.ellipse([300, 30, 380, 110], fill=(255, 165, 0), outline=(255, 215, 0), width=2)
310
-
311
- elif theme == "jungle":
312
- # Trees
313
- for x in [50, 150, 250, 350]:
314
- draw.rectangle([x, 150, x+20, 250], fill=(101, 67, 33))
315
- draw.ellipse([x-20, 120, x+40, 180], fill=(34, 139, 34))
316
-
317
- # Sun
318
- draw.ellipse([320, 30, 380, 90], fill=(255, 215, 0))
319
-
320
- elif theme == "medieval":
321
- # Castle
322
- draw.rectangle([250, 100, 350, 250], fill=(169, 169, 169))
323
- draw.rectangle([280, 150, 320, 250], fill=(105, 105, 105))
324
- for x in [260, 300, 340]:
325
- draw.polygon([(x, 80), (x-20, 100), (x+20, 100)], fill=(220, 20, 60))
326
-
327
- # Mountains
328
- draw.polygon([(0, 250), (100, 100), (200, 250)], fill=(120, 120, 120))
329
-
330
- elif theme == "underwater":
331
- # Seaweed
332
- for x in [50, 150, 250, 350]:
333
- draw.line([(x, 250), (x, 180)], fill=(0, 128, 0), width=5)
334
- draw.ellipse([x-20, 170, x+20, 190], fill=(0, 128, 0))
335
-
336
- # Bubbles
337
- for _ in range(20):
338
- x = random.randint(0, width)
339
- y = random.randint(0, 200)
340
- size = random.randint(5, 15)
341
- draw.ellipse([x, y, x+size, y+size], fill=(173, 216, 230), outline=(70, 130, 180))
342
-
343
- elif theme == "desert":
344
- # Sand dunes
345
- for x in [0, 100, 200, 300]:
346
- draw.arc([x, 150, x+200, 300], 180, 360, fill=(210, 180, 140), width=50)
347
-
348
- # Sun
349
- draw.ellipse([300, 30, 370, 100], fill=(255, 140, 0))
350
-
351
- elif theme == "arctic":
352
- # Snowy ground
353
- draw.rectangle([0, 200, width, height], fill=(255, 255, 255))
354
-
355
- # Snowflakes
356
- for _ in range(50):
357
- x = random.randint(0, width)
358
- y = random.randint(0, 180)
359
- draw.ellipse([x, y, x+3, y+3], fill=(255, 255, 255))
360
-
361
- # Mountains
362
- draw.polygon([(0, 250), (100, 100), (200, 250)], fill=(200, 200, 200))
363
-
364
- # Draw moving elements based on frame
365
- if character == "spaceship":
366
- ship_x = 50 + i * 40
367
- ship_y = 120
368
- # Spaceship body
369
- draw.polygon([(ship_x, ship_y), (ship_x+50, ship_y),
370
- (ship_x+25, ship_y-30)], fill=(169, 169, 169))
371
- # Spaceship details
372
- draw.rectangle([ship_x+20, ship_y-10, ship_x+30, ship_y], fill=(0, 191, 255))
373
-
374
- if "shoot" in story.lower() and i > 1:
375
- for j in range(3):
376
- laser_x = ship_x + 25
377
- laser_y = ship_y - 30 + j*5
378
- draw.line([(laser_x, laser_y), (width, laser_y)], fill=(255, 0, 0), width=3)
379
-
380
- elif character == "dragon":
381
- dragon_x = 50 + i * 30
382
- dragon_y = 140
383
- # Dragon body
384
- draw.ellipse([dragon_x, dragon_y, dragon_x+60, dragon_y+30], fill=(178, 34, 34))
385
- # Dragon head
386
- draw.ellipse([dragon_x+50, dragon_y+5, dragon_x+70, dragon_y+25], fill=(178, 34, 34))
387
- # Dragon wings
388
- draw.ellipse([dragon_x+10, dragon_y-20, dragon_x+40, dragon_y+10], fill=(138, 43, 226))
389
-
390
- if "fire" in story.lower() and i > 0:
391
- for j in range(5):
392
- flame_x = dragon_x + 70
393
- flame_y = dragon_y + 15 - j*5
394
- flame_size = random.randint(8, 18)
395
- draw.ellipse([flame_x, flame_y, flame_x+flame_size, flame_y+flame_size],
396
- fill=(255, random.randint(100, 200), 0))
397
-
398
- elif character == "knight":
399
- knight_x = 50 + i * 30
400
- knight_y = 150
401
- # Knight body
402
- draw.rectangle([knight_x, knight_y, knight_x+25, knight_y+50], fill=(70, 70, 70))
403
- # Knight head
404
- draw.ellipse([knight_x+5, knight_y-15, knight_x+20, knight_y], fill=(210, 180, 140))
405
- # Knight helmet
406
- draw.arc([knight_x, knight_y-20, knight_x+25, knight_y], 0, 180, fill=(50, 50, 50), width=3)
407
- # Sword
408
- draw.rectangle([knight_x+20, knight_y+10, knight_x+30, knight_y+15], fill=(192, 192, 192))
409
- draw.polygon([(knight_x+30, knight_y+12), (knight_x+40, knight_y+10), (knight_x+40, knight_y+15)], fill=(192, 192, 192))
410
-
411
- if "attack" in story.lower() and i % 2 == 1:
412
- # Draw sword swing
413
- draw.line([(knight_x+30, knight_y+12), (knight_x+60, knight_y-20)], fill=(255, 255, 0), width=3)
414
-
415
- elif character == "mermaid":
416
- mermaid_x = 50 + i * 30
417
- mermaid_y = 150
418
- # Mermaid tail
419
- draw.ellipse([mermaid_x, mermaid_y, mermaid_x+40, mermaid_y+30], fill=(255, 105, 180))
420
- # Mermaid body
421
- draw.ellipse([mermaid_x+10, mermaid_y-30, mermaid_x+30, mermaid_y], fill=(255, 218, 185))
422
- # Mermaid hair
423
- draw.ellipse([mermaid_x-10, mermaid_y-35, mermaid_x+40, mermaid_y-20], fill=(255, 215, 0))
424
-
425
- if "swim" in story.lower() and i > 0:
426
- # Draw bubbles
427
- for j in range(3):
428
- bubble_x = mermaid_x + random.randint(0, 40)
429
- bubble_y = mermaid_y - random.randint(20, 40)
430
- draw.ellipse([bubble_x, bubble_y, bubble_x+8, bubble_y+8], fill=(173, 216, 230))
431
-
432
- elif character == "robot":
433
- robot_x = 50 + i * 35
434
- robot_y = 150
435
- # Robot body
436
- draw.rectangle([robot_x, robot_y, robot_x+30, robot_y+50], fill=(100, 100, 100))
437
- # Robot head
438
- draw.rectangle([robot_x-5, robot_y-20, robot_x+35, robot_y], fill=(150, 150, 150))
439
- # Robot eyes
440
- draw.ellipse([robot_x+5, robot_y-15, robot_x+10, robot_y-10], fill=(0, 255, 0))
441
- draw.ellipse([robot_x+20, robot_y-15, robot_x+25, robot_y-10], fill=(0, 255, 0))
442
- # Robot arms
443
- draw.rectangle([robot_x-10, robot_y+10, robot_x, robot_y+20], fill=(100, 100, 100))
444
- draw.rectangle([robot_x+30, robot_y+10, robot_x+40, robot_y+20], fill=(100, 100, 100))
445
-
446
- if "laser" in story.lower() and i > 1:
447
- draw.line([(robot_x+40, robot_y+15), (width, robot_y+15)], fill=(0, 255, 0), width=3)
448
-
449
- elif character == "unicorn":
450
- unicorn_x = 50 + i * 30
451
- unicorn_y = 150
452
- # Unicorn body
453
- draw.ellipse([unicorn_x, unicorn_y, unicorn_x+40, unicorn_y+20], fill=(255, 240, 245))
454
- # Unicorn head
455
- draw.ellipse([unicorn_x+30, unicorn_y-5, unicorn_x+50, unicorn_y+15], fill=(255, 240, 245))
456
- # Unicorn horn
457
- draw.polygon([(unicorn_x+40, unicorn_y-10), (unicorn_x+45, unicorn_y-30), (unicorn_x+50, unicorn_y-10)], fill=(255, 215, 0))
458
- # Unicorn mane
459
- for j in range(5):
460
- color = random.choice(['#FF69B4', '#9370DB', '#87CEFA'])
461
- draw.ellipse([unicorn_x+25+j*3, unicorn_y-10-j*2, unicorn_x+35+j*3, unicorn_y+j*2], fill=color)
462
-
463
- # Draw enemies based on theme
464
- if theme == "space" and "alien" in story.lower():
465
- alien_x = 300
466
- alien_y = 120 - i*5
467
- draw.ellipse([alien_x, alien_y, alien_x+30, alien_y+30], fill=(50, 205, 50))
468
- draw.ellipse([alien_x+7, alien_y+8, alien_x+12, alien_y+13], fill=(0, 0, 0))
469
- draw.ellipse([alien_x+18, alien_y+8, alien_x+23, alien_y+13], fill=(0, 0, 0))
470
- draw.arc([alien_x+7, alien_y+15, alien_x+23, alien_y+25], 0, 180, fill=(0, 0, 0), width=2)
471
-
472
- elif theme == "jungle" and "snake" in story.lower():
473
- snake_x = 300
474
- snake_y = 180 - i*5
475
- for segment in range(8):
476
- offset = segment * 8
477
- draw.ellipse([snake_x+offset, snake_y+offset, snake_x+offset+20, snake_y+offset+20], fill=(0, 128, 0))
478
-
479
- elif theme == "medieval" and "dragon" in story.lower() and character != "dragon":
480
- dragon_x = 250
481
- dragon_y = 100
482
- draw.ellipse([dragon_x, dragon_y, dragon_x+50, dragon_y+25], fill=(178, 34, 34))
483
- draw.line([(dragon_x+50, dragon_y+12), (dragon_x+80, dragon_y)], fill=(178, 34, 34), width=4)
484
-
485
- elif theme == "underwater" and "shark" in story.lower():
486
- shark_x = 250
487
- shark_y = 100 + i*8
488
- # Shark body
489
- draw.ellipse([shark_x, shark_y, shark_x+80, shark_y+40], fill=(169, 169, 169))
490
- # Shark fin
491
- draw.polygon([(shark_x+60, shark_y), (shark_x+70, shark_y-30), (shark_x+80, shark_y)], fill=(169, 169, 169))
492
-
493
- elif theme == "desert" and "scorpion" in story.lower():
494
- scorpion_x = 300
495
- scorpion_y = 200
496
- # Scorpion body
497
- draw.ellipse([scorpion_x, scorpion_y, scorpion_x+40, scorpion_y+20], fill=(165, 42, 42))
498
- # Scorpion tail
499
- draw.line([(scorpion_x+40, scorpion_y+10), (scorpion_x+60, scorpion_y-10)], fill=(165, 42, 42), width=3)
500
- # Scorpion claws
501
- draw.line([(scorpion_x, scorpion_y+5), (scorpion_x-15, scorpion_y)], fill=(165, 42, 42), width=3)
502
- draw.line([(scorpion_x, scorpion_y+15), (scorpion_x-15, scorpion_y+20)], fill=(165, 42, 42), width=3)
503
-
504
- elif theme == "arctic" and "yeti" in story.lower():
505
- yeti_x = 280
506
- yeti_y = 180
507
- # Yeti body
508
- draw.ellipse([yeti_x, yeti_y, yeti_x+50, yeti_y+50], fill=(240, 240, 240))
509
- # Yeti eyes
510
- draw.ellipse([yeti_x+15, yeti_y+15, yeti_x+20, yeti_y+20], fill=(0, 0, 0))
511
- draw.ellipse([yeti_x+30, yeti_y+15, yeti_x+35, yeti_y+20], fill=(0, 0, 0))
512
- # Yeti mouth
513
- draw.arc([yeti_x+15, yeti_y+25, yeti_x+35, yeti_y+35], 0, 180, fill=(0, 0, 0), width=2)
514
-
515
- # Add frame number
516
- draw.text((10, 10), f"Frame {i+1}", fill=(255, 255, 255))
517
-
518
- frames.append(img)
519
 
520
- return frames
521
-
522
- def generate_pygame_code(story, character, theme):
523
- """Generate PyGame code based on the story"""
524
- # Basic PyGame template
525
- code = f"""import pygame
526
- import sys
527
-
528
- # Initialize Pygame
529
- pygame.init()
530
-
531
- # Screen dimensions
532
- WIDTH, HEIGHT = 800, 600
533
- screen = pygame.display.set_mode((WIDTH, HEIGHT))
534
- pygame.display.set_caption("Your Story: {character.capitalize()} in {theme.capitalize()}")
535
-
536
- # Colors
537
- BACKGROUND = {get_theme_color(theme)}
538
- HERO_COLOR = {get_character_color(character)}
539
-
540
- # Hero position
541
- hero_x = 100
542
- hero_y = HEIGHT // 2
543
- hero_speed = 5
544
-
545
- # Main game loop
546
- clock = pygame.time.Clock()
547
- running = True
548
-
549
- while running:
550
- for event in pygame.event.get():
551
- if event.type == pygame.QUIT:
552
- running = False
553
 
554
- # Handle keyboard input
555
- keys = pygame.key.get_pressed()
556
- if keys[pygame.K_LEFT]:
557
- hero_x -= hero_speed
558
- if keys[pygame.K_RIGHT]:
559
- hero_x += hero_speed
560
- if keys[pygame.K_UP]:
561
- hero_y -= hero_speed
562
- if keys[pygame.K_DOWN]:
563
- hero_y += hero_speed
564
 
565
- # Fill the background
566
- screen.fill(BACKGROUND)
 
 
 
 
567
 
568
- # Draw the hero
569
- {get_character_drawing_code(character)}
 
 
 
 
 
 
570
 
571
- # Draw story elements
572
- {get_story_elements_code(story, theme)}
 
 
573
 
574
- pygame.display.flip()
575
- clock.tick(60)
576
-
577
- pygame.quit()
578
- sys.exit()
579
- """
580
- return code
581
-
582
- def get_theme_color(theme):
583
- """Get theme color for PyGame code"""
584
- colors = {
585
- "space": "(0, 0, 30)",
586
- "jungle": "(34, 139, 34)",
587
- "medieval": "(139, 69, 19)",
588
- "underwater": "(0, 105, 148)",
589
- "desert": "(210, 180, 140)",
590
- "arctic": "(240, 248, 255)"
591
  }
592
- return colors.get(theme, "(0, 0, 30)")
 
593
 
594
- def get_character_color(character):
595
- """Get character color for PyGame code"""
596
- colors = {
597
- "spaceship": "(169, 169, 169)",
598
- "dragon": "(178, 34, 34)",
599
- "knight": "(70, 70, 70)",
600
- "mermaid": "(255, 105, 180)",
601
- "robot": "(100, 100, 100)",
602
- "unicorn": "(255, 240, 245)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
603
  }
604
- return colors.get(character, "(169, 169, 169)")
605
 
606
- def get_character_drawing_code(character):
607
- """Get PyGame drawing code for character"""
608
- if character == "spaceship":
609
- return """ # Draw spaceship
610
- pygame.draw.polygon(screen, HERO_COLOR, [(hero_x, hero_y),
611
- (hero_x+50, hero_y),
612
- (hero_x+25, hero_y-30)])
613
- pygame.draw.rect(screen, (0, 191, 255), (hero_x+20, hero_y-10, 10, 10))"""
614
- elif character == "dragon":
615
- return """ # Draw dragon
616
- pygame.draw.ellipse(screen, HERO_COLOR, (hero_x, hero_y, 60, 30))
617
- pygame.draw.ellipse(screen, HERO_COLOR, (hero_x+50, hero_y+5, 20, 20))
618
- pygame.draw.ellipse(screen, (138, 43, 226), (hero_x+10, hero_y-20, 30, 30))"""
619
- elif character == "knight":
620
- return """ # Draw knight
621
- pygame.draw.rect(screen, HERO_COLOR, (hero_x, hero_y, 25, 50))
622
- pygame.draw.ellipse(screen, (210, 180, 140), (hero_x+5, hero_y-15, 15, 15))
623
- pygame.draw.arc(screen, (50, 50, 50), (hero_x, hero_y-20, 25, 20), 0, 3.14, 3)
624
- pygame.draw.rect(screen, (192, 192, 192), (hero_x+20, hero_y+10, 10, 5))
625
- pygame.draw.polygon(screen, (192, 192, 192), [(hero_x+30, hero_y+12),
626
- (hero_x+40, hero_y+10),
627
- (hero_x+40, hero_y+15)])"""
628
- elif character == "mermaid":
629
- return """ # Draw mermaid
630
- pygame.draw.ellipse(screen, HERO_COLOR, (hero_x, hero_y, 40, 30))
631
- pygame.draw.ellipse(screen, (255, 218, 185), (hero_x+10, hero_y-30, 20, 30))
632
- pygame.draw.ellipse(screen, (255, 215, 0), (hero_x-10, hero_y-35, 50, 15))"""
633
- elif character == "robot":
634
- return """ # Draw robot
635
- pygame.draw.rect(screen, HERO_COLOR, (hero_x, hero_y, 30, 50))
636
- pygame.draw.rect(screen, (150, 150, 150), (hero_x-5, hero_y-20, 40, 20))
637
- pygame.draw.ellipse(screen, (0, 255, 0), (hero_x+5, hero_y-15, 5, 5))
638
- pygame.draw.ellipse(screen, (0, 255, 0), (hero_x+20, hero_y-15, 5, 5))
639
- pygame.draw.rect(screen, HERO_COLOR, (hero_x-10, hero_y+10, 10, 10))
640
- pygame.draw.rect(screen, HERO_COLOR, (hero_x+30, hero_y+10, 10, 10))"""
641
- elif character == "unicorn":
642
- return """ # Draw unicorn
643
- pygame.draw.ellipse(screen, HERO_COLOR, (hero_x, hero_y, 40, 20))
644
- pygame.draw.ellipse(screen, HERO_COLOR, (hero_x+30, hero_y-5, 20, 20))
645
- pygame.draw.polygon(screen, (255, 215, 0), [(hero_x+40, hero_y-10),
646
- (hero_x+45, hero_y-30),
647
- (hero_x+50, hero_y-10)])"""
648
- else:
649
- return """ # Draw hero
650
- pygame.draw.rect(screen, HERO_COLOR, (hero_x, hero_y, 40, 60))"""
651
 
652
- def get_story_elements_code(story, theme):
653
- """Get PyGame code for story elements"""
654
- code = ""
655
- if "alien" in story.lower() and theme == "space":
656
- code += """ # Draw alien
657
- pygame.draw.ellipse(screen, (50, 205, 50), (600, 200, 30, 30))
658
- pygame.draw.ellipse(screen, (0, 0, 0), (610, 210, 5, 5))
659
- pygame.draw.ellipse(screen, (0, 0, 0), (620, 210, 5, 5))
660
- pygame.draw.arc(screen, (0, 0, 0), (610, 220, 15, 10), 0, 3.14, 2)
661
- """
662
 
663
- if "dragon" in story.lower() and theme == "medieval":
664
- code += """ # Draw dragon
665
- pygame.draw.ellipse(screen, (178, 34, 34), (650, 150, 50, 25))
666
- pygame.draw.line(screen, (178, 34, 34), (700, 162), (730, 150), 4)
667
- """
668
 
669
- if "treasure" in story.lower():
670
- code += """ # Draw treasure
671
- pygame.draw.rect(screen, (255, 215, 0), (700, 400, 30, 20))
672
- pygame.draw.rect(screen, (255, 215, 0), (705, 395, 20, 10))
673
- """
674
 
675
- if "castle" in story.lower() and theme == "medieval":
676
- code += """ # Draw castle
677
- pygame.draw.rect(screen, (169, 169, 169), (600, 300, 150, 150))
678
- pygame.draw.rect(screen, (105, 105, 105), (650, 350, 50, 100))
679
- for x in range(610, 740, 40):
680
- pygame.draw.polygon(screen, (220, 20, 60), [(x, 300), (x-20, 320), (x+20, 320)])
681
- """
682
 
683
- return code
684
-
685
- def generate_code_explanation(story, explanation_generator):
686
- """Generate code explanation using open-source model"""
687
- try:
688
- # Create a prompt for the model
689
- prompt = f"Explain to a child how this story would become code: '{story}'. Use simple analogies and relate to real-world objects."
690
-
691
- # Generate text
692
- result = explanation_generator(
693
- prompt,
694
- max_length=250,
695
- num_return_sequences=1,
696
- )
697
-
698
- return result[0]['generated_text']
699
- except:
700
- # Fallback explanation if model fails
701
- return f"""See how your story became real code? For example, when you wrote "{story.split()[0]}",
702
- we used code like: character.move(). That's how we turn words into actions!"""
703
 
704
- def extract_story_elements(story, ner_model, classifier):
705
- """Extract hero and world from the story using AI models"""
706
  try:
707
- # Default values
708
- hero = "spaceship"
709
- world = "space"
710
 
711
- # Find hero based on keywords and entities
712
- hero_keywords = {
713
- "spaceship": ["spaceship", "rocket", "ship", "alien", "planet", "star", "space"],
714
- "dragon": ["dragon", "monster", "creature", "beast", "wyvern"],
715
- "knight": ["knight", "warrior", "prince", "princess", "king", "queen", "sword", "castle"],
716
- "mermaid": ["mermaid", "merman", "sea", "ocean", "underwater", "fish"],
717
- "robot": ["robot", "cyborg", "machine", "android"],
718
- "unicorn": ["unicorn", "horse", "pony", "magic"]
719
- }
720
 
721
- # Find world based on keywords and classification
722
- world_labels = ["space", "jungle", "medieval", "underwater", "desert", "arctic"]
 
723
 
724
- # Find hero by keywords
725
- story_lower = story.lower()
726
- for candidate, keywords in hero_keywords.items():
727
- if any(keyword in story_lower for keyword in keywords):
728
- hero = candidate
729
- break
730
 
731
- # Use NER to find entities
732
- entities = ner_model(story)
733
- person_entities = [e['word'] for e in entities if e['entity'] in ['B-PER', 'I-PER']]
734
-
735
- # If we found specific character names, adjust hero
736
- if person_entities:
737
- if "dragon" in story_lower:
738
- hero = "dragon"
739
- elif "knight" in story_lower or "king" in story_lower or "queen" in story_lower:
740
- hero = "knight"
741
- elif "mermaid" in story_lower or "sea" in story_lower:
742
- hero = "mermaid"
743
- elif "robot" in story_lower:
744
- hero = "robot"
745
- elif "unicorn" in story_lower:
746
- hero = "unicorn"
747
-
748
- # Classify world
749
- result = classifier(story, world_labels)
750
- world = result['labels'][0]
751
-
752
- # Override based on specific keywords
753
- if "underwater" in story_lower or "ocean" in story_lower or "sea" in story_lower:
754
- world = "underwater"
755
- if "forest" in story_lower or "jungle" in story_lower:
756
- world = "jungle"
757
- if "castle" in story_lower or "kingdom" in story_lower or "dragon" in story_lower or "knight" in story_lower:
758
- world = "medieval"
759
- if "space" in story_lower or "alien" in story_lower or "planet" in story_lower:
760
- world = "space"
761
- if "desert" in story_lower or "sand" in story_lower:
762
- world = "desert"
763
- if "arctic" in story_lower or "snow" in story_lower or "ice" in story_lower:
764
- world = "arctic"
765
-
766
- return hero, world
767
-
768
- except Exception as e:
769
- st.error(f"Error analyzing story: {str(e)}")
770
- return "spaceship", "space"
771
-
772
- def run_pygame_code(code):
773
- """Run PyGame code and capture the output"""
774
- with tempfile.NamedTemporaryFile(suffix=".py", delete=False, mode="w") as f:
775
- f.write(code)
776
- temp_file_name = f.name
777
-
778
- # Create a video capture of the PyGame window
779
- os.system(f"python {temp_file_name} &")
780
- return temp_file_name
781
-
782
- # Header section
783
- st.markdown('<div class="header">CodeTales ✨</div>', unsafe_allow_html=True)
784
- st.markdown('<div class="subheader">Storytime + Coding Magic</div>', unsafe_allow_html=True)
785
- 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)
786
-
787
- # How it works section
788
- st.markdown("### ✨ How It Works")
789
- step_container = st.container()
790
- with step_container:
791
- cols = st.columns(4)
792
- with cols[0]:
793
- st.markdown('<div class="step"><div class="step-number">1</div>Write Your Story</div>', unsafe_allow_html=True)
794
- with cols[1]:
795
- st.markdown('<div class="step"><div class="step-number">2</div>AI Chooses Hero & World</div>', unsafe_allow_html=True)
796
- with cols[2]:
797
- st.markdown('<div class="step"><div class="step-number">3</div>Watch Animation</div>', unsafe_allow_html=True)
798
- with cols[3]:
799
- st.markdown('<div class="step"><div class="step-number">4</div>Learn Coding</div>', unsafe_allow_html=True)
800
-
801
- # Load models
802
- ner_model, classifier, explanation_generator = load_models()
803
-
804
- # Initialize session state
805
- if 'animation_generated' not in st.session_state:
806
- st.session_state.animation_generated = False
807
- if 'story_text' not in st.session_state:
808
- st.session_state.story_text = ""
809
- if 'animation_frames' not in st.session_state:
810
- st.session_state.animation_frames = []
811
- if 'code_explanation' not in st.session_state:
812
- st.session_state.code_explanation = ""
813
- if 'selected_character' not in st.session_state:
814
- st.session_state.selected_character = "spaceship"
815
- if 'selected_theme' not in st.session_state:
816
- st.session_state.selected_theme = "space"
817
- if 'story_count' not in st.session_state:
818
- st.session_state.story_count = 0
819
- if 'level' not in st.session_state:
820
- st.session_state.level = 1
821
- if 'xp' not in st.session_state:
822
- st.session_state.xp = 0
823
- if 'analyzed' not in st.session_state:
824
- st.session_state.analyzed = False
825
- if 'pygame_code' not in st.session_state:
826
- st.session_state.pygame_code = ""
827
- if 'show_code' not in st.session_state:
828
- st.session_state.show_code = False
829
-
830
- # Character and theme mapping
831
- characters = {
832
- "spaceship": "🚀 Spaceship",
833
- "dragon": "🐉 Dragon",
834
- "knight": "🛡️ Knight",
835
- "mermaid": "🧜‍♀️ Mermaid",
836
- "robot": "🤖 Robot",
837
- "unicorn": "🦄 Unicorn"
838
- }
839
-
840
- themes = {
841
- "space": "🌌 Space",
842
- "jungle": "🌿 Jungle",
843
- "medieval": "🏰 Medieval",
844
- "underwater": "🌊 Underwater",
845
- "desert": "🏜️ Desert",
846
- "arctic": "❄️ Arctic"
847
- }
848
-
849
- # Main content
850
- st.markdown(f'<div class="level-indicator">Level {st.session_state.level} ✨ XP: {st.session_state.xp}/100</div>', unsafe_allow_html=True)
851
- progress = st.progress(st.session_state.xp / 100)
852
 
853
- col1, col2 = st.columns([1, 1])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
854
 
855
- with col1:
856
- st.markdown('<div class="story-box">', unsafe_allow_html=True)
857
- st.markdown("### 📖 Step 1: Write Your Story")
858
-
859
- story_text = st.text_area(
860
- "Tell your adventure story...",
861
- height=200,
862
- placeholder="Once upon a time, a brave spaceship zoomed through space, shooting lasers at alien spaceships...",
863
- label_visibility="collapsed",
864
- value=st.session_state.story_text
865
- )
866
-
867
- if st.button("✨ Analyze My Story!", use_container_width=True, key="analyze", type="primary"):
868
- if story_text.strip():
869
- st.session_state.story_text = story_text
870
- with st.spinner("🔍 AI is reading your story to find the perfect hero and world..."):
871
- # Extract story elements using AI
872
- hero, world = extract_story_elements(story_text, ner_model, classifier)
873
- st.session_state.selected_character = hero
874
- st.session_state.selected_theme = world
875
- st.session_state.analyzed = True
876
-
877
- # Show suggestions
878
- st.success(f"🎯 AI found a {characters[hero]} hero in a {themes[world]} world!")
 
 
 
 
 
879
  else:
880
- st.warning("Please enter a story first!")
881
-
882
- if st.session_state.analyzed:
883
- st.markdown("### 🧙 Step 2: Your Hero & World")
884
-
885
- st.markdown(f'<div class="hero-suggestion">Your Hero: {characters[st.session_state.selected_character]}</div>',
886
- unsafe_allow_html=True)
887
- st.markdown(f'<div class="world-suggestion">Your World: {themes[st.session_state.selected_theme]}</div>',
888
- unsafe_allow_html=True)
889
-
890
- # Customization options
891
- st.markdown("### 🎨 Customize Your Hero")
892
- custom_char = st.selectbox(
893
- "Choose a different hero:",
894
- options=list(characters.keys()),
895
- format_func=lambda x: characters[x],
896
- index=list(characters.keys()).index(st.session_state.selected_character)
897
- )
898
- st.session_state.selected_character = custom_char
899
-
900
- # Generate animation button
901
- if st.button("🎬 Generate Animation & Code!", use_container_width=True, key="generate", type="primary"):
902
- st.session_state.animation_generated = True
903
- with st.spinner("🧙‍♂️ Creating your animation and code..."):
904
- # Generate animation frames
905
- st.session_state.animation_frames = generate_sprite_animation(
906
- story_text,
907
- character=st.session_state.selected_character,
908
- theme=st.session_state.selected_theme,
909
- num_frames=8
910
- )
911
-
912
- # Generate code explanation
913
- st.session_state.code_explanation = generate_code_explanation(story_text, explanation_generator)
914
-
915
- # Generate PyGame code
916
- st.session_state.pygame_code = generate_pygame_code(
917
- story_text,
918
- st.session_state.selected_character,
919
- st.session_state.selected_theme
920
- )
921
-
922
- # Update user progress
923
- st.session_state.story_count += 1
924
- st.session_state.xp += 25
925
-
926
- # Check for level up
927
- if st.session_state.xp >= 100:
928
- st.session_state.level += 1
929
- st.session_state.xp = st.session_state.xp - 100
930
- st.session_state.new_level = True
931
-
932
- st.markdown('</div>', unsafe_allow_html=True)
933
 
934
- with col2:
935
- st.markdown('<div class="story-box">', unsafe_allow_html=True)
936
-
937
- if st.session_state.animation_generated and st.session_state.animation_frames:
938
- st.markdown("### 🎮 Step 3: Your Animation")
939
- # Display animation frames
940
- st.markdown("**Your Story Comes to Life!**")
941
-
942
- # Show animation as GIF
943
- gif_buffer = BytesIO()
944
- st.session_state.animation_frames[0].save(
945
- gif_buffer,
946
- format='GIF',
947
- save_all=True,
948
- append_images=st.session_state.animation_frames[1:],
949
- duration=500,
950
- loop=0
951
- )
952
-
953
- st.image(gif_buffer, caption="Your Animated Story", use_container_width=True)
954
-
955
- # Download button
956
- st.download_button(
957
- label="⬇️ Download Animation",
958
- data=gif_buffer.getvalue(),
959
- file_name="your_story.gif",
960
- mime="image/gif",
961
- use_container_width=True
962
- )
963
-
964
- # Display character and theme info
965
- st.success(f"✨ Your {characters[st.session_state.selected_character]} in the {themes[st.session_state.selected_theme]} world!")
966
 
967
- elif st.session_state.analyzed:
968
- st.markdown("### 🎮 Step 3: Your Animation")
969
- st.image("https://img.freepik.com/free-vector/hand-drawn-colorful-space-background_23-2148821798.jpg",
970
- use_container_width=True)
971
- st.info("👆 Click 'Generate Animation & Code!' to bring your story to life!")
972
- elif story_text:
973
- st.markdown("### 🎮 Your Animation Will Appear Here")
974
- preview_img = create_storyboard_image(story_text)
975
- st.image(preview_img, caption="Your Story Preview", use_container_width=True)
976
- st.info("👆 Click 'Analyze My Story' to begin the magic!")
977
- else:
978
- st.image("https://img.freepik.com/free-vector/hand-drawn-colorful-space-background_23-2148821798.jpg",
979
- use_container_width=True)
980
- st.info("👆 Write your story and click 'Analyze My Story' to begin!")
981
-
982
- st.markdown('</div>', unsafe_allow_html=True)
983
 
984
- # Coding tutorial section
985
- if st.session_state.animation_generated and st.session_state.story_text:
986
- st.markdown('<div class="robot-speech">', unsafe_allow_html=True)
987
- st.markdown("### 🤖 Step 4: Tavus the Robot Teacher Explains Coding")
988
-
989
- # Show code explanation
990
- st.markdown("### 🧠 AI-Powered Explanation:")
991
- st.write(st.session_state.code_explanation)
992
-
993
- # Toggle for showing full code
994
- if st.button("👨‍💻 Show Me the Full Code!", key="show_code"):
995
- st.session_state.show_code = not st.session_state.show_code
996
-
997
- if st.session_state.show_code:
998
- st.markdown("### 🐍 Your Story as Python Code")
999
- st.code(st.session_state.pygame_code, language='python')
1000
 
1001
- if st.button("▶️ Run This Code in PyGame", key="run_pygame"):
1002
- with st.spinner("🚀 Launching your game..."):
1003
- temp_file = run_pygame_code(st.session_state.pygame_code)
1004
- st.success(f"Game launched! Check your desktop for the PyGame window")
1005
- st.info("Use arrow keys to move your character!")
1006
-
1007
- # Step-by-step coding tutorial
1008
- st.markdown("### 👣 Step-by-Step Coding Tutorial")
1009
- with st.expander("1. Setting Up Your Game"):
1010
- st.markdown("""
1011
- Every PyGame program starts with these basic steps:
1012
- ```python
1013
- import pygame # Import the game library
1014
- import sys # Import system library for exit
1015
 
1016
- # Initialize Pygame
1017
- pygame.init()
 
 
 
1018
 
1019
- # Create a game window
1020
- WIDTH, HEIGHT = 800, 600
1021
- screen = pygame.display.set_mode((WIDTH, HEIGHT))
1022
- pygame.display.set_caption("Your Awesome Game")
1023
- ```
1024
- """)
1025
-
1026
- with st.expander("2. Creating Your Hero"):
1027
- st.markdown(f"""
1028
- Let's create your {st.session_state.selected_character} hero:
1029
- ```python
1030
- # Hero position
1031
- hero_x = 100
1032
- hero_y = 300
1033
-
1034
- # How to draw your hero
1035
- def draw_hero():
1036
- {get_character_drawing_code(st.session_state.selected_character).replace('\\n', '\\n ')}
1037
- ```
1038
- """)
1039
 
1040
-
1041
- with st.expander("3. Making Your Hero Move"):
1042
- st.markdown("""
1043
- We'll use keyboard input to move the hero:
1044
- ```python
1045
- hero_speed = 5
1046
-
1047
- # Inside the game loop
1048
- keys = pygame.key.get_pressed()
1049
- if keys[pygame.K_LEFT]:
1050
- hero_x -= hero_speed
1051
- if keys[pygame.K_RIGHT]:
1052
- hero_x += hero_speed
1053
- if keys[pygame.K_UP]:
1054
- hero_y -= hero_speed
1055
- if keys[pygame.K_DOWN]:
1056
- hero_y += hero_speed
1057
- ```
1058
- """)
1059
-
1060
- with st.expander("4. Adding Your Story Elements"):
1061
- story_elements = []
1062
- if "alien" in st.session_state.story_text.lower():
1063
- story_elements.append("Aliens")
1064
- if "dragon" in st.session_state.story_text.lower():
1065
- story_elements.append("Dragons")
1066
- if "treasure" in st.session_state.story_text.lower():
1067
- story_elements.append("Treasure")
1068
-
1069
- if story_elements:
1070
- elements = ", ".join(story_elements)
1071
- st.markdown(f"""
1072
- Let's add {elements} from your story:
1073
- ```python
1074
- def draw_story_elements():
1075
- {get_story_elements_code(st.session_state.story_text, st.session_state.selected_theme).replace('\n', '\n ')}
1076
- ```
1077
- """)
1078
- else:
1079
- st.markdown("""
1080
- Add your own story elements with drawing commands:
1081
- ```python
1082
- # Example: Draw a treasure chest
1083
- pygame.draw.rect(screen, (255, 215, 0), (700, 400, 30, 20))
1084
- pygame.draw.rect(screen, (255, 215, 0), (705, 395, 20, 10))
1085
- ```
1086
- """)
1087
-
1088
- with st.expander("5. Running Your Game"):
1089
- st.markdown("""
1090
- Finally, we put everything together in a game loop:
1091
- ```python
1092
- # Main game loop
1093
- clock = pygame.time.Clock()
1094
- running = True
1095
-
1096
- while running:
1097
- # Handle events
1098
- for event in pygame.event.get():
1099
- if event.type == pygame.QUIT:
1100
- running = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1101
 
1102
- # Handle movement
1103
- # ... (movement code from step 3)
 
 
 
 
 
1104
 
1105
- # Draw everything
1106
- screen.fill(BACKGROUND)
1107
- draw_hero()
1108
- draw_story_elements()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1109
 
1110
- # Update the display
1111
- pygame.display.flip()
1112
- clock.tick(60)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1113
 
1114
- pygame.quit()
1115
- sys.exit()
1116
- ```
1117
- """)
1118
-
1119
- st.markdown("</div>", unsafe_allow_html=True)
1120
-
1121
- # Code Playground
1122
- if st.session_state.animation_generated:
1123
- st.markdown('<div class="code-playground">', unsafe_allow_html=True)
1124
- st.markdown("### 🧪 Step 5: Code Playground")
1125
- st.markdown("Try modifying your code and see the changes!")
1126
-
1127
- # Editable code area
1128
- modified_code = st.text_area(
1129
- "Edit your Python code:",
1130
- value=st.session_state.pygame_code,
1131
- height=300,
1132
- key="code_editor"
1133
- )
1134
-
1135
- # Run the modified code
1136
- if st.button("🚀 Run My Modified Code", key="run_modified_code"):
1137
- with st.spinner("Running your code..."):
1138
- temp_file = run_pygame_code(modified_code)
1139
- st.success("Game launched with your modifications!")
1140
-
1141
- st.markdown("</div>", unsafe_allow_html=True)
1142
-
1143
- # New level notification
1144
- if 'new_level' in st.session_state and st.session_state.new_level:
1145
- st.balloons()
1146
- st.success(f"🌟 Level Up! You're now Level {st.session_state.level}!")
1147
- st.session_state.new_level = False
1148
-
1149
- # Achievements
1150
- st.markdown("### 🏆 Your Achievements")
1151
- achievement_cols = st.columns(4)
1152
- with achievement_cols[0]:
1153
- st.markdown('<div class="achievement-badge">📝</div>', unsafe_allow_html=True)
1154
- st.markdown("**Storyteller**", help="Created your first story")
1155
- st.markdown(f"{st.session_state.story_count} story created")
1156
-
1157
- with achievement_cols[1]:
1158
- st.markdown('<div class="achievement-badge">👾</div>', unsafe_allow_html=True)
1159
- st.markdown("**Animator**", help="Generated 5 animations")
1160
- st.markdown(f"{min(st.session_state.story_count, 5)}/5 animations")
1161
 
1162
- with achievement_cols[2]:
1163
- st.markdown('<div class="achievement-badge">💻</div>', unsafe_allow_html=True)
1164
- st.markdown("**Coder**", help="Modified and ran code")
1165
- st.markdown("Unlocked!" if st.session_state.animation_generated else "Locked")
1166
-
1167
- with achievement_cols[3]:
1168
- st.markdown('<div class="achievement-badge">🚀</div>', unsafe_allow_html=True)
1169
- st.markdown("**Explorer**", help="Used 3 different heroes")
1170
- heroes_used = len(set([st.session_state.selected_character]))
1171
- st.markdown(f"{heroes_used}/3 heroes used")
1172
-
1173
- # Benefits section
1174
- st.markdown("""
1175
- ## ❤ Why Kids & Parents Love CodeTales
1176
-
1177
- | For Kids 👧👦 | For Parents & Teachers 👪👩‍🏫 |
1178
- |--------------|----------------------------|
1179
- | ✨ Create your own animated stories | 🧠 Teaches computational thinking |
1180
- | 🚀 See imagination come to life | 🔍 Develops problem-solving skills |
1181
- | 🎮 Interactive game creation | ➗ Reinforces STEM fundamentals |
1182
- | 😄 Fun characters and worlds | 🧩 Encourages logical reasoning |
1183
- | 🌟 Unlock new levels | 📈 Tracks learning progress |
1184
- | 💻 Real Python coding experience | 🎯 Aligned with coding curriculum |
1185
- """)
1186
-
1187
- # Footer
1188
- st.markdown("---")
1189
- st.markdown("""
1190
- <center>
1191
- <p style="color:white; font-size:1.1rem;">
1192
- ✨ Made with magic by CodeTales Team ✨<br>
1193
- Transforming stories into games since 2023
1194
- </p>
1195
- </center>
1196
- """, unsafe_allow_html=True)
 
1
+ # app.py - Hugging Face Compatible Version
2
  import streamlit as st
3
+ import requests
4
+ import json
5
  import time
6
+ import base64
7
  import random
8
+ from PIL import Image
9
+ import io
10
+ import matplotlib.pyplot as plt
11
+ import matplotlib.animation as animation
12
+ from matplotlib.animation import FuncAnimation
13
  import numpy as np
 
 
 
 
 
 
 
14
 
15
+ # Configure Streamlit page
16
  st.set_page_config(
17
+ page_title="StoryCoder - Learn Python Through Stories",
18
+ page_icon="🧙‍♂️",
19
  layout="wide",
20
  initial_sidebar_state="expanded"
21
  )
22
 
23
+ # Custom CSS for colorful UI
24
  st.markdown("""
25
  <style>
26
+ @import url('https://fonts.googleapis.com/css2?family=Comic+Neue:wght@700&display=swap');
27
+
28
+ :root {
29
+ --primary: #FF6B6B;
30
+ --secondary: #4ECDC4;
31
+ --accent: #FFD166;
32
+ --dark: #1A535C;
33
+ --light: #F7FFF7;
34
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ body {
37
+ background: linear-gradient(135deg, var(--light) 0%, #E8F4F8 100%);
38
+ font-family: 'Comic Neue', cursive;
39
+ }
40
 
41
+ .stApp {
42
+ background: url('https://www.transparenttextures.com/patterns/cartographer.png');
43
+ }
44
 
45
+ .story-box {
46
+ background-color: white;
47
+ border-radius: 20px;
48
+ padding: 25px;
49
+ box-shadow: 0 8px 16px rgba(26, 83, 92, 0.15);
50
+ border: 3px solid var(--accent);
51
+ margin-bottom: 25px;
52
+ }
53
 
54
+ .header {
55
+ color: var(--dark);
56
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
57
+ }
58
 
59
+ .concept-card {
60
+ background: linear-gradient(145deg, #ffffff, #f0f0f0);
61
+ border-radius: 15px;
62
+ padding: 15px;
63
+ margin: 10px 0;
64
+ border-left: 5px solid var(--secondary);
65
+ box-shadow: 0 4px 8px rgba(0,0,0,0.05);
66
+ }
67
 
68
+ .stButton>button {
69
+ background: linear-gradient(45deg, var(--primary), var(--secondary));
70
+ color: white;
71
+ border-radius: 12px;
72
+ padding: 10px 24px;
73
+ font-weight: bold;
74
+ font-size: 18px;
75
+ border: none;
76
+ transition: all 0.3s;
77
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
+ .stButton>button:hover {
80
+ transform: scale(1.05);
81
+ box-shadow: 0 6px 12px rgba(0,0,0,0.15);
82
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
+ .stTextInput>div>div>input {
85
+ border-radius: 12px;
86
+ padding: 12px;
87
+ border: 2px solid var(--accent);
88
+ }
 
 
 
 
 
89
 
90
+ .tabs {
91
+ display: flex;
92
+ gap: 10px;
93
+ margin-bottom: 20px;
94
+ overflow-x: auto;
95
+ }
96
 
97
+ .tab {
98
+ padding: 10px 20px;
99
+ background-color: var(--accent);
100
+ border-radius: 10px;
101
+ cursor: pointer;
102
+ font-weight: bold;
103
+ white-space: nowrap;
104
+ }
105
 
106
+ .tab.active {
107
+ background-color: var(--secondary);
108
+ color: white;
109
+ }
110
 
111
+ @media (max-width: 768px) {
112
+ .tabs {
113
+ flex-wrap: wrap;
114
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  }
116
+ </style>
117
+ """, unsafe_allow_html=True)
118
 
119
+ # Concept database
120
+ CONCEPTS = {
121
+ "loop": {
122
+ "name": "Loop",
123
+ "emoji": "🔄",
124
+ "description": "Loops repeat actions multiple times",
125
+ "example": "for i in range(5):\n print('Hello!')",
126
+ "color": "#FF9E6D"
127
+ },
128
+ "conditional": {
129
+ "name": "Conditional",
130
+ "emoji": "❓",
131
+ "description": "Conditionals make decisions in code",
132
+ "example": "if sunny:\n go_outside()\nelse:\n stay_inside()",
133
+ "color": "#4ECDC4"
134
+ },
135
+ "function": {
136
+ "name": "Function",
137
+ "emoji": "✨",
138
+ "description": "Functions are reusable blocks of code",
139
+ "example": "def greet(name):\n print(f'Hello {name}!')",
140
+ "color": "#FFD166"
141
+ },
142
+ "variable": {
143
+ "name": "Variable",
144
+ "emoji": "📦",
145
+ "description": "Variables store information",
146
+ "example": "score = 10\nplayer = 'Alex'",
147
+ "color": "#FF6B6B"
148
+ },
149
+ "list": {
150
+ "name": "List",
151
+ "emoji": "📝",
152
+ "description": "Lists store collections of items",
153
+ "example": "fruits = ['apple', 'banana', 'orange']",
154
+ "color": "#1A535C"
155
  }
156
+ }
157
 
158
+ # Free AI models via Hugging Face Inference API
159
+ HF_API_URL = "https://api-inference.huggingface.co/models/"
160
+ MODELS = {
161
+ "codegen": "Salesforce/codegen-350M-mono",
162
+ "story": "gpt2"
163
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
 
165
+ def analyze_story(story):
166
+ """Analyze story using simple NLP and identify programming concepts"""
167
+ story_lower = story.lower()
168
+ detected_concepts = []
 
 
 
 
 
 
169
 
170
+ # Check for loops
171
+ if any(word in story_lower for word in ["times", "repeat", "again", "multiple"]):
172
+ detected_concepts.append("loop")
 
 
173
 
174
+ # Check for conditionals
175
+ if any(word in story_lower for word in ["if", "when", "unless", "whether"]):
176
+ detected_concepts.append("conditional")
 
 
177
 
178
+ # Check for functions
179
+ if any(word in story_lower for word in ["make", "create", "do", "perform", "cast"]):
180
+ detected_concepts.append("function")
 
 
 
 
181
 
182
+ # Check for variables
183
+ if any(word in story_lower for word in ["is", "has", "set to", "value"]):
184
+ detected_concepts.append("variable")
185
+
186
+ # Check for lists
187
+ if any(word in story_lower for word in ["and", "many", "several", "collection", "items"]):
188
+ detected_concepts.append("list")
189
+
190
+ return list(set(detected_concepts))
 
 
 
 
 
 
 
 
 
 
 
191
 
192
+ def generate_animation_code(story, concepts):
193
+ """Generate Python animation code using free Hugging Face model"""
194
  try:
195
+ # For Hugging Face Spaces, we'll use a simplified approach
196
+ # since we can't run complex AI models for free
 
197
 
198
+ # Build a template-based code generator
199
+ characters = ["rabbit", "dragon", "cat", "dog", "knight", "wizard", "scientist", "pirate"]
200
+ actions = ["hop", "run", "fly", "jump", "cast", "collect", "change", "grow"]
 
 
 
 
 
 
201
 
202
+ character = random.choice(characters)
203
+ action = random.choice(actions)
204
+ count = random.randint(2, 5)
205
 
206
+ concept = concepts[0] if concepts else "loop"
 
 
 
 
 
207
 
208
+ if concept == "loop":
209
+ code = f"""# {story}
210
+ import matplotlib.pyplot as plt
211
+ import matplotlib.animation as animation
212
+ import numpy as np
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
 
214
+ fig, ax = plt.subplots(figsize=(8, 6))
215
+ ax.set_xlim(0, 10)
216
+ ax.set_ylim(0, 10)
217
+ ax.set_title('{" ".join(story.split()[:5])}...')
218
+ ax.set_facecolor('#f0f8ff')
219
+
220
+ {character}_x = [2]
221
+ {character}_y = [2]
222
+ {character}_dot, = ax.plot({character}_x, {character}_y, 'o', markersize=20, color='orange')
223
+
224
+ carrot_x = [8]
225
+ carrot_y = [8]
226
+ carrot_dot, = ax.plot(carrot_x, carrot_y, 'o', markersize=15, color='orange')
227
+
228
+ def animate(frame):
229
+ # This is a loop that runs {count} times
230
+ if frame < {count}:
231
+ # Move the {character} closer to the target
232
+ new_x = {character}_x[-1] + 1.5
233
+ new_y = {character}_y[-1] + 1.5
234
+ {character}_x.append(new_x)
235
+ {character}_y.append(new_y)
236
+ {character}_dot.set_data({character}_x[-1], {character}_y[-1])
237
+
238
+ return {character}_dot, carrot_dot
239
+
240
+ ani = animation.FuncAnimation(fig, animate, frames={count+1}, interval=1000)
241
+ plt.grid(True, linestyle='--', alpha=0.7)
242
+ plt.show()
243
+ """
244
+ elif concept == "conditional":
245
+ code = f"""# {story}
246
+ import matplotlib.pyplot as plt
247
+ import numpy as np
248
 
249
+ fig, ax = plt.subplots(figsize=(8, 6))
250
+ ax.set_xlim(0, 10)
251
+ ax.set_ylim(0, 10)
252
+ ax.set_title('{" ".join(story.split()[:5])}...')
253
+ ax.set_facecolor('#f0f8ff')
254
+
255
+ # This variable stores our condition
256
+ is_unlocked = {'True' if random.choice([True, False]) else 'False'}
257
+
258
+ # Draw treasure chest
259
+ chest = plt.Rectangle((4, 4), 2, 2, fill=True, color='brown')
260
+ ax.add_patch(chest)
261
+
262
+ # Draw lock if not unlocked
263
+ if not is_unlocked:
264
+ lock = plt.Rectangle((5, 6), 0.5, 0.8, fill=True, color='gray')
265
+ ax.add_patch(lock)
266
+ ax.text(5, 3, 'Locked! Find the key', fontsize=12, ha='center')
267
+ else:
268
+ # Show open chest with treasure
269
+ chest.set_fill(False)
270
+ chest.set_edgecolor('brown')
271
+ chest.set_linestyle('--')
272
+ ax.text(5, 5, '$$$', fontsize=20, ha='center')
273
+ ax.text(5, 3, 'Treasure Acquired!', fontsize=12, ha='center')
274
+
275
+ plt.grid(True, linestyle='--', alpha=0.7)
276
+ plt.show()
277
+ """
278
  else:
279
+ code = f"""# {story}
280
+ import matplotlib.pyplot as plt
281
+ import numpy as np
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
 
283
+ fig, ax = plt.subplots(figsize=(8, 6))
284
+ ax.set_xlim(0, 10)
285
+ ax.set_ylim(0, 10)
286
+ ax.set_title('{" ".join(story.split()[:5])}...')
287
+ ax.set_facecolor('#f0f8ff')
288
+
289
+ # Draw the scene
290
+ ax.text(5, 8, '✨ Your Story ✨', fontsize=20, ha='center')
291
+ ax.text(5, 7, f'"{story[:50]}{"..." if len(story) > 50 else ""}"',
292
+ fontsize=14, ha='center', wrap=True)
293
+
294
+ # Draw coding concept icons
295
+ y_pos = 5
296
+ for concept in {concepts}:
297
+ details = {CONCEPTS}[concept]
298
+ ax.text(2, y_pos, details['emoji'], fontsize=30, ha='center')
299
+ ax.text(5, y_pos, details['name'], fontsize=16, ha='left')
300
+ y_pos -= 1
301
+
302
+ ax.text(5, 2, 'Generated with Python!', fontsize=14, ha='center', style='italic')
303
+ plt.grid(True, linestyle='--', alpha=0.7)
304
+ plt.show()
305
+ """
 
 
 
 
 
 
 
 
 
306
 
307
+ return code
308
+ except Exception as e:
309
+ return f"# Error generating code\nprint('Could not generate code: {str(e)}')"
 
 
 
 
 
 
 
 
 
 
 
 
 
310
 
311
+ def create_matplotlib_animation(code):
312
+ """Create an animation using matplotlib"""
313
+ try:
314
+ # Create a namespace to execute the code
315
+ namespace = {}
316
+ exec(code, namespace)
 
 
 
 
 
 
 
 
 
 
317
 
318
+ # Get the figure from the executed code
319
+ fig = plt.gcf()
 
 
 
 
 
 
 
 
 
 
 
 
320
 
321
+ # Create a BytesIO object to save the animation
322
+ buf = io.BytesIO()
323
+ fig.savefig(buf, format='png')
324
+ buf.seek(0)
325
+ image = Image.open(buf)
326
 
327
+ return image
328
+ except Exception as e:
329
+ st.error(f"Animation error: {str(e)}")
330
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
331
 
332
+ def generate_story_image(story):
333
+ """Generate a story image using a free API"""
334
+ try:
335
+ # For Hugging Face deployment, we'll use placeholders
336
+ # In a real deployment, you could use Hugging Face's diffusion models
337
+
338
+ # Create a simple image with text
339
+ fig, ax = plt.subplots(figsize=(10, 6))
340
+ ax.set_facecolor('#f0f8ff')
341
+ ax.set_xlim(0, 10)
342
+ ax.set_ylim(0, 10)
343
+ ax.axis('off')
344
+
345
+ # Add title
346
+ ax.text(5, 8, '✨ Your Story ✨', fontsize=24,
347
+ ha='center', color='purple', fontweight='bold')
348
+
349
+ # Add story text (wrapped)
350
+ words = story.split()
351
+ lines = []
352
+ current_line = []
353
+
354
+ for word in words:
355
+ if len(' '.join(current_line + [word])) < 60:
356
+ current_line.append(word)
357
+ else:
358
+ lines.append(' '.join(current_line))
359
+ current_line = [word]
360
+
361
+ if current_line:
362
+ lines.append(' '.join(current_line))
363
+
364
+ for i, line in enumerate(lines):
365
+ ax.text(5, 6.5 - i*0.7, line, fontsize=14, ha='center')
366
+
367
+ # Add decoration
368
+ ax.text(2, 2, '🐰', fontsize=40, ha='center')
369
+ ax.text(8, 2, '🐉', fontsize=40, ha='center')
370
+ ax.text(5, 1, 'Created with StoryCoder', fontsize=12,
371
+ ha='center', style='italic', color='gray')
372
+
373
+ # Save to buffer
374
+ buf = io.BytesIO()
375
+ plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.5)
376
+ buf.seek(0)
377
+ image = Image.open(buf)
378
+ plt.close()
379
+
380
+ return image
381
+ except Exception as e:
382
+ st.error(f"Image generation error: {str(e)}")
383
+ return None
384
+
385
+ def main():
386
+ """Main application function"""
387
+ st.title("🧙‍♂️ StoryCoder - Learn Python Through Stories!")
388
+ st.subheader("Turn your story into an animation and discover coding secrets!")
389
+
390
+ # Initialize session state
391
+ if 'story' not in st.session_state:
392
+ st.session_state.story = ""
393
+ if 'concepts' not in st.session_state:
394
+ st.session_state.concepts = []
395
+ if 'animation_code' not in st.session_state:
396
+ st.session_state.animation_code = ""
397
+ if 'active_tab' not in st.session_state:
398
+ st.session_state.active_tab = "story"
399
+ if 'animation_image' not in st.session_state:
400
+ st.session_state.animation_image = None
401
+
402
+ # Create tabs
403
+ tabs = st.empty()
404
+ tab_cols = st.columns(5)
405
+ with tab_cols[0]:
406
+ if st.button("📖 Create Story"):
407
+ st.session_state.active_tab = "story"
408
+ with tab_cols[1]:
409
+ if st.button("🎬 Animation"):
410
+ st.session_state.active_tab = "animation"
411
+ with tab_cols[2]:
412
+ if st.button("🔍 Concepts"):
413
+ st.session_state.active_tab = "concepts"
414
+ with tab_cols[3]:
415
+ if st.button("💻 Code"):
416
+ st.session_state.active_tab = "code"
417
+ with tab_cols[4]:
418
+ if st.button("🔄 Reset"):
419
+ st.session_state.story = ""
420
+ st.session_state.concepts = []
421
+ st.session_state.animation_code = ""
422
+ st.session_state.animation_image = None
423
+ st.session_state.active_tab = "story"
424
+
425
+ # Story creation tab
426
+ if st.session_state.active_tab == "story":
427
+ with st.container():
428
+ st.header("📖 Create Your Story")
429
+ st.write("Write a short story (2-5 sentences) and I'll turn it into an animation!")
430
 
431
+ story = st.text_area(
432
+ "Your story:",
433
+ height=200,
434
+ placeholder="Once upon a time, a rabbit hopped 3 times to reach a carrot...",
435
+ value=st.session_state.story,
436
+ key="story_input"
437
+ )
438
 
439
+ if st.button("Create Animation!", use_container_width=True):
440
+ if len(story) < 10:
441
+ st.error("Your story needs to be at least 10 characters long!")
442
+ else:
443
+ st.session_state.story = story
444
+ with st.spinner("🧠 Analyzing your story for coding concepts..."):
445
+ st.session_state.concepts = analyze_story(story)
446
+
447
+ with st.spinner("✨ Generating animation code..."):
448
+ st.session_state.animation_code = generate_animation_code(
449
+ story, st.session_state.concepts
450
+ )
451
+
452
+ with st.spinner("🎨 Creating your animation..."):
453
+ st.session_state.animation_image = create_matplotlib_animation(
454
+ st.session_state.animation_code
455
+ )
456
+
457
+ st.session_state.active_tab = "animation"
458
+ st.experimental_rerun()
459
 
460
+ # Show examples
461
+ st.subheader("✨ Story Examples")
462
+ col1, col2, col3 = st.columns(3)
463
+ with col1:
464
+ st.caption("Loop Example")
465
+ st.code('"A dragon breathes fire 5 times at the castle"', language="text")
466
+ with col2:
467
+ st.caption("Conditional Example")
468
+ st.code('"If it rains, the cat stays inside, else it goes out"', language="text")
469
+ with col3:
470
+ st.caption("Function Example")
471
+ st.code('"A wizard casts a spell to make flowers grow"', language="text")
472
+
473
+ # Animation tab
474
+ elif st.session_state.active_tab == "animation":
475
+ st.header("🎬 Your Story Animation")
476
+
477
+ if not st.session_state.animation_image:
478
+ st.warning("Please create a story first!")
479
+ st.session_state.active_tab = "story"
480
+ st.experimental_rerun()
481
+
482
+ # Display animation
483
+ st.image(st.session_state.animation_image, use_column_width=True)
484
+
485
+ st.success("✨ Animation created successfully!")
486
+ st.caption("This animation was generated with Python code based on your story!")
487
+
488
+ if st.button("Reveal Coding Secrets!", use_container_width=True):
489
+ st.session_state.active_tab = "concepts"
490
+ st.experimental_rerun()
491
+
492
+ # Concepts tab
493
+ elif st.session_state.active_tab == "concepts":
494
+ st.header("🔍 Coding Concepts in Your Story")
495
+ st.subheader("We secretly used these programming concepts:")
496
+
497
+ if not st.session_state.concepts:
498
+ st.warning("No concepts detected in your story! Try adding words like '3 times', 'if', or 'make'.")
499
+ else:
500
+ for concept in st.session_state.concepts:
501
+ if concept in CONCEPTS:
502
+ details = CONCEPTS[concept]
503
+ st.markdown(f"""
504
+ <div class="concept-card" style="border-left: 5px solid {details['color']};">
505
+ <div style="display:flex; align-items:center; gap:15px;">
506
+ <span style="font-size:36px;">{details['emoji']}</span>
507
+ <h3 style="color:{details['color']};">{details['name']}</h3>
508
+ </div>
509
+ <p>{details['description']}</p>
510
+ <pre style="background:#f0f0f0; padding:10px; border-radius:8px;">{details['example']}</pre>
511
+ </div>
512
+ """, unsafe_allow_html=True)
513
+
514
+ if st.button("See the Magic Code!", use_container_width=True):
515
+ st.session_state.active_tab = "code"
516
+ st.experimental_rerun()
517
+
518
+ # Code tab
519
+ elif st.session_state.active_tab == "code":
520
+ st.header("💻 The Magic Code Behind Your Animation")
521
+ st.write("Here's the Python code that created your animation:")
522
+
523
+ if st.session_state.animation_code:
524
+ st.code(st.session_state.animation_code, language="python")
525
+
526
+ # Download button
527
+ st.download_button(
528
+ label="Download Animation Code",
529
+ data=st.session_state.animation_code,
530
+ file_name="story_animation.py",
531
+ mime="text/python",
532
+ use_container_width=True
533
+ )
534
+
535
+ st.write("You can run this code on your computer to see the animation!")
536
+ else:
537
+ st.warning("No code generated yet!")
538
 
539
+ if st.button("Create Another Story!", use_container_width=True):
540
+ st.session_state.active_tab = "story"
541
+ st.session_state.story = ""
542
+ st.experimental_rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
543
 
544
+ if __name__ == "__main__":
545
+ main()