Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,15 +1,15 @@
|
|
1 |
-
# app.py - Final Working Version
|
2 |
import streamlit as st
|
3 |
import os
|
4 |
import time
|
5 |
import random
|
6 |
import numpy as np
|
7 |
import matplotlib.pyplot as plt
|
8 |
-
from matplotlib.animation import FuncAnimation
|
9 |
-
from matplotlib import rc
|
10 |
import base64
|
11 |
from PIL import Image
|
12 |
import io
|
|
|
|
|
13 |
|
14 |
# Configure Streamlit page
|
15 |
st.set_page_config(
|
@@ -190,6 +190,90 @@ CHARACTERS = [
|
|
190 |
{"name": "pirate", "emoji": "π΄ββ οΈ", "color": "#FFA500"}
|
191 |
]
|
192 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
193 |
def analyze_story(story):
|
194 |
"""Analyze story and identify programming concepts"""
|
195 |
story_lower = story.lower()
|
@@ -225,84 +309,146 @@ def extract_count_from_story(story):
|
|
225 |
return 3 # Default value
|
226 |
|
227 |
def create_animation(story, concepts):
|
228 |
-
"""Create
|
229 |
try:
|
230 |
# Choose a random character
|
231 |
character = random.choice(CHARACTERS)
|
232 |
count = extract_count_from_story(story)
|
233 |
|
234 |
-
# Create figure
|
235 |
-
fig, ax = plt.subplots(figsize=(10, 6)
|
|
|
236 |
ax.set_xlim(0, 10)
|
237 |
ax.set_ylim(0, 10)
|
238 |
ax.axis('off')
|
239 |
|
240 |
# Add title
|
241 |
-
|
|
|
242 |
|
243 |
# Add story text
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
254 |
|
255 |
-
#
|
256 |
-
|
257 |
-
|
258 |
-
ax.plot(target_x, target_y, 'ro', markersize=15, alpha=0.5)
|
259 |
-
ax.text(target_x, target_y - 0.8, 'Target', ha='center', fontsize=12)
|
260 |
|
261 |
-
#
|
262 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
|
264 |
-
#
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
|
|
|
|
288 |
|
289 |
-
#
|
290 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
291 |
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
|
297 |
-
|
298 |
-
|
299 |
|
300 |
-
return
|
301 |
|
302 |
except Exception as e:
|
303 |
-
st.error(f"
|
304 |
return None
|
305 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
306 |
def create_story_image(story):
|
307 |
"""Create a story image with Matplotlib"""
|
308 |
try:
|
@@ -343,7 +489,7 @@ def create_story_image(story):
|
|
343 |
|
344 |
# Save to buffer
|
345 |
buf = io.BytesIO()
|
346 |
-
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.5, dpi=
|
347 |
buf.seek(0)
|
348 |
plt.close()
|
349 |
return buf
|
@@ -364,6 +510,12 @@ def main():
|
|
364 |
st.session_state.concepts = []
|
365 |
if 'animation' not in st.session_state:
|
366 |
st.session_state.animation = None
|
|
|
|
|
|
|
|
|
|
|
|
|
367 |
if 'active_tab' not in st.session_state:
|
368 |
st.session_state.active_tab = "story"
|
369 |
|
@@ -387,6 +539,9 @@ def main():
|
|
387 |
st.session_state.story = ""
|
388 |
st.session_state.concepts = []
|
389 |
st.session_state.animation = None
|
|
|
|
|
|
|
390 |
st.session_state.active_tab = "story"
|
391 |
|
392 |
# Story creation tab
|
@@ -415,6 +570,14 @@ def main():
|
|
415 |
st.session_state.animation = create_animation(
|
416 |
story, st.session_state.concepts
|
417 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
418 |
|
419 |
st.session_state.active_tab = "animation"
|
420 |
st.rerun()
|
@@ -448,14 +611,23 @@ def main():
|
|
448 |
</div>
|
449 |
""", unsafe_allow_html=True)
|
450 |
|
|
|
451 |
if st.session_state.animation:
|
452 |
st.image(st.session_state.animation, use_container_width=True)
|
453 |
else:
|
454 |
-
st.warning("
|
455 |
story_img = create_story_image(st.session_state.story)
|
456 |
if story_img:
|
457 |
st.image(story_img, use_container_width=True)
|
458 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
459 |
st.success("β¨ Animation created successfully!")
|
460 |
st.caption("This animation was generated with Python code based on your story!")
|
461 |
|
@@ -492,81 +664,32 @@ def main():
|
|
492 |
# Code tab
|
493 |
elif st.session_state.active_tab == "code":
|
494 |
st.header("π» The Magic Code Behind Your Animation")
|
495 |
-
st.write("Here's the Python code that
|
496 |
-
|
497 |
-
# Sample code (in a real app, you would generate this based on the story)
|
498 |
-
count = extract_count_from_story(st.session_state.story)
|
499 |
-
character = random.choice(CHARACTERS)
|
500 |
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
import matplotlib.pyplot as plt
|
505 |
-
from matplotlib.animation import FuncAnimation
|
506 |
-
import numpy as np
|
507 |
-
|
508 |
-
# Setup the figure
|
509 |
-
fig, ax = plt.subplots(figsize=(10, 6))
|
510 |
-
ax.set_xlim(0, 10)
|
511 |
-
ax.set_ylim(0, 10)
|
512 |
-
ax.axis('off')
|
513 |
-
|
514 |
-
# Add story text
|
515 |
-
ax.text(5, 9, "{st.session_state.story[:50]}{'...' if len(st.session_state.story) > 50 else ''}",
|
516 |
-
fontsize=14, ha='center', wrap=True)
|
517 |
-
|
518 |
-
# Add character
|
519 |
-
char = ax.text(5, 6, "{character['emoji']}", fontsize=48, ha='center', color='{character['color']}')
|
520 |
-
|
521 |
-
# Add target
|
522 |
-
ax.plot(8, 6, 'ro', markersize=15, alpha=0.5)
|
523 |
-
ax.text(8, 5.2, 'Target', ha='center', fontsize=12)
|
524 |
-
|
525 |
-
# Add counter
|
526 |
-
counter = ax.text(2, 8, 'Hops: 0/{count}', fontsize=16)
|
527 |
-
|
528 |
-
# Animation function
|
529 |
-
def animate(frame):
|
530 |
-
x = char.get_position()[0]
|
531 |
-
|
532 |
-
# Move character toward target
|
533 |
-
if frame < {count}:
|
534 |
-
new_x = x + 0.3
|
535 |
-
|
536 |
-
# Hop animation
|
537 |
-
if frame % 2 == 0:
|
538 |
-
new_y = 6.5
|
539 |
-
else:
|
540 |
-
new_y = 6
|
541 |
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
label="Download Animation Code",
|
563 |
-
data=sample_code,
|
564 |
-
file_name="story_animation.py",
|
565 |
-
mime="text/python",
|
566 |
-
use_container_width=True
|
567 |
-
)
|
568 |
-
|
569 |
-
st.write("You can run this code on your computer to create similar animations!")
|
570 |
|
571 |
if st.button("Create Another Story!", use_container_width=True):
|
572 |
st.session_state.active_tab = "story"
|
|
|
1 |
+
# app.py - Final Working Version with Animation
|
2 |
import streamlit as st
|
3 |
import os
|
4 |
import time
|
5 |
import random
|
6 |
import numpy as np
|
7 |
import matplotlib.pyplot as plt
|
|
|
|
|
8 |
import base64
|
9 |
from PIL import Image
|
10 |
import io
|
11 |
+
import pandas as pd
|
12 |
+
import plotly.express as px
|
13 |
|
14 |
# Configure Streamlit page
|
15 |
st.set_page_config(
|
|
|
190 |
{"name": "pirate", "emoji": "π΄ββ οΈ", "color": "#FFA500"}
|
191 |
]
|
192 |
|
193 |
+
# Animation templates
|
194 |
+
ANIMATION_TEMPLATES = {
|
195 |
+
"loop": {
|
196 |
+
"description": "Character moving to a target multiple times",
|
197 |
+
"code": """
|
198 |
+
# Loop Animation
|
199 |
+
import matplotlib.pyplot as plt
|
200 |
+
import numpy as np
|
201 |
+
|
202 |
+
fig, ax = plt.subplots(figsize=(10, 6))
|
203 |
+
ax.set_xlim(0, 10)
|
204 |
+
ax.set_ylim(0, 10)
|
205 |
+
ax.axis('off')
|
206 |
+
|
207 |
+
character = ax.text(1, 5, "{emoji}", fontsize=48, color='{color}')
|
208 |
+
target = ax.text(9, 5, "π―", fontsize=48)
|
209 |
+
ax.text(5, 9, "{story}", ha='center', fontsize=14)
|
210 |
+
|
211 |
+
for i in range({count}):
|
212 |
+
for pos in np.linspace(1, 9, 20):
|
213 |
+
character.set_position((pos, 5))
|
214 |
+
plt.pause(0.05)
|
215 |
+
plt.show()
|
216 |
+
"""
|
217 |
+
},
|
218 |
+
"conditional": {
|
219 |
+
"description": "Character making a decision based on a condition",
|
220 |
+
"code": """
|
221 |
+
# Conditional Animation
|
222 |
+
import matplotlib.pyplot as plt
|
223 |
+
import numpy as np
|
224 |
+
|
225 |
+
fig, ax = plt.subplots(figsize=(10, 6))
|
226 |
+
ax.set_xlim(0, 10)
|
227 |
+
ax.set_ylim(0, 10)
|
228 |
+
ax.axis('off')
|
229 |
+
|
230 |
+
character = ax.text(5, 5, "{emoji}", fontsize=48, color='{color}')
|
231 |
+
ax.text(5, 9, "{story}", ha='center', fontsize=14)
|
232 |
+
|
233 |
+
# Condition: {condition}
|
234 |
+
if {condition}:
|
235 |
+
decision = ax.text(7, 7, "β
Yes", fontsize=24, color='green')
|
236 |
+
path = np.linspace(5, 8, 20)
|
237 |
+
else:
|
238 |
+
decision = ax.text(7, 7, "β No", fontsize=24, color='red')
|
239 |
+
path = np.linspace(5, 2, 20)
|
240 |
+
|
241 |
+
for pos in path:
|
242 |
+
character.set_position((pos, 5))
|
243 |
+
plt.pause(0.05)
|
244 |
+
plt.show()
|
245 |
+
"""
|
246 |
+
},
|
247 |
+
"function": {
|
248 |
+
"description": "Character performing an action multiple times",
|
249 |
+
"code": """
|
250 |
+
# Function Animation
|
251 |
+
import matplotlib.pyplot as plt
|
252 |
+
import numpy as np
|
253 |
+
|
254 |
+
fig, ax = plt.subplots(figsize=(10, 6))
|
255 |
+
ax.set_xlim(0, 10)
|
256 |
+
ax.set_ylim(0, 10)
|
257 |
+
ax.axis('off')
|
258 |
+
|
259 |
+
character = ax.text(5, 5, "{emoji}", fontsize=48, color='{color}')
|
260 |
+
ax.text(5, 9, "{story}", ha='center', fontsize=14)
|
261 |
+
|
262 |
+
def perform_action():
|
263 |
+
for _ in range(5):
|
264 |
+
character.set_fontsize(60)
|
265 |
+
plt.pause(0.1)
|
266 |
+
character.set_fontsize(48)
|
267 |
+
plt.pause(0.1)
|
268 |
+
|
269 |
+
for i in range({count}):
|
270 |
+
perform_action()
|
271 |
+
character.set_position((5 + i, 5))
|
272 |
+
plt.show()
|
273 |
+
"""
|
274 |
+
}
|
275 |
+
}
|
276 |
+
|
277 |
def analyze_story(story):
|
278 |
"""Analyze story and identify programming concepts"""
|
279 |
story_lower = story.lower()
|
|
|
309 |
return 3 # Default value
|
310 |
|
311 |
def create_animation(story, concepts):
|
312 |
+
"""Create an animation visualization based on the story and concepts"""
|
313 |
try:
|
314 |
# Choose a random character
|
315 |
character = random.choice(CHARACTERS)
|
316 |
count = extract_count_from_story(story)
|
317 |
|
318 |
+
# Create figure
|
319 |
+
fig, ax = plt.subplots(figsize=(10, 6))
|
320 |
+
ax.set_facecolor('#f0f8ff')
|
321 |
ax.set_xlim(0, 10)
|
322 |
ax.set_ylim(0, 10)
|
323 |
ax.axis('off')
|
324 |
|
325 |
# Add title
|
326 |
+
ax.text(5, 9, 'β¨ Your Story Animation β¨',
|
327 |
+
fontsize=20, ha='center', color='purple', fontweight='bold')
|
328 |
|
329 |
# Add story text
|
330 |
+
story_text = story[:80] + ('...' if len(story) > 80 else '')
|
331 |
+
ax.text(5, 8, f'"{story_text}"',
|
332 |
+
fontsize=14, ha='center', color='#333')
|
333 |
+
|
334 |
+
# Add character
|
335 |
+
ax.text(5, 5, character["emoji"],
|
336 |
+
fontsize=100, ha='center', color=character["color"])
|
337 |
+
|
338 |
+
# Add concept visualization
|
339 |
+
if "loop" in concepts:
|
340 |
+
ax.text(5, 3, f"π Repeating {count} times",
|
341 |
+
fontsize=18, ha='center', color=CONCEPTS["loop"]["color"])
|
342 |
+
elif "conditional" in concepts:
|
343 |
+
condition = random.choice(["sunny", "raining", "dark"])
|
344 |
+
ax.text(5, 3, f"β Checking if it's {condition}",
|
345 |
+
fontsize=18, ha='center', color=CONCEPTS["conditional"]["color"])
|
346 |
+
elif "function" in concepts:
|
347 |
+
ax.text(5, 3, f"β¨ Performing action {count} times",
|
348 |
+
fontsize=18, ha='center', color=CONCEPTS["function"]["color"])
|
349 |
+
else:
|
350 |
+
ax.text(5, 3, "π Creating your story visualization",
|
351 |
+
fontsize=18, ha='center', color=CONCEPTS["variable"]["color"])
|
352 |
|
353 |
+
# Add footer
|
354 |
+
ax.text(5, 1, "Created with StoryCoder",
|
355 |
+
fontsize=12, ha='center', style='italic', color='gray')
|
|
|
|
|
356 |
|
357 |
+
# Save to buffer
|
358 |
+
buf = io.BytesIO()
|
359 |
+
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.5, dpi=150)
|
360 |
+
buf.seek(0)
|
361 |
+
plt.close()
|
362 |
+
return buf
|
363 |
+
|
364 |
+
except Exception as e:
|
365 |
+
st.error(f"Animation error: {str(e)}")
|
366 |
+
return None
|
367 |
+
|
368 |
+
def create_interactive_animation(story, concepts):
|
369 |
+
"""Create an interactive animation using Plotly"""
|
370 |
+
try:
|
371 |
+
# Choose a random character
|
372 |
+
character = random.choice(CHARACTERS)
|
373 |
+
count = extract_count_from_story(story)
|
374 |
|
375 |
+
# Create animation data
|
376 |
+
frames = []
|
377 |
+
for i in range(count):
|
378 |
+
frames.append({
|
379 |
+
"frame": i,
|
380 |
+
"x": np.random.uniform(1, 9),
|
381 |
+
"y": np.random.uniform(1, 9),
|
382 |
+
"size": np.random.uniform(10, 30),
|
383 |
+
"character": character["emoji"]
|
384 |
+
})
|
385 |
+
|
386 |
+
df = pd.DataFrame(frames)
|
387 |
+
|
388 |
+
# Create animated scatter plot
|
389 |
+
fig = px.scatter(
|
390 |
+
df,
|
391 |
+
x="x",
|
392 |
+
y="y",
|
393 |
+
animation_frame="frame",
|
394 |
+
text="character",
|
395 |
+
size="size",
|
396 |
+
size_max=45,
|
397 |
+
color_discrete_sequence=[character["color"]],
|
398 |
+
range_x=[0, 10],
|
399 |
+
range_y=[0, 10]
|
400 |
+
)
|
401 |
|
402 |
+
# Customize layout
|
403 |
+
fig.update_layout(
|
404 |
+
title=f'Animation for: "{story[:50]}{"..." if len(story) > 50 else ""}"',
|
405 |
+
showlegend=False,
|
406 |
+
plot_bgcolor='rgba(240,248,255,1)',
|
407 |
+
paper_bgcolor='rgba(240,248,255,1)',
|
408 |
+
width=800,
|
409 |
+
height=600
|
410 |
+
)
|
411 |
|
412 |
+
fig.update_traces(
|
413 |
+
textfont_size=30,
|
414 |
+
textposition='middle center'
|
415 |
+
)
|
416 |
|
417 |
+
fig.layout.updatemenus[0].buttons[0].args[1]["frame"]["duration"] = 1000
|
418 |
+
fig.layout.updatemenus[0].buttons[0].args[1]["transition"]["duration"] = 500
|
419 |
|
420 |
+
return fig
|
421 |
|
422 |
except Exception as e:
|
423 |
+
st.error(f"Interactive animation error: {str(e)}")
|
424 |
return None
|
425 |
|
426 |
+
def generate_animation_code(story, concepts):
|
427 |
+
"""Generate Python animation code based on story"""
|
428 |
+
try:
|
429 |
+
# Choose a random character
|
430 |
+
character = random.choice(CHARACTERS)
|
431 |
+
count = extract_count_from_story(story)
|
432 |
+
concept = concepts[0] if concepts else "loop"
|
433 |
+
|
434 |
+
# Get the appropriate template
|
435 |
+
template = ANIMATION_TEMPLATES.get(concept, ANIMATION_TEMPLATES["loop"])
|
436 |
+
|
437 |
+
# Fill in the template
|
438 |
+
condition = random.choice(["True", "False"])
|
439 |
+
code = template["code"].format(
|
440 |
+
emoji=character["emoji"],
|
441 |
+
color=character["color"],
|
442 |
+
story=story[:80] + ('...' if len(story) > 80 else ''),
|
443 |
+
count=count,
|
444 |
+
condition=condition
|
445 |
+
)
|
446 |
+
|
447 |
+
return code, template["description"]
|
448 |
+
|
449 |
+
except Exception as e:
|
450 |
+
return f"# Error generating code\nprint('Could not generate code: {str(e)}')", ""
|
451 |
+
|
452 |
def create_story_image(story):
|
453 |
"""Create a story image with Matplotlib"""
|
454 |
try:
|
|
|
489 |
|
490 |
# Save to buffer
|
491 |
buf = io.BytesIO()
|
492 |
+
plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0.5, dpi=150)
|
493 |
buf.seek(0)
|
494 |
plt.close()
|
495 |
return buf
|
|
|
510 |
st.session_state.concepts = []
|
511 |
if 'animation' not in st.session_state:
|
512 |
st.session_state.animation = None
|
513 |
+
if 'interactive_animation' not in st.session_state:
|
514 |
+
st.session_state.interactive_animation = None
|
515 |
+
if 'animation_code' not in st.session_state:
|
516 |
+
st.session_state.animation_code = ""
|
517 |
+
if 'code_description' not in st.session_state:
|
518 |
+
st.session_state.code_description = ""
|
519 |
if 'active_tab' not in st.session_state:
|
520 |
st.session_state.active_tab = "story"
|
521 |
|
|
|
539 |
st.session_state.story = ""
|
540 |
st.session_state.concepts = []
|
541 |
st.session_state.animation = None
|
542 |
+
st.session_state.interactive_animation = None
|
543 |
+
st.session_state.animation_code = ""
|
544 |
+
st.session_state.code_description = ""
|
545 |
st.session_state.active_tab = "story"
|
546 |
|
547 |
# Story creation tab
|
|
|
570 |
st.session_state.animation = create_animation(
|
571 |
story, st.session_state.concepts
|
572 |
)
|
573 |
+
|
574 |
+
st.session_state.interactive_animation = create_interactive_animation(
|
575 |
+
story, st.session_state.concepts
|
576 |
+
)
|
577 |
+
|
578 |
+
st.session_state.animation_code, st.session_state.code_description = generate_animation_code(
|
579 |
+
story, st.session_state.concepts
|
580 |
+
)
|
581 |
|
582 |
st.session_state.active_tab = "animation"
|
583 |
st.rerun()
|
|
|
611 |
</div>
|
612 |
""", unsafe_allow_html=True)
|
613 |
|
614 |
+
# Display static animation
|
615 |
if st.session_state.animation:
|
616 |
st.image(st.session_state.animation, use_container_width=True)
|
617 |
else:
|
618 |
+
st.warning("Static animation couldn't be generated. Showing story image instead.")
|
619 |
story_img = create_story_image(st.session_state.story)
|
620 |
if story_img:
|
621 |
st.image(story_img, use_container_width=True)
|
622 |
|
623 |
+
# Display interactive animation
|
624 |
+
st.subheader("π Interactive Animation")
|
625 |
+
if st.session_state.interactive_animation:
|
626 |
+
st.plotly_chart(st.session_state.interactive_animation, use_container_width=True)
|
627 |
+
else:
|
628 |
+
st.info("Interactive animation preview. The real animation would run on your computer!")
|
629 |
+
st.image("https://i.imgur.com/5X8jYAy.gif", use_container_width=True)
|
630 |
+
|
631 |
st.success("β¨ Animation created successfully!")
|
632 |
st.caption("This animation was generated with Python code based on your story!")
|
633 |
|
|
|
664 |
# Code tab
|
665 |
elif st.session_state.active_tab == "code":
|
666 |
st.header("π» The Magic Code Behind Your Animation")
|
667 |
+
st.write("Here's the Python code that would create your animation:")
|
|
|
|
|
|
|
|
|
668 |
|
669 |
+
if st.session_state.animation_code:
|
670 |
+
st.markdown(f"**{st.session_state.code_description}**")
|
671 |
+
st.code(st.session_state.animation_code, language="python")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
672 |
|
673 |
+
# Download button
|
674 |
+
st.download_button(
|
675 |
+
label="Download Animation Code",
|
676 |
+
data=st.session_state.animation_code,
|
677 |
+
file_name="story_animation.py",
|
678 |
+
mime="text/python",
|
679 |
+
use_container_width=True
|
680 |
+
)
|
681 |
+
|
682 |
+
st.info("π‘ To run this animation on your computer:")
|
683 |
+
st.markdown("""
|
684 |
+
1. Install Python from [python.org](https://python.org)
|
685 |
+
2. Install required libraries: `pip install matplotlib numpy`
|
686 |
+
3. Copy the code above into a file named `animation.py`
|
687 |
+
4. Run it with: `python animation.py`
|
688 |
+
""")
|
689 |
+
|
690 |
+
st.success("π When you run this code, you'll see your story come to life!")
|
691 |
+
else:
|
692 |
+
st.warning("No code generated yet!")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
693 |
|
694 |
if st.button("Create Another Story!", use_container_width=True):
|
695 |
st.session_state.active_tab = "story"
|