Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -9,6 +9,10 @@ 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(
|
@@ -178,10 +182,37 @@ st.markdown("""
|
|
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 |
|
@@ -234,10 +265,10 @@ def create_storyboard_image(text, width=400, height=300):
|
|
234 |
|
235 |
return img
|
236 |
|
237 |
-
def generate_sprite_animation(story, character="spaceship", theme="space", num_frames=
|
238 |
"""Generate a sprite-based animation from story"""
|
239 |
frames = []
|
240 |
-
width, height =
|
241 |
|
242 |
for i in range(num_frames):
|
243 |
# Create base image with theme
|
@@ -245,14 +276,20 @@ def generate_sprite_animation(story, character="spaceship", theme="space", num_f
|
|
245 |
bg_color = (0, 0, 30)
|
246 |
star_color = (255, 255, 255)
|
247 |
elif theme == "jungle":
|
248 |
-
bg_color = (
|
249 |
-
star_color = None
|
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)
|
@@ -260,109 +297,391 @@ def generate_sprite_animation(story, character="spaceship", theme="space", num_f
|
|
260 |
img = Image.new('RGB', (width, height), color=bg_color)
|
261 |
draw = ImageDraw.Draw(img)
|
262 |
|
263 |
-
# Draw
|
264 |
-
if
|
265 |
-
|
|
|
266 |
x = random.randint(0, width)
|
267 |
y = random.randint(0, height)
|
268 |
draw.ellipse([x, y, x+2, y+2], fill=star_color)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
269 |
|
270 |
# Draw moving elements based on frame
|
271 |
if character == "spaceship":
|
272 |
-
ship_x = 50 + i *
|
273 |
-
ship_y =
|
274 |
-
|
275 |
-
|
|
|
|
|
|
|
276 |
|
277 |
if "shoot" in story.lower() and i > 1:
|
278 |
for j in range(3):
|
279 |
-
laser_x = ship_x +
|
280 |
-
laser_y = ship_y -
|
281 |
-
draw.line([(laser_x, laser_y), (width, laser_y)], fill=(255, 0, 0), width=
|
282 |
|
283 |
elif character == "dragon":
|
284 |
-
dragon_x = 50 + i *
|
285 |
-
dragon_y =
|
286 |
-
#
|
287 |
-
draw.ellipse([dragon_x, dragon_y, dragon_x+
|
288 |
-
#
|
289 |
-
draw.ellipse([dragon_x+
|
290 |
-
#
|
291 |
-
draw.ellipse([dragon_x+10, dragon_y-
|
292 |
|
293 |
if "fire" in story.lower() and i > 0:
|
294 |
for j in range(5):
|
295 |
-
flame_x = dragon_x +
|
296 |
-
flame_y = dragon_y +
|
297 |
-
flame_size = random.randint(
|
298 |
draw.ellipse([flame_x, flame_y, flame_x+flame_size, flame_y+flame_size],
|
299 |
fill=(255, random.randint(100, 200), 0))
|
300 |
|
301 |
elif character == "knight":
|
302 |
-
knight_x = 50 + i *
|
303 |
-
knight_y =
|
304 |
-
#
|
305 |
-
draw.rectangle([knight_x, knight_y, knight_x+
|
306 |
-
#
|
307 |
-
draw.ellipse([knight_x+5, knight_y-15, knight_x+
|
308 |
-
#
|
309 |
-
draw.
|
310 |
-
|
|
|
|
|
311 |
|
312 |
if "attack" in story.lower() and i % 2 == 1:
|
313 |
# Draw sword swing
|
314 |
-
draw.line([(knight_x+
|
315 |
|
316 |
elif character == "mermaid":
|
317 |
-
mermaid_x = 50 + i *
|
318 |
-
mermaid_y =
|
319 |
-
#
|
320 |
-
draw.ellipse([mermaid_x, mermaid_y, mermaid_x+
|
321 |
-
#
|
322 |
-
draw.ellipse([mermaid_x+
|
323 |
-
#
|
324 |
-
draw.ellipse([mermaid_x-
|
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,
|
330 |
-
bubble_y = mermaid_y - random.randint(
|
331 |
-
draw.ellipse([bubble_x, bubble_y, bubble_x+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
332 |
|
333 |
# Draw enemies based on theme
|
334 |
if theme == "space" and "alien" in story.lower():
|
335 |
-
alien_x =
|
336 |
-
alien_y =
|
337 |
-
draw.ellipse([alien_x, alien_y, alien_x+
|
338 |
-
draw.ellipse([alien_x+
|
339 |
-
draw.ellipse([alien_x+
|
|
|
340 |
|
341 |
elif theme == "jungle" and "snake" in story.lower():
|
342 |
-
snake_x =
|
343 |
-
snake_y =
|
344 |
-
for segment in range(
|
345 |
-
offset = segment *
|
346 |
-
draw.ellipse([snake_x+offset, snake_y+offset, snake_x+offset+
|
347 |
|
348 |
elif theme == "medieval" and "dragon" in story.lower() and character != "dragon":
|
349 |
-
dragon_x =
|
350 |
-
dragon_y =
|
351 |
-
draw.ellipse([dragon_x, dragon_y, dragon_x+
|
352 |
-
draw.line([(dragon_x+
|
353 |
|
354 |
elif theme == "underwater" and "shark" in story.lower():
|
355 |
-
shark_x =
|
356 |
-
shark_y =
|
357 |
-
#
|
358 |
-
draw.ellipse([shark_x, shark_y, shark_x+
|
359 |
-
#
|
360 |
-
draw.polygon([(shark_x+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
361 |
|
362 |
frames.append(img)
|
363 |
|
364 |
return frames
|
365 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
366 |
def generate_code_explanation(story, explanation_generator):
|
367 |
"""Generate code explanation using open-source model"""
|
368 |
try:
|
@@ -391,14 +710,16 @@ def extract_story_elements(story, ner_model, classifier):
|
|
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()
|
@@ -419,6 +740,10 @@ def extract_story_elements(story, ner_model, classifier):
|
|
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)
|
@@ -429,10 +754,14 @@ def extract_story_elements(story, ner_model, classifier):
|
|
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 |
|
@@ -440,6 +769,16 @@ def extract_story_elements(story, ner_model, classifier):
|
|
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)
|
@@ -483,20 +822,28 @@ 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
|
@@ -540,25 +887,41 @@ with col1:
|
|
540 |
st.markdown(f'<div class="world-suggestion">Your World: {themes[st.session_state.selected_theme]}</div>',
|
541 |
unsafe_allow_html=True)
|
542 |
|
543 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
552 |
character=st.session_state.selected_character,
|
553 |
-
theme=st.session_state.selected_theme
|
|
|
554 |
)
|
555 |
|
556 |
# Generate code explanation
|
557 |
st.session_state.code_explanation = generate_code_explanation(story_text, explanation_generator)
|
558 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
559 |
# Update user progress
|
560 |
st.session_state.story_count += 1
|
561 |
-
st.session_state.xp +=
|
562 |
|
563 |
# Check for level up
|
564 |
if st.session_state.xp >= 100:
|
@@ -575,12 +938,8 @@ with col2:
|
|
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))
|
579 |
-
for i, frame in enumerate(st.session_state.animation_frames):
|
580 |
-
with cols[i]:
|
581 |
-
st.image(frame, caption=f"Frame {i+1}", use_container_width=True)
|
582 |
|
583 |
-
#
|
584 |
gif_buffer = BytesIO()
|
585 |
st.session_state.animation_frames[0].save(
|
586 |
gif_buffer,
|
@@ -590,10 +949,13 @@ with col2:
|
|
590 |
duration=500,
|
591 |
loop=0
|
592 |
)
|
593 |
-
|
|
|
|
|
|
|
594 |
st.download_button(
|
595 |
label="โฌ๏ธ Download Animation",
|
596 |
-
data=
|
597 |
file_name="your_story.gif",
|
598 |
mime="image/gif",
|
599 |
use_container_width=True
|
@@ -606,7 +968,7 @@ with col2:
|
|
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)
|
@@ -619,65 +981,161 @@ with col2:
|
|
619 |
|
620 |
st.markdown('</div>', unsafe_allow_html=True)
|
621 |
|
622 |
-
#
|
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 |
-
#
|
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 |
-
|
676 |
-
st.
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
681 |
|
682 |
st.markdown("</div>", unsafe_allow_html=True)
|
683 |
|
@@ -687,6 +1145,30 @@ if 'new_level' in st.session_state and st.session_state.new_level:
|
|
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
|
@@ -698,6 +1180,7 @@ st.markdown("""
|
|
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
|
|
|
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(
|
|
|
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 |
|
|
|
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
|
|
|
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)
|
|
|
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:
|
|
|
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()
|
|
|
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)
|
|
|
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 |
|
|
|
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)
|
|
|
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
|
|
|
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:
|
|
|
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,
|
|
|
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
|
|
|
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)
|
|
|
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 |
+
with st.expander("3. Making Your Hero Move"):
|
1041 |
+
st.markdown("""
|
1042 |
+
We'll use keyboard input to move the hero:
|
1043 |
+
```python
|
1044 |
+
hero_speed = 5
|
1045 |
+
|
1046 |
+
# Inside the game loop
|
1047 |
+
keys = pygame.key.get_pressed()
|
1048 |
+
if keys[pygame.K_LEFT]:
|
1049 |
+
hero_x -= hero_speed
|
1050 |
+
if keys[pygame.K_RIGHT]:
|
1051 |
+
hero_x += hero_speed
|
1052 |
+
if keys[pygame.K_UP]:
|
1053 |
+
hero_y -= hero_speed
|
1054 |
+
if keys[pygame.K_DOWN]:
|
1055 |
+
hero_y += hero_speed
|
1056 |
+
```
|
1057 |
+
""")
|
1058 |
+
|
1059 |
+
with st.expander("4. Adding Your Story Elements"):
|
1060 |
+
story_elements = []
|
1061 |
+
if "alien" in st.session_state.story_text.lower():
|
1062 |
+
story_elements.append("Aliens")
|
1063 |
+
if "dragon" in st.session_state.story_text.lower():
|
1064 |
+
story_elements.append("Dragons")
|
1065 |
+
if "treasure" in st.session_state.story_text.lower():
|
1066 |
+
story_elements.append("Treasure")
|
1067 |
+
|
1068 |
+
if story_elements:
|
1069 |
+
elements = ", ".join(story_elements)
|
1070 |
+
st.markdown(f"""
|
1071 |
+
Let's add {elements} from your story:
|
1072 |
+
```python
|
1073 |
+
def draw_story_elements():
|
1074 |
+
{get_story_elements_code(st.session_state.story_text, st.session_state.selected_theme).replace('\n', '\n ')}
|
1075 |
+
```
|
1076 |
+
""")
|
1077 |
+
else:
|
1078 |
+
st.markdown("""
|
1079 |
+
Add your own story elements with drawing commands:
|
1080 |
+
```python
|
1081 |
+
# Example: Draw a treasure chest
|
1082 |
+
pygame.draw.rect(screen, (255, 215, 0), (700, 400, 30, 20))
|
1083 |
+
pygame.draw.rect(screen, (255, 215, 0), (705, 395, 20, 10))
|
1084 |
+
```
|
1085 |
+
""")
|
1086 |
+
|
1087 |
+
with st.expander("5. Running Your Game"):
|
1088 |
+
st.markdown("""
|
1089 |
+
Finally, we put everything together in a game loop:
|
1090 |
+
```python
|
1091 |
+
# Main game loop
|
1092 |
+
clock = pygame.time.Clock()
|
1093 |
+
running = True
|
1094 |
+
|
1095 |
+
while running:
|
1096 |
+
# Handle events
|
1097 |
+
for event in pygame.event.get():
|
1098 |
+
if event.type == pygame.QUIT:
|
1099 |
+
running = False
|
1100 |
+
|
1101 |
+
# Handle movement
|
1102 |
+
# ... (movement code from step 3)
|
1103 |
+
|
1104 |
+
# Draw everything
|
1105 |
+
screen.fill(BACKGROUND)
|
1106 |
+
draw_hero()
|
1107 |
+
draw_story_elements()
|
1108 |
+
|
1109 |
+
# Update the display
|
1110 |
+
pygame.display.flip()
|
1111 |
+
clock.tick(60)
|
1112 |
+
|
1113 |
+
pygame.quit()
|
1114 |
+
sys.exit()
|
1115 |
+
```
|
1116 |
+
""")
|
1117 |
+
|
1118 |
+
st.markdown("</div>", unsafe_allow_html=True)
|
1119 |
+
|
1120 |
+
# Code Playground
|
1121 |
+
if st.session_state.animation_generated:
|
1122 |
+
st.markdown('<div class="code-playground">', unsafe_allow_html=True)
|
1123 |
+
st.markdown("### ๐งช Step 5: Code Playground")
|
1124 |
+
st.markdown("Try modifying your code and see the changes!")
|
1125 |
+
|
1126 |
+
# Editable code area
|
1127 |
+
modified_code = st.text_area(
|
1128 |
+
"Edit your Python code:",
|
1129 |
+
value=st.session_state.pygame_code,
|
1130 |
+
height=300,
|
1131 |
+
key="code_editor"
|
1132 |
+
)
|
1133 |
+
|
1134 |
+
# Run the modified code
|
1135 |
+
if st.button("๐ Run My Modified Code", key="run_modified_code"):
|
1136 |
+
with st.spinner("Running your code..."):
|
1137 |
+
temp_file = run_pygame_code(modified_code)
|
1138 |
+
st.success("Game launched with your modifications!")
|
1139 |
|
1140 |
st.markdown("</div>", unsafe_allow_html=True)
|
1141 |
|
|
|
1145 |
st.success(f"๐ Level Up! You're now Level {st.session_state.level}!")
|
1146 |
st.session_state.new_level = False
|
1147 |
|
1148 |
+
# Achievements
|
1149 |
+
st.markdown("### ๐ Your Achievements")
|
1150 |
+
achievement_cols = st.columns(4)
|
1151 |
+
with achievement_cols[0]:
|
1152 |
+
st.markdown('<div class="achievement-badge">๐</div>', unsafe_allow_html=True)
|
1153 |
+
st.markdown("**Storyteller**", help="Created your first story")
|
1154 |
+
st.markdown(f"{st.session_state.story_count} story created")
|
1155 |
+
|
1156 |
+
with achievement_cols[1]:
|
1157 |
+
st.markdown('<div class="achievement-badge">๐พ</div>', unsafe_allow_html=True)
|
1158 |
+
st.markdown("**Animator**", help="Generated 5 animations")
|
1159 |
+
st.markdown(f"{min(st.session_state.story_count, 5)}/5 animations")
|
1160 |
+
|
1161 |
+
with achievement_cols[2]:
|
1162 |
+
st.markdown('<div class="achievement-badge">๐ป</div>', unsafe_allow_html=True)
|
1163 |
+
st.markdown("**Coder**", help="Modified and ran code")
|
1164 |
+
st.markdown("Unlocked!" if st.session_state.animation_generated else "Locked")
|
1165 |
+
|
1166 |
+
with achievement_cols[3]:
|
1167 |
+
st.markdown('<div class="achievement-badge">๐</div>', unsafe_allow_html=True)
|
1168 |
+
st.markdown("**Explorer**", help="Used 3 different heroes")
|
1169 |
+
heroes_used = len(set([st.session_state.selected_character]))
|
1170 |
+
st.markdown(f"{heroes_used}/3 heroes used")
|
1171 |
+
|
1172 |
# Benefits section
|
1173 |
st.markdown("""
|
1174 |
## โค Why Kids & Parents Love CodeTales
|
|
|
1180 |
| ๐ฎ Interactive game creation | โ Reinforces STEM fundamentals |
|
1181 |
| ๐ Fun characters and worlds | ๐งฉ Encourages logical reasoning |
|
1182 |
| ๐ Unlock new levels | ๐ Tracks learning progress |
|
1183 |
+
| ๐ป Real Python coding experience | ๐ฏ Aligned with coding curriculum |
|
1184 |
""")
|
1185 |
|
1186 |
# Footer
|