Spaces:
Sleeping
Sleeping
import os | |
import streamlit as st | |
from dotenv import load_dotenv | |
from openai import OpenAI | |
import ast | |
import subprocess | |
import tempfile | |
load_dotenv() | |
class StoryToCodeConverter: | |
def __init__(self): | |
api_key = os.getenv("NOVITA_API_KEY") | |
if not api_key: | |
raise ValueError("NOVITA_API_KEY not found in environment") | |
self.client = OpenAI( | |
api_key=api_key, | |
base_url="https://api.novita.ai/v3/openai" | |
) | |
def generate_code(self, story: str) -> str: | |
prompt = f""" | |
Convert this children's story into Python animation code using turtle graphics. | |
Include comments that explain loops, movement, colors—easy for kids. | |
Story: | |
\"\"\"{story}\"\"\" | |
Wrap the code in triple backticks like ```python ... ``` | |
""" | |
response = self.client.chat.completions.create( | |
model="meta-llama/llama-3.1-8b-instruct", | |
messages=[ | |
{"role": "system", "content": "You are a friendly teacher and coder for kids."}, | |
{"role": "user", "content": prompt} | |
], | |
max_tokens=512, | |
) | |
return self._extract_code(response.choices[0].message.content) | |
def _extract_code(self, content: str) -> str: | |
if "```python" in content: | |
return content.split("```python")[1].split("```")[0] | |
return content | |
class CodeExecutor: | |
def execute_safely(self, code: str) -> bool: | |
try: | |
ast.parse(code) | |
with tempfile.NamedTemporaryFile(delete=False, suffix=".py") as tmp: | |
tmp.write(code.encode("utf-8")) | |
path = tmp.name | |
subprocess.Popen(["python", path]) | |
return True | |
except Exception as e: | |
st.error(f"Robot Chef burned the cake: {e}") | |
return False | |
st.set_page_config(page_title="CodeTales", page_icon="✨") | |
with st.sidebar: | |
st.header("🍰 How It Works") | |
st.markdown(""" | |
1. 📝 Kids write a story | |
2. 🔮 Novita AI turns it into Python‑turtle code | |
3. 🎮 Animation plays | |
4. 🤖 Robot Teacher explains concepts | |
""") | |
st.title("✨ CodeTales: Storytime + Coding Magic") | |
story = st.text_area("Write your story here:", height=200, | |
placeholder="A turtle draws a rainbow circle...") | |
if st.button("✨ Bake My Story Cake!"): | |
if not story.strip(): | |
st.warning("Please enter a story!") | |
else: | |
with st.spinner("Baking your story code... 🍰"): | |
try: | |
converter = StoryToCodeConverter() | |
code = converter.generate_code(story) | |
except Exception as e: | |
st.error(f"AI oven broke down! {e}") | |
st.stop() | |
st.subheader("📜 Your Code Recipe") | |
st.code(code, language="python") | |
executor = CodeExecutor() | |
if executor.execute_safely(code): | |
st.balloons() | |
with st.expander("🤖 Robot Teacher Says:"): | |
st.markdown(""" | |
- `turtle.forward(100)` – Moves forward | |
- `turtle.color("red")` – Changes color | |
- `for` loops – Repeat patterns | |
""") | |
st.success("🎉 Animation ready!") | |
else: | |
st.error("Oops, something went wrong.") | |
st.caption("Made with ❤️ for young coders | Powered by Novita AI + Python Turtle") | |