sunbal7 commited on
Commit
65eb8e4
ยท
verified ยท
1 Parent(s): 5ac732d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +86 -310
app.py CHANGED
@@ -1,331 +1,107 @@
1
- # app.py
2
- import streamlit as st
3
- import requests
4
- import time
5
  import os
 
6
  from dotenv import load_dotenv
 
 
 
 
 
7
 
8
- # Load environment variables
9
  load_dotenv()
10
 
11
- # Set up the page
12
- st.set_page_config(
13
- page_title="CodeTales โœจ",
14
- page_icon="๐Ÿš€",
15
- layout="wide",
16
- initial_sidebar_state="expanded"
17
- )
18
 
19
- # Custom CSS
20
- st.markdown("""
21
- <style>
22
- @import url('https://fonts.googleapis.com/css2?family=Comic+Neue:wght@700&display=swap');
23
-
24
- .stApp {
25
- background: linear-gradient(135deg, #6e8efb, #a777e3);
26
- }
27
-
28
- .header {
29
- font-family: 'Comic Neue', cursive;
30
- color: white;
31
- text-align: center;
32
- font-size: 3.5rem;
33
- text-shadow: 3px 3px 0 #000;
34
- padding: 1rem;
35
- }
36
-
37
- .subheader {
38
- font-family: 'Comic Neue', cursive;
39
- color: #ffeb3b;
40
- text-align: center;
41
- font-size: 1.8rem;
42
- margin-bottom: 2rem;
43
- }
44
-
45
- .story-box {
46
- background-color: rgba(255, 255, 255, 0.9);
47
- border-radius: 20px;
48
- padding: 2rem;
49
- box-shadow: 0 8px 16px rgba(0,0,0,0.2);
50
- margin-bottom: 2rem;
51
- }
52
-
53
- .robot-speech {
54
- background-color: #4caf50;
55
- color: white;
56
- border-radius: 20px;
57
- padding: 1.5rem;
58
- font-size: 1.2rem;
59
- position: relative;
60
- margin-top: 2rem;
61
- }
62
-
63
- .robot-speech:after {
64
- content: '';
65
- position: absolute;
66
- top: -20px;
67
- left: 50px;
68
- border: 10px solid transparent;
69
- border-bottom-color: #4caf50;
70
- }
71
-
72
- .generate-btn {
73
- background: #ff5722 !important;
74
- color: white !important;
75
- font-weight: bold !important;
76
- font-size: 1.2rem !important;
77
- padding: 0.7rem 2rem !important;
78
- border-radius: 50px !important;
79
- border: none !important;
80
- box-shadow: 0 4px 8px rgba(0,0,0,0.3) !important;
81
- transition: all 0.3s !important;
82
- margin-top: 1rem;
83
- }
84
-
85
- .generate-btn:hover {
86
- transform: scale(1.05) !important;
87
- box-shadow: 0 6px 12px rgba(0,0,0,0.4) !important;
88
- }
89
-
90
- .code-block {
91
- background: #2d2d2d;
92
- color: #f8f8f2;
93
- padding: 1rem;
94
- border-radius: 10px;
95
- font-family: monospace;
96
- font-size: 1.1rem;
97
- margin: 1rem 0;
98
- overflow-x: auto;
99
- }
100
- </style>
101
- """, unsafe_allow_html=True)
102
 
103
- # Novita.ai API functions
104
- def generate_animation(prompt):
105
- """Generate animation using Novita.ai API"""
106
- api_key = os.getenv("NOVITA_API_KEY")
107
- if not api_key:
108
- st.error("Novita.ai API key not found. Please add it to your .env file.")
109
- return None
110
-
111
- headers = {
112
- "Authorization": f"Bearer {api_key}",
113
- "Content-Type": "application/json"
114
- }
115
-
116
- payload = {
117
- "prompt": prompt,
118
- "model": "animov-0.1.1",
119
- "width": 512,
120
- "height": 512,
121
- "fps": 8,
122
- "seconds": 4
123
- }
124
-
125
- try:
126
- response = requests.post(
127
- "https://api.novita.ai/v1/video",
128
- headers=headers,
129
- json=payload
130
- )
131
-
132
- if response.status_code == 200:
133
- task_id = response.json()["task_id"]
134
- return task_id
135
- else:
136
- st.error(f"API Error: {response.status_code} - {response.text}")
137
- return None
138
- except Exception as e:
139
- st.error(f"Connection Error: {str(e)}")
140
- return None
141
 
142
- def get_animation_status(task_id):
143
- """Check status of animation generation"""
144
- api_key = os.getenv("NOVITA_API_KEY")
145
- headers = {"Authorization": f"Bearer {api_key}"}
146
-
147
- try:
148
- response = requests.get(
149
- f"https://api.novita.ai/v1/video/{task_id}",
150
- headers=headers
151
  )
152
-
153
- if response.status_code == 200:
154
- return response.json()
155
- else:
156
- return None
157
- except:
158
- return None
159
 
160
- # Header section
161
- st.markdown('<div class="header">CodeTales โœจ</div>', unsafe_allow_html=True)
162
- st.markdown('<div class="subheader">Storytime + Coding Magic</div>', unsafe_allow_html=True)
163
- 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)
164
 
165
- # How it works section
166
- with st.expander("โœจ How It Works (Like Baking a Cake) ๐ŸŽ‚"):
167
- st.markdown("""
168
- **1. Kids Write a Story (The Recipe)**
169
- Example: *"The spaceship zooms past aliens and shoots lasers!"*
170
-
171
- **2. AI is the Magic Oven ๐Ÿ”ฎ**
172
- We turn words into code (like translating English to Computer)
173
-
174
- **3. Animation Pops Out (The Cake!) ๐ŸŽฎ**
175
- See your spaceship flying and shooting instantly!
176
-
177
- **4. Robot Teacher Explains ๐Ÿค–**
178
- Tavus shows: *"See? 'spaceship.move_right()' makes it fly! That's coding!"*
179
- """)
180
 
181
- # Initialize session state
182
- if 'task_id' not in st.session_state:
183
- st.session_state.task_id = None
184
- if 'video_url' not in st.session_state:
185
- st.session_state.video_url = None
186
- if 'generating' not in st.session_state:
187
- st.session_state.generating = False
188
- if 'story_text' not in st.session_state:
189
- st.session_state.story_text = ""
 
 
 
 
190
 
191
- # Main content
192
- col1, col2 = st.columns([1, 1])
193
 
194
- with col1:
195
- st.markdown('<div class="story-box">', unsafe_allow_html=True)
196
- st.markdown("### ๐Ÿ“– Write Your Story Here:")
197
- story_text = st.text_area(
198
- "Tell your adventure story...",
199
- height=200,
200
- placeholder="Once upon a time, a brave spaceship zoomed through space, shooting lasers at alien spaceships...",
201
- label_visibility="collapsed",
202
- value=st.session_state.story_text
203
- )
204
-
205
- # Generate button with animation
206
- if st.button("โœจ Generate Animation!", use_container_width=True, key="generate", type="primary"):
207
- if story_text.strip():
208
- st.session_state.story_text = story_text
209
- st.session_state.generating = True
210
- st.session_state.task_id = generate_animation(story_text)
211
- st.session_state.video_url = None
212
- st.rerun()
213
- else:
214
- st.warning("Please enter a story first!")
215
- st.markdown('</div>', unsafe_allow_html=True)
216
 
217
- with col2:
218
- st.markdown('<div class="story-box">', unsafe_allow_html=True)
219
- st.markdown("### ๐ŸŽฎ Your Game Animation")
220
-
221
- if st.session_state.generating and st.session_state.task_id:
222
- with st.spinner("๐Ÿง™โ€โ™‚๏ธ Cooking your story in the magic oven..."):
223
- status = get_animation_status(st.session_state.task_id)
224
-
225
- if status and status.get("status") == "SUCCESS":
226
- st.session_state.video_url = status["video_url"]
227
- st.session_state.generating = False
228
- st.rerun()
229
- elif status and status.get("status") in ["FAILED", "CANCELLED"]:
230
- st.error("Oh no! The magic oven malfunctioned. Try again with a different story!")
231
- st.session_state.generating = False
232
- else:
233
- # Still processing
234
- time.sleep(3)
235
- st.rerun()
236
-
237
- if st.session_state.video_url:
238
- st.video(st.session_state.video_url)
239
- st.success("๐ŸŽ‰ Your animation is ready! Tavus will explain the magic now!")
240
- elif st.session_state.story_text:
241
- st.image("https://img.freepik.com/free-vector/hand-drawn-colorful-space-background_23-2148821798.jpg",
242
- use_column_width=True)
243
- st.info("๐Ÿ‘† Click Generate to see your story come to life!")
244
- else:
245
- st.image("https://img.freepik.com/free-vector/hand-drawn-colorful-space-background_23-2148821798.jpg",
246
- use_column_width=True)
247
- st.info("๐Ÿ‘† Write your story and click Generate to see the magic!")
248
-
249
- st.markdown('</div>', unsafe_allow_html=True)
250
 
251
- # Tavus explanation section
252
- if st.session_state.video_url and st.session_state.story_text:
253
- st.markdown('<div class="robot-speech">', unsafe_allow_html=True)
254
- st.markdown("### ๐Ÿค– Tavus the Robot Teacher says:")
255
-
256
- # Extract action words from story
257
- action_words = ["zoom", "shoot", "fly", "move", "jump", "run", "attack", "laser", "alien", "spaceship"]
258
- found_actions = [word for word in action_words if word in st.session_state.story_text.lower()]
259
-
260
- if found_actions:
261
- # Create explanation based on found words
262
- explanations = []
263
- code_snippets = []
264
-
265
- for action in found_actions[:3]: # Limit to 3 explanations
266
- if action == "zoom":
267
- explanations.append("makes your spaceship move super fast!")
268
- code_snippets.append("spaceship.accelerate(speed=10)")
269
- elif action == "shoot":
270
- explanations.append("creates laser beams to defeat enemies!")
271
- code_snippets.append("laser = spaceship.fire_weapon()")
272
- elif action == "fly":
273
- explanations.append("keeps your character moving through the air!")
274
- code_snippets.append("character.apply_gravity(False)")
275
- elif action == "move":
276
- explanations.append("changes position on the screen!")
277
- code_snippets.append("player.move(direction='right')")
278
- elif action == "jump":
279
- explanations.append("makes your character leap upwards!")
280
- code_snippets.append("hero.jump(height=100)")
281
- elif action == "run":
282
- explanations.append("makes your character move faster!")
283
- code_snippets.append("player.speed = player.speed * 2")
284
- elif action == "attack":
285
- explanations.append("lets your hero fight the bad guys!")
286
- code_snippets.append("sword.swing(damage=15)")
287
- elif action == "laser":
288
- explanations.append("creates powerful energy beams!")
289
- code_snippets.append("weapon = Laser(color='red', damage=20)")
290
- elif action == "alien":
291
- explanations.append("adds enemies to your game!")
292
- code_snippets.append("enemy = Alien(position=(100, 200))")
293
- elif action == "spaceship":
294
- explanations.append("creates your main character!")
295
- code_snippets.append("player = Spaceship(image='spaceship.png')")
296
-
297
- st.markdown("See how your story became real code? Here's what happened:")
298
-
299
- for i, (action, explanation, snippet) in enumerate(zip(found_actions, explanations, code_snippets)):
300
- st.markdown(f"**{i+1}. When you said '{action}'**:")
301
- st.markdown(f'<div class="code-block">{snippet}</div>', unsafe_allow_html=True)
302
- st.markdown(f"This code {explanation}")
303
-
304
- st.markdown("That's the magic of coding - turning words into actions!")
305
  else:
306
- st.markdown("I see you created an awesome story! Every word you write can become game code. Try adding action words like 'jump', 'run', or 'shoot' next time!")
307
-
308
- st.markdown("</div>", unsafe_allow_html=True)
 
 
 
 
309
 
310
- # Benefits section
311
- st.markdown("""
312
- ## โค Why Everyone Will Love CodeTales
313
 
314
- | For Kids ๐Ÿ‘ง๐Ÿ‘ฆ | For Parents & Teachers ๐Ÿ‘ช๐Ÿ‘ฉโ€๐Ÿซ |
315
- |--------------|----------------------------|
316
- | โœจ Feels like playing, not learning | ๐Ÿง  Secretly teaches programming concepts |
317
- | ๐Ÿš€ Brings imagination to life | ๐Ÿ” Develops logical thinking skills |
318
- | ๐ŸŽฎ Creates personal video games | โž— Reinforces math fundamentals |
319
- | ๐Ÿ˜„ Makes learning fun and exciting | ๐Ÿงฉ Encourages problem-solving abilities |
320
- """)
 
 
 
 
 
 
 
321
 
322
- # Footer
323
  st.markdown("---")
324
- st.markdown("""
325
- <center>
326
- <p style="color:white; font-size:1.1rem;">
327
- โœจ Made with magic by CodeTales Team โœจ<br>
328
- Transforming stories into games since 2023
329
- </p>
330
- </center>
331
- """, unsafe_allow_html=True)
 
 
 
 
 
1
  import os
2
+ import streamlit as st
3
  from dotenv import load_dotenv
4
+ from novita_client import NovitaClient
5
+ import ast
6
+ import subprocess
7
+ import tempfile
8
+ import time
9
 
 
10
  load_dotenv()
11
 
12
+ # Initialize Novita API client
13
+ class StoryToCodeConverter:
14
+ def __init__(self):
15
+ api_key = os.getenv("NOVITA_API_KEY")
16
+ if not api_key:
17
+ raise ValueError("NOVITA_API_KEY not found in environment")
18
+ self.client = NovitaClient(api_key)
19
 
20
+ def generate_code(self, story):
21
+ prompt = f"""
22
+ Convert this children's story into Python animation code using turtle graphics.
23
+ Add code comments that explain the basic concepts to kids, like loops, movement, and colors.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
+ Story: {story}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
+ Only return the Python code wrapped in triple backticks like ```python ... ```
28
+ """
29
+ response = self.client.chat_completions.create(
30
+ model="gpt-4",
31
+ messages=[{"role": "user", "content": prompt}]
 
 
 
 
32
  )
33
+ content = response.choices[0].message.content
34
+ return self._extract_code(content)
 
 
 
 
 
35
 
36
+ def _extract_code(self, content):
37
+ if "```python" in content:
38
+ return content.split("```python")[1].split("```")[0]
39
+ return content
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
+ # Safe execution
43
+ class CodeExecutor:
44
+ def execute_safely(self, code):
45
+ try:
46
+ ast.parse(code) # Safety check
47
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".py") as tmp:
48
+ tmp.write(code.encode("utf-8"))
49
+ tmp_path = tmp.name
50
+ subprocess.Popen(["python", tmp_path])
51
+ return True
52
+ except Exception as e:
53
+ st.error(f"Robot Chef burned the cake: {e}")
54
+ return False
55
 
 
 
56
 
57
+ # ---------- Streamlit UI ----------
58
+ st.set_page_config(page_title="CodeTales", page_icon="โœจ")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
+ with st.sidebar:
61
+ st.header("๐Ÿฐ How It Works")
62
+ st.markdown("""
63
+ 1. ๐Ÿ“ Kids write a story (like a recipe!)
64
+ 2. ๐Ÿ”ฎ AI turns it into **Python code**
65
+ 3. ๐ŸŽฎ Animation appears like magic!
66
+ 4. ๐Ÿค– Robot Teacher explains the code!
67
+
68
+ Made for ages 6โ€“12. Fun, visual, and interactive!
69
+ """)
70
+
71
+ st.title("โœจ CodeTales: Storytime + Coding Magic")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
+ story = st.text_area("Write Your Story Recipe ๐Ÿ“", height=200,
74
+ placeholder="Once upon a time, a rocket zoomed past rainbow stars and met an alien...")
75
+
76
+ if st.button("โœจ Bake My Story Cake!"):
77
+ if not story.strip():
78
+ st.warning("Please write a story first!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  else:
80
+ with st.spinner("Baking your story cake... ๐Ÿฐ"):
81
+ converter = StoryToCodeConverter()
82
+ try:
83
+ code = converter.generate_code(story)
84
+ except Exception as e:
85
+ st.error(f"AI oven broke down! {e}")
86
+ st.stop()
87
 
88
+ st.subheader("๐Ÿ“œ Your Code Recipe")
89
+ st.code(code, language='python')
 
90
 
91
+ executor = CodeExecutor()
92
+ if executor.execute_safely(code):
93
+ st.balloons()
94
+ with st.expander("๐Ÿค– Robot Teacher Says:"):
95
+ st.markdown("""
96
+ - `turtle.forward(100)` โ€“ Moves the rocket forward ๐Ÿš€
97
+ - `turtle.color("red")` โ€“ Paints with colors ๐ŸŽจ
98
+ - `for loop` โ€“ Repeats an action like magic ๐Ÿ”
99
+ """)
100
+ st.success("๐ŸŽ‰ Your story came to life!")
101
+ else:
102
+ st.error("Oops! Couldn't bake the animation.")
103
+ else:
104
+ st.caption("Turn your words into animated code with magic ๐Ÿช„")
105
 
 
106
  st.markdown("---")
107
+ st.caption("Made with โค๏ธ for young coders | Powered by Novita + Python Turtle")