Update app.py
Browse files
app.py
CHANGED
@@ -1,41 +1,86 @@
|
|
1 |
import streamlit as st
|
2 |
-
import
|
3 |
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
-
# Initialize session state variables
|
6 |
if 'story' not in st.session_state:
|
7 |
st.session_state.story = []
|
8 |
if 'current_level' not in st.session_state:
|
9 |
st.session_state.current_level = 'beginner'
|
10 |
if 'story_started' not in st.session_state:
|
11 |
st.session_state.story_started = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
'intermediate': {
|
23 |
-
'next_sentence': "The adventurous feline gracefully leaped over the wooden fence.",
|
24 |
-
'feedback': "Nice structure! Consider adding more complex adjectives.",
|
25 |
-
'vocabulary_suggestions': ['gracefully', 'elegantly', 'swiftly']
|
26 |
-
},
|
27 |
-
'advanced': {
|
28 |
-
'next_sentence': "With remarkable agility, the intrepid feline launched itself over the weathered fence.",
|
29 |
-
'feedback': "Excellent use of complex sentence structure!",
|
30 |
-
'vocabulary_suggestions': ['agility', 'intrepid', 'launched']
|
31 |
-
}
|
32 |
}
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
def main():
|
36 |
st.title("π¨ Interactive Story Adventure")
|
37 |
|
38 |
-
# Level selection
|
39 |
if not st.session_state.story_started:
|
40 |
col1, col2 = st.columns([2, 1])
|
41 |
with col1:
|
@@ -61,17 +106,26 @@ def main():
|
|
61 |
for i, entry in enumerate(st.session_state.story):
|
62 |
if entry['author'] == 'AI':
|
63 |
st.info(entry['text'])
|
|
|
|
|
64 |
else:
|
65 |
st.success(entry['text'])
|
66 |
|
67 |
# Writing area
|
68 |
with st.container():
|
|
|
|
|
|
|
|
|
69 |
user_input = st.text_area("Add to the story:", key='story_input')
|
70 |
col1, col2, col3 = st.columns([1,1,1])
|
71 |
|
72 |
with col1:
|
73 |
if st.button("Submit"):
|
74 |
if user_input:
|
|
|
|
|
|
|
75 |
# Add user's sentence to story
|
76 |
st.session_state.story.append({
|
77 |
'author': 'User',
|
@@ -80,31 +134,61 @@ def main():
|
|
80 |
})
|
81 |
|
82 |
# Get AI response
|
83 |
-
ai_response = get_ai_response(
|
|
|
84 |
|
85 |
# Add AI's sentence to story
|
86 |
st.session_state.story.append({
|
87 |
'author': 'AI',
|
88 |
'text': ai_response['next_sentence'],
|
|
|
|
|
89 |
'timestamp': datetime.now().isoformat()
|
90 |
})
|
91 |
|
92 |
-
# Show feedback
|
93 |
st.write("### Feedback:")
|
94 |
st.write(ai_response['feedback'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
st.rerun()
|
96 |
|
97 |
with col2:
|
98 |
-
if st.button("Get
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
st.write(
|
|
|
|
|
103 |
|
104 |
with col3:
|
105 |
if st.button("Finish Story"):
|
106 |
if len(st.session_state.story) > 0:
|
107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
story_text = "\n".join([entry['text'] for entry in st.session_state.story])
|
109 |
st.download_button(
|
110 |
label="Download Story",
|
@@ -112,10 +196,26 @@ def main():
|
|
112 |
file_name="my_story.txt",
|
113 |
mime="text/plain"
|
114 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
115 |
# Reset session state
|
116 |
-
st.
|
117 |
-
|
118 |
-
|
|
|
|
|
119 |
|
120 |
if __name__ == "__main__":
|
121 |
main()
|
|
|
1 |
import streamlit as st
|
2 |
+
import openai
|
3 |
from datetime import datetime
|
4 |
+
import json
|
5 |
+
from collections import defaultdict
|
6 |
+
|
7 |
+
# Initialize OpenAI
|
8 |
+
openai.api_key = st.secrets["OPENAI_API_KEY"]
|
9 |
|
10 |
+
# Initialize session state variables
|
11 |
if 'story' not in st.session_state:
|
12 |
st.session_state.story = []
|
13 |
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 get_ai_response(prompt, level):
|
25 |
+
"""Get response from OpenAI API"""
|
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-4-turbo-preview",
|
39 |
+
messages=[
|
40 |
+
{"role": "system", "content": system_prompt},
|
41 |
+
{"role": "user", "content": f"Story so far: {prompt}\n\nProvide response in JSON format."}
|
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 get_default_response(level)
|
49 |
|
50 |
+
def get_default_response(level):
|
51 |
+
"""Fallback response if API fails"""
|
52 |
+
return {
|
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 award_badge(category):
|
62 |
+
"""Award badges based on achievements"""
|
63 |
+
st.session_state.badges[category] += 1
|
64 |
+
st.balloons()
|
65 |
+
st.success(f"π New Badge Earned: {category}!")
|
66 |
+
|
67 |
+
def generate_learning_summary():
|
68 |
+
"""Generate end-of-story learning summary"""
|
69 |
+
unique_words = len(st.session_state.vocabulary_used)
|
70 |
+
story_length = len(st.session_state.story)
|
71 |
+
summary = {
|
72 |
+
"total_sentences": story_length,
|
73 |
+
"unique_vocabulary": unique_words,
|
74 |
+
"badges_earned": dict(st.session_state.badges),
|
75 |
+
"level": st.session_state.current_level,
|
76 |
+
"completion_date": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
77 |
+
}
|
78 |
+
return summary
|
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:
|
|
|
106 |
for i, entry in enumerate(st.session_state.story):
|
107 |
if entry['author'] == 'AI':
|
108 |
st.info(entry['text'])
|
109 |
+
if 'visual_description' in entry:
|
110 |
+
st.caption(f"π¨ Scene: {entry['visual_description']}")
|
111 |
else:
|
112 |
st.success(entry['text'])
|
113 |
|
114 |
# Writing area
|
115 |
with st.container():
|
116 |
+
# Show AI's question if available
|
117 |
+
if st.session_state.story and 'question' in st.session_state.story[-1]:
|
118 |
+
st.write(f"π€ Think about: {st.session_state.story[-1]['question']}")
|
119 |
+
|
120 |
user_input = st.text_area("Add to the story:", key='story_input')
|
121 |
col1, col2, col3 = st.columns([1,1,1])
|
122 |
|
123 |
with col1:
|
124 |
if st.button("Submit"):
|
125 |
if user_input:
|
126 |
+
# Get story so far as context
|
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': 'User',
|
|
|
134 |
})
|
135 |
|
136 |
# Get AI response
|
137 |
+
ai_response = get_ai_response(f"{story_context}\n{user_input}",
|
138 |
+
st.session_state.current_level)
|
139 |
|
140 |
# Add AI's sentence to story
|
141 |
st.session_state.story.append({
|
142 |
'author': 'AI',
|
143 |
'text': ai_response['next_sentence'],
|
144 |
+
'question': ai_response['question'],
|
145 |
+
'visual_description': ai_response['visual_description'],
|
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 |
with col2:
|
168 |
+
if st.button("Get Help"):
|
169 |
+
if st.session_state.story:
|
170 |
+
ai_response = get_ai_response(" ".join([entry['text'] for entry in st.session_state.story]),
|
171 |
+
st.session_state.current_level)
|
172 |
+
st.write("### Suggested Words:")
|
173 |
+
for word in ai_response['vocabulary_suggestions']:
|
174 |
+
st.write(f"- {word}")
|
175 |
|
176 |
with col3:
|
177 |
if st.button("Finish Story"):
|
178 |
if len(st.session_state.story) > 0:
|
179 |
+
# Generate learning summary
|
180 |
+
summary = generate_learning_summary()
|
181 |
+
st.session_state.learning_summary.append(summary)
|
182 |
+
|
183 |
+
st.write("### Story Complete! π")
|
184 |
+
st.write("#### Your Achievements:")
|
185 |
+
st.write(f"- Total sentences written: {summary['total_sentences']}")
|
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",
|
|
|
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()
|