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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +62 -312
app.py CHANGED
@@ -1,331 +1,81 @@
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 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")