Update app.py
Browse files
app.py
CHANGED
@@ -14,78 +14,73 @@ if 'current_level' not in st.session_state:
|
|
14 |
st.session_state.current_level = 'beginner'
|
15 |
if 'story_started' not in st.session_state:
|
16 |
st.session_state.story_started = False
|
|
|
|
|
|
|
|
|
17 |
if 'badges' not in st.session_state:
|
18 |
st.session_state.badges = defaultdict(int)
|
19 |
if 'vocabulary_used' not in st.session_state:
|
20 |
st.session_state.vocabulary_used = set()
|
21 |
-
if 'learning_summary' not in st.session_state:
|
22 |
-
st.session_state.learning_summary = []
|
23 |
|
24 |
-
def
|
25 |
-
"""Get
|
26 |
-
system_prompt = f"""You are an English teacher helping a {level} level student write a story.
|
27 |
-
Provide the following in JSON format:
|
28 |
-
1. next_sentence: Continue the story naturally
|
29 |
-
2. feedback: Constructive feedback about their writing
|
30 |
-
3. vocabulary_suggestions: 3 new words they could use, appropriate for their level
|
31 |
-
4. question: An open-ended question about the story to stimulate creativity
|
32 |
-
5. grammar_check: Any grammar corrections needed
|
33 |
-
6. visual_description: A simple description of the current scene
|
34 |
-
Keep responses appropriate for the student's level."""
|
35 |
-
|
36 |
try:
|
37 |
response = openai.ChatCompletion.create(
|
38 |
-
model="gpt-
|
39 |
messages=[
|
40 |
-
{"role": "system", "content":
|
41 |
-
|
|
|
|
|
|
|
|
|
|
|
42 |
],
|
43 |
temperature=0.7
|
44 |
)
|
45 |
return json.loads(response.choices[0].message.content)
|
46 |
except Exception as e:
|
47 |
st.error(f"Error with AI response: {e}")
|
48 |
-
return
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
"next_sentence": "The story continues...",
|
54 |
-
"feedback": "Please try again.",
|
55 |
-
"vocabulary_suggestions": ["word1", "word2", "word3"],
|
56 |
-
"question": "What happens next?",
|
57 |
-
"grammar_check": "No issues found.",
|
58 |
-
"visual_description": "A simple scene"
|
59 |
-
}
|
60 |
|
61 |
-
def
|
62 |
-
"""
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
|
|
|
|
|
|
|
|
|
|
79 |
|
80 |
def main():
|
81 |
st.title("π¨ Interactive Story Adventure")
|
82 |
|
83 |
-
# Level selection
|
84 |
if not st.session_state.story_started:
|
85 |
col1, col2 = st.columns([2, 1])
|
86 |
with col1:
|
87 |
st.write("### Welcome to Story Adventure!")
|
88 |
-
st.write("Let's create an amazing story together. Choose your level and
|
89 |
|
90 |
level = st.selectbox(
|
91 |
"Choose your English level:",
|
@@ -93,9 +88,30 @@ def main():
|
|
93 |
key='level_select'
|
94 |
)
|
95 |
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
if st.button("Start Story!"):
|
97 |
st.session_state.current_level = level
|
|
|
|
|
98 |
st.session_state.story_started = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
st.rerun()
|
100 |
|
101 |
# Main story interface
|
@@ -103,119 +119,66 @@ def main():
|
|
103 |
# Story display area
|
104 |
with st.container():
|
105 |
st.write("### Our Story So Far:")
|
106 |
-
for
|
107 |
if entry['author'] == 'AI':
|
108 |
st.info(entry['text'])
|
109 |
-
|
110 |
-
st.caption(f"π¨ Scene: {entry['visual_description']}")
|
111 |
else:
|
112 |
st.success(entry['text'])
|
113 |
|
114 |
-
# Writing area
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
st.
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
if st.button("Submit"):
|
125 |
if user_input:
|
126 |
-
#
|
127 |
-
story_context = " ".join([entry['text'] for entry in st.session_state.story])
|
128 |
-
|
129 |
-
# Add user's sentence to story
|
130 |
st.session_state.story.append({
|
131 |
-
'author': '
|
132 |
'text': user_input,
|
133 |
'timestamp': datetime.now().isoformat()
|
134 |
})
|
135 |
|
136 |
-
# Get AI response
|
137 |
-
|
138 |
-
|
139 |
|
140 |
-
# Add AI's
|
141 |
st.session_state.story.append({
|
142 |
'author': 'AI',
|
143 |
-
'text': ai_response['
|
144 |
-
'
|
145 |
-
'
|
146 |
'timestamp': datetime.now().isoformat()
|
147 |
})
|
148 |
|
149 |
-
# Show feedback and grammar check
|
150 |
-
st.write("### Feedback:")
|
151 |
-
st.write(ai_response['feedback'])
|
152 |
-
if ai_response['grammar_check'] != "No issues found.":
|
153 |
-
st.warning(ai_response['grammar_check'])
|
154 |
-
|
155 |
-
# Update vocabulary used
|
156 |
-
words = set(user_input.lower().split())
|
157 |
-
st.session_state.vocabulary_used.update(words)
|
158 |
-
|
159 |
-
# Check for badges
|
160 |
-
if len(st.session_state.story) >= 10:
|
161 |
-
award_badge("Storyteller")
|
162 |
-
if len(st.session_state.vocabulary_used) >= 20:
|
163 |
-
award_badge("Vocabulary Master")
|
164 |
-
|
165 |
st.rerun()
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
st.write(f"- Unique words used: {summary['unique_vocabulary']}")
|
187 |
-
st.write("- Badges earned:")
|
188 |
-
for badge, count in summary['badges_earned'].items():
|
189 |
-
st.write(f" * {badge}: {count} π")
|
190 |
-
|
191 |
-
# Download options
|
192 |
-
story_text = "\n".join([entry['text'] for entry in st.session_state.story])
|
193 |
-
st.download_button(
|
194 |
-
label="Download Story",
|
195 |
-
data=story_text,
|
196 |
-
file_name="my_story.txt",
|
197 |
-
mime="text/plain"
|
198 |
-
)
|
199 |
-
|
200 |
-
# Download progress report for parents/teachers
|
201 |
-
progress_report = {
|
202 |
-
"student_level": st.session_state.current_level,
|
203 |
-
"story_summary": summary,
|
204 |
-
"learning_progress": st.session_state.learning_summary
|
205 |
-
}
|
206 |
-
st.download_button(
|
207 |
-
label="Download Progress Report",
|
208 |
-
data=json.dumps(progress_report, indent=2),
|
209 |
-
file_name="progress_report.json",
|
210 |
-
mime="application/json"
|
211 |
-
)
|
212 |
-
|
213 |
-
# Reset session state
|
214 |
-
if st.button("Start New Story"):
|
215 |
-
st.session_state.story = []
|
216 |
-
st.session_state.story_started = False
|
217 |
-
st.session_state.vocabulary_used = set()
|
218 |
-
st.rerun()
|
219 |
|
220 |
if __name__ == "__main__":
|
221 |
main()
|
|
|
14 |
st.session_state.current_level = 'beginner'
|
15 |
if 'story_started' not in st.session_state:
|
16 |
st.session_state.story_started = False
|
17 |
+
if 'first_turn' not in st.session_state:
|
18 |
+
st.session_state.first_turn = None
|
19 |
+
if 'current_turn' not in st.session_state:
|
20 |
+
st.session_state.current_turn = None
|
21 |
if 'badges' not in st.session_state:
|
22 |
st.session_state.badges = defaultdict(int)
|
23 |
if 'vocabulary_used' not in st.session_state:
|
24 |
st.session_state.vocabulary_used = set()
|
|
|
|
|
25 |
|
26 |
+
def get_ai_story_continuation(story_context, level):
|
27 |
+
"""Get story continuation from OpenAI API"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
try:
|
29 |
response = openai.ChatCompletion.create(
|
30 |
+
model="gpt-4-mini", # ΰΉΰΈΰΉ model ΰΈΰΈ΅ΰΉΰΈΰΈΉΰΈΰΈΰΉΰΈΰΈ
|
31 |
messages=[
|
32 |
+
{"role": "system", "content": f"""You are helping a {level} level English student write a story.
|
33 |
+
Provide a JSON response with:
|
34 |
+
1. continuation: A single sentence continuing the story (appropriate for {level} level)
|
35 |
+
2. creative_prompt: A short question to guide the student's next sentence
|
36 |
+
3. vocabulary_suggestions: 3 relevant words they might use next
|
37 |
+
Make the story engaging and suitable for their level."""},
|
38 |
+
{"role": "user", "content": f"Story context: {story_context}\n\nProvide the next part of the story and a guiding question."}
|
39 |
],
|
40 |
temperature=0.7
|
41 |
)
|
42 |
return json.loads(response.choices[0].message.content)
|
43 |
except Exception as e:
|
44 |
st.error(f"Error with AI response: {e}")
|
45 |
+
return {
|
46 |
+
"continuation": "The story continues...",
|
47 |
+
"creative_prompt": "What happens next?",
|
48 |
+
"vocabulary_suggestions": ["word1", "word2", "word3"]
|
49 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
|
51 |
+
def start_story(level):
|
52 |
+
"""Get the first sentence from AI"""
|
53 |
+
try:
|
54 |
+
response = openai.ChatCompletion.create(
|
55 |
+
model="gpt-4o-mini",
|
56 |
+
messages=[
|
57 |
+
{"role": "system", "content": f"""You are starting a story for a {level} level English student.
|
58 |
+
Provide a JSON response with:
|
59 |
+
1. opening: An engaging opening sentence (appropriate for {level} level)
|
60 |
+
2. creative_prompt: A short question to guide the student's first sentence
|
61 |
+
3. vocabulary_suggestions: 3 words they might use in their response"""},
|
62 |
+
{"role": "user", "content": "Please start a new story."}
|
63 |
+
],
|
64 |
+
temperature=0.7
|
65 |
+
)
|
66 |
+
return json.loads(response.choices[0].message.content)
|
67 |
+
except Exception as e:
|
68 |
+
st.error(f"Error with AI response: {e}")
|
69 |
+
return {
|
70 |
+
"opening": "Once upon a time...",
|
71 |
+
"creative_prompt": "Who is our main character?",
|
72 |
+
"vocabulary_suggestions": ["brave", "curious", "friendly"]
|
73 |
+
}
|
74 |
|
75 |
def main():
|
76 |
st.title("π¨ Interactive Story Adventure")
|
77 |
|
78 |
+
# Level selection and first turn choice
|
79 |
if not st.session_state.story_started:
|
80 |
col1, col2 = st.columns([2, 1])
|
81 |
with col1:
|
82 |
st.write("### Welcome to Story Adventure!")
|
83 |
+
st.write("Let's create an amazing story together. Choose your level and who starts first!")
|
84 |
|
85 |
level = st.selectbox(
|
86 |
"Choose your English level:",
|
|
|
88 |
key='level_select'
|
89 |
)
|
90 |
|
91 |
+
first_turn = st.radio(
|
92 |
+
"Who should start the story?",
|
93 |
+
['AI', 'Player'],
|
94 |
+
key='first_turn_select'
|
95 |
+
)
|
96 |
+
|
97 |
if st.button("Start Story!"):
|
98 |
st.session_state.current_level = level
|
99 |
+
st.session_state.first_turn = first_turn
|
100 |
+
st.session_state.current_turn = first_turn
|
101 |
st.session_state.story_started = True
|
102 |
+
|
103 |
+
# If AI starts, get the first sentence
|
104 |
+
if first_turn == 'AI':
|
105 |
+
response = start_story(level)
|
106 |
+
st.session_state.story.append({
|
107 |
+
'author': 'AI',
|
108 |
+
'text': response['opening'],
|
109 |
+
'prompt': response['creative_prompt'],
|
110 |
+
'vocabulary': response['vocabulary_suggestions'],
|
111 |
+
'timestamp': datetime.now().isoformat()
|
112 |
+
})
|
113 |
+
st.session_state.current_turn = 'Player'
|
114 |
+
|
115 |
st.rerun()
|
116 |
|
117 |
# Main story interface
|
|
|
119 |
# Story display area
|
120 |
with st.container():
|
121 |
st.write("### Our Story So Far:")
|
122 |
+
for entry in st.session_state.story:
|
123 |
if entry['author'] == 'AI':
|
124 |
st.info(entry['text'])
|
125 |
+
st.write("π€ " + entry['prompt'])
|
|
|
126 |
else:
|
127 |
st.success(entry['text'])
|
128 |
|
129 |
+
# Writing area - only show if it's player's turn
|
130 |
+
if st.session_state.current_turn == 'Player':
|
131 |
+
with st.container():
|
132 |
+
# Show vocabulary suggestions if available
|
133 |
+
if st.session_state.story and 'vocabulary' in st.session_state.story[-1]:
|
134 |
+
st.write("π‘ Suggested words you might use:")
|
135 |
+
for word in st.session_state.story[-1]['vocabulary']:
|
136 |
+
st.write(f"- {word}")
|
137 |
+
|
138 |
+
user_input = st.text_area("Your turn! Add to the story:", key='story_input')
|
139 |
if st.button("Submit"):
|
140 |
if user_input:
|
141 |
+
# Add player's sentence
|
|
|
|
|
|
|
142 |
st.session_state.story.append({
|
143 |
+
'author': 'Player',
|
144 |
'text': user_input,
|
145 |
'timestamp': datetime.now().isoformat()
|
146 |
})
|
147 |
|
148 |
+
# Get AI's response
|
149 |
+
story_context = " ".join([entry['text'] for entry in st.session_state.story])
|
150 |
+
ai_response = get_ai_story_continuation(story_context, st.session_state.current_level)
|
151 |
|
152 |
+
# Add AI's response
|
153 |
st.session_state.story.append({
|
154 |
'author': 'AI',
|
155 |
+
'text': ai_response['continuation'],
|
156 |
+
'prompt': ai_response['creative_prompt'],
|
157 |
+
'vocabulary': ai_response['vocabulary_suggestions'],
|
158 |
'timestamp': datetime.now().isoformat()
|
159 |
})
|
160 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
161 |
st.rerun()
|
162 |
+
|
163 |
+
# Finish story button
|
164 |
+
if st.button("Finish Story"):
|
165 |
+
if len(st.session_state.story) > 0:
|
166 |
+
st.write("### Story Complete! π")
|
167 |
+
story_text = "\n".join([entry['text'] for entry in st.session_state.story])
|
168 |
+
st.download_button(
|
169 |
+
label="Download Story",
|
170 |
+
data=story_text,
|
171 |
+
file_name="my_story.txt",
|
172 |
+
mime="text/plain"
|
173 |
+
)
|
174 |
+
|
175 |
+
if st.button("Start New Story"):
|
176 |
+
st.session_state.story = []
|
177 |
+
st.session_state.story_started = False
|
178 |
+
st.session_state.first_turn = None
|
179 |
+
st.session_state.current_turn = None
|
180 |
+
st.session_state.vocabulary_used = set()
|
181 |
+
st.rerun()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
|
183 |
if __name__ == "__main__":
|
184 |
main()
|