|
import streamlit as st |
|
import openai |
|
from datetime import datetime |
|
import json |
|
from collections import defaultdict |
|
|
|
|
|
openai.api_key = st.secrets["OPENAI_API_KEY"] |
|
|
|
|
|
if 'story' not in st.session_state: |
|
st.session_state.story = [] |
|
if 'current_level' not in st.session_state: |
|
st.session_state.current_level = 'beginner' |
|
if 'story_started' not in st.session_state: |
|
st.session_state.story_started = False |
|
if 'badges' not in st.session_state: |
|
st.session_state.badges = defaultdict(int) |
|
if 'vocabulary_used' not in st.session_state: |
|
st.session_state.vocabulary_used = set() |
|
if 'learning_summary' not in st.session_state: |
|
st.session_state.learning_summary = [] |
|
|
|
def get_ai_response(prompt, level): |
|
"""Get response from OpenAI API""" |
|
system_prompt = f"""You are an English teacher helping a {level} level student write a story. |
|
Provide the following in JSON format: |
|
1. next_sentence: Continue the story naturally |
|
2. feedback: Constructive feedback about their writing |
|
3. vocabulary_suggestions: 3 new words they could use, appropriate for their level |
|
4. question: An open-ended question about the story to stimulate creativity |
|
5. grammar_check: Any grammar corrections needed |
|
6. visual_description: A simple description of the current scene |
|
Keep responses appropriate for the student's level.""" |
|
|
|
try: |
|
response = openai.ChatCompletion.create( |
|
model="gpt-4-turbo-preview", |
|
messages=[ |
|
{"role": "system", "content": system_prompt}, |
|
{"role": "user", "content": f"Story so far: {prompt}\n\nProvide response in JSON format."} |
|
], |
|
temperature=0.7 |
|
) |
|
return json.loads(response.choices[0].message.content) |
|
except Exception as e: |
|
st.error(f"Error with AI response: {e}") |
|
return get_default_response(level) |
|
|
|
def get_default_response(level): |
|
"""Fallback response if API fails""" |
|
return { |
|
"next_sentence": "The story continues...", |
|
"feedback": "Please try again.", |
|
"vocabulary_suggestions": ["word1", "word2", "word3"], |
|
"question": "What happens next?", |
|
"grammar_check": "No issues found.", |
|
"visual_description": "A simple scene" |
|
} |
|
|
|
def award_badge(category): |
|
"""Award badges based on achievements""" |
|
st.session_state.badges[category] += 1 |
|
st.balloons() |
|
st.success(f"π New Badge Earned: {category}!") |
|
|
|
def generate_learning_summary(): |
|
"""Generate end-of-story learning summary""" |
|
unique_words = len(st.session_state.vocabulary_used) |
|
story_length = len(st.session_state.story) |
|
summary = { |
|
"total_sentences": story_length, |
|
"unique_vocabulary": unique_words, |
|
"badges_earned": dict(st.session_state.badges), |
|
"level": st.session_state.current_level, |
|
"completion_date": datetime.now().strftime("%Y-%m-%d %H:%M:%S") |
|
} |
|
return summary |
|
|
|
def main(): |
|
st.title("π¨ Interactive Story Adventure") |
|
|
|
|
|
if not st.session_state.story_started: |
|
col1, col2 = st.columns([2, 1]) |
|
with col1: |
|
st.write("### Welcome to Story Adventure!") |
|
st.write("Let's create an amazing story together. Choose your level and start writing!") |
|
|
|
level = st.selectbox( |
|
"Choose your English level:", |
|
['beginner', 'intermediate', 'advanced'], |
|
key='level_select' |
|
) |
|
|
|
if st.button("Start Story!"): |
|
st.session_state.current_level = level |
|
st.session_state.story_started = True |
|
st.rerun() |
|
|
|
|
|
if st.session_state.story_started: |
|
|
|
with st.container(): |
|
st.write("### Our Story So Far:") |
|
for i, entry in enumerate(st.session_state.story): |
|
if entry['author'] == 'AI': |
|
st.info(entry['text']) |
|
if 'visual_description' in entry: |
|
st.caption(f"π¨ Scene: {entry['visual_description']}") |
|
else: |
|
st.success(entry['text']) |
|
|
|
|
|
with st.container(): |
|
|
|
if st.session_state.story and 'question' in st.session_state.story[-1]: |
|
st.write(f"π€ Think about: {st.session_state.story[-1]['question']}") |
|
|
|
user_input = st.text_area("Add to the story:", key='story_input') |
|
col1, col2, col3 = st.columns([1,1,1]) |
|
|
|
with col1: |
|
if st.button("Submit"): |
|
if user_input: |
|
|
|
story_context = " ".join([entry['text'] for entry in st.session_state.story]) |
|
|
|
|
|
st.session_state.story.append({ |
|
'author': 'User', |
|
'text': user_input, |
|
'timestamp': datetime.now().isoformat() |
|
}) |
|
|
|
|
|
ai_response = get_ai_response(f"{story_context}\n{user_input}", |
|
st.session_state.current_level) |
|
|
|
|
|
st.session_state.story.append({ |
|
'author': 'AI', |
|
'text': ai_response['next_sentence'], |
|
'question': ai_response['question'], |
|
'visual_description': ai_response['visual_description'], |
|
'timestamp': datetime.now().isoformat() |
|
}) |
|
|
|
|
|
st.write("### Feedback:") |
|
st.write(ai_response['feedback']) |
|
if ai_response['grammar_check'] != "No issues found.": |
|
st.warning(ai_response['grammar_check']) |
|
|
|
|
|
words = set(user_input.lower().split()) |
|
st.session_state.vocabulary_used.update(words) |
|
|
|
|
|
if len(st.session_state.story) >= 10: |
|
award_badge("Storyteller") |
|
if len(st.session_state.vocabulary_used) >= 20: |
|
award_badge("Vocabulary Master") |
|
|
|
st.rerun() |
|
|
|
with col2: |
|
if st.button("Get Help"): |
|
if st.session_state.story: |
|
ai_response = get_ai_response(" ".join([entry['text'] for entry in st.session_state.story]), |
|
st.session_state.current_level) |
|
st.write("### Suggested Words:") |
|
for word in ai_response['vocabulary_suggestions']: |
|
st.write(f"- {word}") |
|
|
|
with col3: |
|
if st.button("Finish Story"): |
|
if len(st.session_state.story) > 0: |
|
|
|
summary = generate_learning_summary() |
|
st.session_state.learning_summary.append(summary) |
|
|
|
st.write("### Story Complete! π") |
|
st.write("#### Your Achievements:") |
|
st.write(f"- Total sentences written: {summary['total_sentences']}") |
|
st.write(f"- Unique words used: {summary['unique_vocabulary']}") |
|
st.write("- Badges earned:") |
|
for badge, count in summary['badges_earned'].items(): |
|
st.write(f" * {badge}: {count} π") |
|
|
|
|
|
story_text = "\n".join([entry['text'] for entry in st.session_state.story]) |
|
st.download_button( |
|
label="Download Story", |
|
data=story_text, |
|
file_name="my_story.txt", |
|
mime="text/plain" |
|
) |
|
|
|
|
|
progress_report = { |
|
"student_level": st.session_state.current_level, |
|
"story_summary": summary, |
|
"learning_progress": st.session_state.learning_summary |
|
} |
|
st.download_button( |
|
label="Download Progress Report", |
|
data=json.dumps(progress_report, indent=2), |
|
file_name="progress_report.json", |
|
mime="application/json" |
|
) |
|
|
|
|
|
if st.button("Start New Story"): |
|
st.session_state.story = [] |
|
st.session_state.story_started = False |
|
st.session_state.vocabulary_used = set() |
|
st.rerun() |
|
|
|
if __name__ == "__main__": |
|
main() |