sunbal7 commited on
Commit
5ac732d
ยท
verified ยท
1 Parent(s): 996f869

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +312 -62
app.py CHANGED
@@ -1,81 +1,331 @@
1
- import os
2
  import streamlit as st
3
- from novita_client import NovitaClient
4
- from dotenv import load_dotenv
5
- import ast
6
  import time
 
 
7
 
 
8
  load_dotenv()
9
 
10
- class StoryToCodeConverter:
11
- def __init__(self):
12
- self.client = NovitaClient(os.getenv('NOVITA_API_KEY'))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- def generate_code(self, story):
15
- prompt = f"""Convert this children's story into Python animation code using turtle graphics.
16
- Include code comments that explain basic programming concepts to kids. Story: {story}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- Return ONLY the Python code wrapped in triple backticks."""
19
- response = self_client.chat_completions.create(
20
- model="gpt-4",
21
- messages=[{"role": "user", "content": prompt}]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  )
23
- return self._extract_code(response.choices[0].message.content)
 
 
 
 
 
 
24
 
25
- def _extract_code(self, text):
26
- if '```python' in text:
27
- return text.split('```python')[1].split('```')[0]
28
- return text
29
 
30
- class CodeExecutor:
31
- def execute_safely(self, code):
32
- restricted_namespace = {
33
- '__builtins__': {
34
- 'range': range,
35
- 'print': print,
36
- 'len': len
37
- }
38
- }
39
- try:
40
- ast.parse(code)
41
- exec(code, restricted_namespace)
42
- return True
43
- except Exception as e:
44
- st.error(f"Oops! Our robot chef burned the cake: {str(e)}")
45
- return False
46
 
47
- # Streamlit UI
48
- st.set_page_config(page_title="CodeTales", page_icon="โœจ")
 
 
 
 
 
 
 
49
 
50
- with st.sidebar:
51
- st.header("Magic Ingredients ๐Ÿง™โ™‚๏ธ")
52
- st.markdown("1. Write your story recipe โœ๏ธ\n2. We bake it into code ๐Ÿง‘๐Ÿณ\n3. Play your game! ๐ŸŽฎ")
53
 
54
- st.title("CodeTales: Storytime Coding Magic โœจ")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
- story = st.text_area("Write your story recipe here (English only):", height=150,
57
- placeholder="Once upon a time, a rocket zoomed past rainbow stars...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
- if st.button("Bake My Story Cake! ๐ŸŽ‚", use_container_width=True):
60
- with st.spinner("Baking your code cake... ๐Ÿง‘๐Ÿณ"):
61
- converter = StoryToCodeConverter()
62
- code = converter.generate_code(story)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
- st.subheader("Your Secret Code Recipe ๐Ÿ“œ")
65
- st.code(code)
 
 
 
 
 
 
 
 
66
 
67
- executor = CodeExecutor()
68
- if executor.execute_safely(code):
69
- st.balloons()
70
-
71
- with st.expander("Robot Chef's Coding Kitchen ๐Ÿง‘๐Ÿณ"):
72
- st.markdown("""
73
- **How the magic works:**
74
- - `move()` โ†’ Makes characters dance! ๐Ÿ’ƒ
75
- - `color()` โ†’ Paints with rainbow colors ๐ŸŒˆ
76
- - `loop` โ†’ Repeats fun patterns ๐Ÿ”
77
- """)
78
 
79
- st.success("๐ŸŽ‰ Your coding cake is ready! Keep storytelling to learn more magic!")
 
 
 
 
 
 
80
 
81
- st.caption("Made with โค๏ธ by CodeTales Kitchen | Perfect for ages 6-12")
 
 
 
 
 
 
 
 
 
 
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)