Rathapoom commited on
Commit
69fee89
Β·
verified Β·
1 Parent(s): ee7ba92

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +526 -101
app.py CHANGED
@@ -4,6 +4,81 @@ 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
 
@@ -25,16 +100,37 @@ if 'vocabulary_used' not in st.session_state:
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
@@ -45,20 +141,43 @@ def get_ai_story_continuation(story_context, level):
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
@@ -69,116 +188,422 @@ def start_story(level):
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:",
87
- ['beginner', 'intermediate', 'advanced'],
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
118
  if st.session_state.story_started:
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()
 
4
  import json
5
  from collections import defaultdict
6
 
7
+ # Custom CSS for layout
8
+ st.markdown("""
9
+ <style>
10
+ .box-container {
11
+ background-color: #ffffff;
12
+ border-radius: 10px;
13
+ padding: 20px;
14
+ margin: 10px 0;
15
+ border: 2px solid #eee;
16
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
17
+ }
18
+
19
+ .story-box {
20
+ max-height: 300px;
21
+ overflow-y: auto;
22
+ padding: 15px;
23
+ background-color: #f8f9fa;
24
+ border-radius: 8px;
25
+ }
26
+
27
+ .input-box {
28
+ background-color: #ffffff;
29
+ padding: 15px;
30
+ border-radius: 8px;
31
+ }
32
+
33
+ .help-box {
34
+ background-color: #f0f7ff;
35
+ padding: 15px;
36
+ border-radius: 8px;
37
+ }
38
+
39
+ .rewards-box {
40
+ background-color: #fff9f0;
41
+ padding: 15px;
42
+ border-radius: 8px;
43
+ }
44
+
45
+ .stButton button {
46
+ width: 100%;
47
+ border-radius: 20px;
48
+ margin: 5px 0;
49
+ }
50
+
51
+ .story-text {
52
+ padding: 10px;
53
+ border-radius: 5px;
54
+ margin: 5px 0;
55
+ }
56
+
57
+ .ai-text {
58
+ background-color: #e3f2fd;
59
+ }
60
+
61
+ .player-text {
62
+ background-color: #f0f4c3;
63
+ }
64
+
65
+ .prompt-text {
66
+ color: #666;
67
+ font-style: italic;
68
+ margin: 5px 0;
69
+ }
70
+
71
+ .badge-container {
72
+ display: inline-block;
73
+ margin: 5px;
74
+ padding: 10px;
75
+ background-color: #ffd700;
76
+ border-radius: 50%;
77
+ text-align: center;
78
+ }
79
+ </style>
80
+ """, unsafe_allow_html=True)
81
+
82
  # Initialize OpenAI
83
  openai.api_key = st.secrets["OPENAI_API_KEY"]
84
 
 
100
 
101
  def get_ai_story_continuation(story_context, level):
102
  """Get story continuation from OpenAI API"""
103
+ # Define level-specific parameters
104
+ level_params = {
105
+ 'beginner': {
106
+ 'complexity': "Use simple present tense and basic vocabulary. Keep sentences short (8-12 words).",
107
+ 'examples': "Example: 'The dog runs to the park.' or 'She likes to read books.'"
108
+ },
109
+ 'intermediate': {
110
+ 'complexity': "Use present and past tense, compound sentences, and intermediate vocabulary.",
111
+ 'examples': "Example: 'The excited dog rushed to the park, where his friends were waiting.'"
112
+ },
113
+ 'advanced': {
114
+ 'complexity': "Use varied tenses, complex sentences, and advanced vocabulary appropriately.",
115
+ 'examples': "Example: 'Having spotted his friends at the park, the enthusiastic dog bounded over with unbridled joy.'"
116
+ }
117
+ }
118
+
119
  try:
120
  response = openai.ChatCompletion.create(
121
+ model="gpt-4o-mini", # ΰΈ«ΰΈ£ΰΈ·ΰΈ­ model ΰΈ—ΰΈ΅ΰΉˆΰΈ–ΰΈΉΰΈΰΈ•ΰΉ‰ΰΈ­ΰΈ‡ΰΈ•ΰΈ²ΰΈ‘ΰΈ—ΰΈ΅ΰΉˆΰΈ„ΰΈΈΰΈ“ΰΉƒΰΈŠΰΉ‰
122
  messages=[
123
  {"role": "system", "content": f"""You are helping a {level} level English student write a story.
124
+ {level_params[level]['complexity']}
125
+ {level_params[level]['examples']}
126
+
127
  Provide a JSON response with:
128
+ 1. continuation: A single sentence continuing the story (matching the specified level)
129
+ 2. creative_prompt: A short question (3-8 words) to guide the student's next sentence
130
+ 3. vocabulary_suggestions: 3 relevant words they might use next (appropriate for {level} level)
131
+ 4. translation: Thai translation of the continuation sentence
132
+
133
+ Ensure the story stays coherent with the context."""},
134
  {"role": "user", "content": f"Story context: {story_context}\n\nProvide the next part of the story and a guiding question."}
135
  ],
136
  temperature=0.7
 
141
  return {
142
  "continuation": "The story continues...",
143
  "creative_prompt": "What happens next?",
144
+ "vocabulary_suggestions": ["word1", "word2", "word3"],
145
+ "translation": "ΰΉ€ΰΈ£ΰΈ·ΰΉˆΰΈ­ΰΈ‡ΰΈ£ΰΈ²ΰΈ§ΰΈ”ΰΈ³ΰΉ€ΰΈ™ΰΈ΄ΰΈ™ΰΈ•ΰΉˆΰΈ­ΰΉ„ΰΈ›..."
146
  }
147
 
148
  def start_story(level):
149
  """Get the first sentence from AI"""
150
+ # Define level-specific starting prompts
151
+ level_prompts = {
152
+ 'beginner': {
153
+ 'guidance': "Start with a simple, engaging sentence about a person, animal, or place.",
154
+ 'examples': "Example: 'A happy dog lived in a blue house.'"
155
+ },
156
+ 'intermediate': {
157
+ 'guidance': "Start with an interesting situation using compound sentences.",
158
+ 'examples': "Example: 'On a sunny morning, Sarah found a mysterious letter in her garden.'"
159
+ },
160
+ 'advanced': {
161
+ 'guidance': "Start with a sophisticated hook using complex sentence structure.",
162
+ 'examples': "Example: 'Deep in the ancient forest, where shadows danced beneath ancient trees, a peculiar sound echoed through the mist.'"
163
+ }
164
+ }
165
+
166
  try:
167
  response = openai.ChatCompletion.create(
168
+ model="gpt-4o-mini", # ΰΈ«ΰΈ£ΰΈ·ΰΈ­ model ΰΈ—ΰΈ΅ΰΉˆΰΈ–ΰΈΉΰΈΰΈ•ΰΉ‰ΰΈ­ΰΈ‡ΰΈ•ΰΈ²ΰΈ‘ΰΈ—ΰΈ΅ΰΉˆΰΈ„ΰΈΈΰΈ“ΰΉƒΰΈŠΰΉ‰
169
  messages=[
170
  {"role": "system", "content": f"""You are starting a story for a {level} level English student.
171
+ {level_prompts[level]['guidance']}
172
+ {level_prompts[level]['examples']}
173
+
174
  Provide a JSON response with:
175
+ 1. opening: An engaging opening sentence (matching the specified level)
176
+ 2. creative_prompt: A short question (3-8 words) to guide the student's first sentence
177
+ 3. vocabulary_suggestions: 3 words they might use in their response (appropriate for {level} level)
178
+ 4. translation: Thai translation of the opening sentence
179
+
180
+ Make the opening engaging but appropriate for the student's level."""},
181
  {"role": "user", "content": "Please start a new story."}
182
  ],
183
  temperature=0.7
 
188
  return {
189
  "opening": "Once upon a time...",
190
  "creative_prompt": "Who is our main character?",
191
+ "vocabulary_suggestions": ["brave", "curious", "friendly"],
192
+ "translation": "กาΰΈ₯ΰΈ„ΰΈ£ΰΈ±ΰΉ‰ΰΈ‡ΰΈ«ΰΈ™ΰΈΆΰΉˆΰΈ‡..."
193
  }
194
 
195
  def main():
196
  st.title("🎨 Interactive Story Adventure")
197
 
198
+ # Initial setup (level selection and first turn choice)
199
  if not st.session_state.story_started:
200
+ with st.container():
201
+ st.markdown('<div class="box-container">', unsafe_allow_html=True)
202
  st.write("### Welcome to Story Adventure!")
203
+ col1, col2 = st.columns(2)
204
+ with col1:
205
+ level = st.selectbox(
206
+ "Choose your English level:",
207
+ ['beginner', 'intermediate', 'advanced']
208
+ )
209
+ with col2:
210
+ first_turn = st.radio(
211
+ "Who should start the story?",
212
+ ['AI', 'Player']
213
+ )
214
+ if st.button("Start Story!", key="start_button"):
215
+ st.session_state.current_level = level
216
+ st.session_state.first_turn = first_turn
217
+ st.session_state.current_turn = first_turn
218
+ st.session_state.story_started = True
219
+ if first_turn == 'AI':
220
+ response = start_story(level)
221
+ st.session_state.story.append({
222
+ 'author': 'AI',
223
+ 'text': response['opening'],
224
+ 'prompt': response['creative_prompt'],
225
+ 'vocabulary': response['vocabulary_suggestions'],
226
+ 'timestamp': datetime.now().isoformat()
227
+ })
228
+ st.session_state.current_turn = 'Player'
229
+ st.rerun()
230
+ st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
 
231
 
232
+ # Main story interface with 4-box layout
233
  if st.session_state.story_started:
234
+ # Box 1: Story Display
235
  with st.container():
236
+ st.markdown('<div class="box-container story-box">', unsafe_allow_html=True)
237
+ st.write("### πŸ“– Our Story So Far:")
238
  for entry in st.session_state.story:
239
+ css_class = "ai-text" if entry['author'] == 'AI' else "player-text"
240
+ st.markdown(f'<div class="story-text {css_class}">{entry["text"]}</div>',
241
+ unsafe_allow_html=True)
242
+ if 'prompt' in entry:
243
+ st.markdown(f'<div class="prompt-text">πŸ€” {entry["prompt"]}</div>',
244
+ unsafe_allow_html=True)
245
+ st.markdown('</div>', unsafe_allow_html=True)
246
 
247
+ # Box 2: Writing Area
248
  if st.session_state.current_turn == 'Player':
249
  with st.container():
250
+ st.markdown('<div class="box-container input-box">', unsafe_allow_html=True)
251
+ st.write("### ✏️ Your Turn!")
252
+ user_input = st.text_area("Write your next sentence:", key='story_input')
253
+ if st.button("✨ Submit", key="submit_button"):
 
 
 
 
254
  if user_input:
255
+ process_player_input(user_input)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  st.rerun()
257
+ st.markdown('</div>', unsafe_allow_html=True)
258
+
259
+ # Box 3: Help Buttons
260
+ with st.container():
261
+ st.markdown('<div class="box-container help-box">', unsafe_allow_html=True)
262
+ st.write("### πŸ’‘ Need Help?")
263
+ col1, col2, col3 = st.columns(3)
264
+ with col1:
265
+ if st.button("πŸ“š Vocabulary Help"):
266
+ show_vocabulary_help()
267
+ with col2:
268
+ if st.button("❓ Writing Tips"):
269
+ show_writing_tips()
270
+ with col3:
271
+ if st.button("🎯 Story Ideas"):
272
+ show_story_ideas()
273
+ st.markdown('</div>', unsafe_allow_html=True)
274
+
275
+ # Box 4: Rewards and Progress
276
+ with st.container():
277
+ st.markdown('<div class="box-container rewards-box">', unsafe_allow_html=True)
278
+ st.write("### πŸ† Your Achievements")
279
+ show_achievements()
280
+ col1, col2 = st.columns(2)
281
+ with col1:
282
+ if st.button("πŸ“₯ Save Story"):
283
+ save_story()
284
+ with col2:
285
+ if st.button("πŸ”„ Start New Story"):
286
+ reset_story()
287
+ st.rerun()
288
+ st.markdown('</div>', unsafe_allow_html=True)
289
+
290
+ def process_player_input(user_input):
291
+ """Process the player's input, generate feedback, and update the story"""
292
+ try:
293
+ # Get story context for AI
294
+ story_context = " ".join([entry['text'] for entry in st.session_state.story])
295
 
296
+ # Get writing feedback from GPT
297
+ feedback_response = openai.ChatCompletion.create(
298
+ model="gpt-4o-mini", # ΰΈ«ΰΈ£ΰΈ·ΰΈ­ model ΰΈ—ΰΈ΅ΰΉˆΰΈ–ΰΈΉΰΈΰΈ•ΰΉ‰ΰΈ­ΰΈ‡ΰΈ•ΰΈ²ΰΈ‘ΰΈ—ΰΈ΅ΰΉˆΰΈ„ΰΈΈΰΈ“ΰΉƒΰΈŠΰΉ‰
299
+ messages=[
300
+ {"role": "system", "content": f"""You are an English teacher helping a {st.session_state.current_level} level student.
301
+ Analyze their sentence and provide feedback in JSON format with:
302
+ 1. grammar_check: List of grammar issues found (if any)
303
+ 2. spelling_check: List of spelling issues found (if any)
304
+ 3. improvement_suggestions: Specific suggestions for improvement
305
+ 4. positive_feedback: What they did well
306
+ Be encouraging but thorough in your feedback."""},
307
+ {"role": "user", "content": f"Student's sentence: {user_input}"}
308
+ ],
309
+ temperature=0.7
310
+ )
311
+ feedback = json.loads(feedback_response.choices[0].message.content)
312
+
313
+ # Add player's sentence to story with feedback
314
+ st.session_state.story.append({
315
+ 'author': 'Player',
316
+ 'text': user_input,
317
+ 'feedback': feedback,
318
+ 'timestamp': datetime.now().isoformat()
319
+ })
320
+
321
+ # Update vocabulary used
322
+ words = set(user_input.lower().split())
323
+ st.session_state.vocabulary_used.update(words)
324
+
325
+ # Check for achievements
326
+ check_achievements(user_input, feedback)
327
+
328
+ # Get AI's continuation
329
+ ai_response = get_ai_story_continuation(
330
+ story_context + "\n" + user_input,
331
+ st.session_state.current_level
332
+ )
333
+
334
+ # Add AI's response to story
335
+ st.session_state.story.append({
336
+ 'author': 'AI',
337
+ 'text': ai_response['continuation'],
338
+ 'prompt': ai_response['creative_prompt'],
339
+ 'vocabulary': ai_response['vocabulary_suggestions'],
340
+ 'translation': ai_response.get('translation', ''),
341
+ 'timestamp': datetime.now().isoformat()
342
+ })
343
+
344
+ # Switch turn back to player
345
+ st.session_state.current_turn = 'Player'
346
+
347
+ # Show feedback to player
348
+ display_feedback(feedback)
349
+
350
+ except Exception as e:
351
+ st.error(f"Error processing input: {e}")
352
+ st.session_state.story.append({
353
+ 'author': 'Player',
354
+ 'text': user_input,
355
+ 'timestamp': datetime.now().isoformat()
356
+ })
357
+
358
+ def check_achievements(user_input, feedback):
359
+ """Check and award achievements based on player's writing"""
360
+ # Story length achievements
361
+ if len(st.session_state.story) >= 10:
362
+ award_badge("Storyteller")
363
+ if len(st.session_state.story) >= 20:
364
+ award_badge("Master Storyteller")
365
+
366
+ # Vocabulary achievements
367
+ if len(st.session_state.vocabulary_used) >= 20:
368
+ award_badge("Vocabulary Explorer")
369
+ if len(st.session_state.vocabulary_used) >= 50:
370
+ award_badge("Word Master")
371
+
372
+ # Writing quality achievements
373
+ if not feedback['grammar_check'] and not feedback['spelling_check']:
374
+ award_badge("Perfect Writing")
375
+
376
+ # Creativity achievements
377
+ if len(user_input.split()) >= 15:
378
+ award_badge("Detailed Writer")
379
+
380
+ def award_badge(badge_name):
381
+ """Award a new badge if not already earned"""
382
+ if badge_name not in st.session_state.badges:
383
+ st.session_state.badges[badge_name] = 1
384
+ st.balloons()
385
+ st.success(f"πŸ† New Achievement Unlocked: {badge_name}!")
386
+ else:
387
+ st.session_state.badges[badge_name] += 1
388
+
389
+ def display_feedback(feedback):
390
+ """Display writing feedback to the player"""
391
+ with st.container():
392
+ # Show positive feedback first
393
+ st.success(f"πŸ‘ {feedback['positive_feedback']}")
394
+
395
+ # Show any grammar or spelling issues
396
+ if feedback['grammar_check']:
397
+ st.warning("πŸ“ Grammar points to consider:")
398
+ for issue in feedback['grammar_check']:
399
+ st.write(f"- {issue}")
400
+
401
+ if feedback['spelling_check']:
402
+ st.warning("✍️ Spelling points to consider:")
403
+ for issue in feedback['spelling_check']:
404
+ st.write(f"- {issue}")
405
+
406
+ # Show improvement suggestions
407
+ if feedback['improvement_suggestions']:
408
+ st.info("πŸ’‘ Suggestions for next time:")
409
+ for suggestion in feedback['improvement_suggestions']:
410
+ st.write(f"- {suggestion}")
411
+
412
+ def show_vocabulary_help():
413
+ """Show vocabulary suggestions and meanings"""
414
+ if st.session_state.story:
415
+ last_entry = st.session_state.story[-1]
416
+ if 'vocabulary' in last_entry:
417
+ # Get word meanings and examples
418
+ try:
419
+ word_info = openai.ChatCompletion.create(
420
+ model="gpt-4o-mini",
421
+ messages=[
422
+ {"role": "system", "content": f"""For each word, provide:
423
+ 1. Simple definition
424
+ 2. Thai translation
425
+ 3. Example sentence
426
+ Format in JSON with word as key."""},
427
+ {"role": "user", "content": f"Words: {', '.join(last_entry['vocabulary'])}"}
428
+ ]
429
  )
430
+ word_details = json.loads(word_info.choices[0].message.content)
431
 
432
+ st.write("### πŸ“š Suggested Words:")
433
+ for word in last_entry['vocabulary']:
434
+ with st.expander(f"πŸ”€ {word}"):
435
+ if word in word_details:
436
+ details = word_details[word]
437
+ st.write(f"**Meaning:** {details['definition']}")
438
+ st.write(f"**แปΰΈ₯ΰΉ„ΰΈ—ΰΈ’:** {details['thai']}")
439
+ st.write(f"**Example:** _{details['example']}_")
440
+ except Exception as e:
441
+ # Fallback to simple display
442
+ st.write("Try using these words:")
443
+ for word in last_entry['vocabulary']:
444
+ st.markdown(f"- *{word}*")
445
+
446
+ def show_writing_tips():
447
+ """Show writing tips based on current level and story context"""
448
+ if st.session_state.story:
449
+ try:
450
+ # Get personalized writing tips
451
+ tips_response = openai.ChatCompletion.create(
452
+ model="gpt-4o-mini",
453
+ messages=[
454
+ {"role": "system", "content": f"""You are helping a {st.session_state.current_level} level English student.
455
+ Provide 3 specific writing tips based on their level and story context.
456
+ Include examples for each tip.
457
+ Keep tips short and friendly."""},
458
+ {"role": "user", "content": f"Story so far: {' '.join([entry['text'] for entry in st.session_state.story])}"}
459
+ ]
460
+ )
461
+
462
+ st.write("### ✍️ Writing Tips")
463
+ tips = tips_response.choices[0].message.content.split('\n')
464
+ for tip in tips:
465
+ if tip.strip():
466
+ st.info(tip)
467
+
468
+ # Add quick reference examples
469
+ st.write("### 🎯 Quick Examples:")
470
+ col1, col2 = st.columns(2)
471
+ with col1:
472
+ st.write("**Good:**")
473
+ st.success("The happy dog played in the garden.")
474
+ with col2:
475
+ st.write("**Better:**")
476
+ st.success("The excited golden retriever chased butterflies in the colorful garden.")
477
+
478
+ except Exception as e:
479
+ # Fallback tips
480
+ st.write("### General Writing Tips:")
481
+ st.write("1. Use descriptive words")
482
+ st.write("2. Keep your sentences clear")
483
+ st.write("3. Try to be creative")
484
+
485
+ def show_story_ideas():
486
+ """Generate creative story ideas based on current context"""
487
+ if st.session_state.story:
488
+ try:
489
+ # Get creative prompts
490
+ ideas_response = openai.ChatCompletion.create(
491
+ model="gpt-4o-mini",
492
+ messages=[
493
+ {"role": "system", "content": f"""Generate 3 creative story direction ideas for a {st.session_state.current_level} student.
494
+ Ideas should follow from the current story.
495
+ Make suggestions exciting but achievable for their level."""},
496
+ {"role": "user", "content": f"Story so far: {' '.join([entry['text'] for entry in st.session_state.story])}"}
497
+ ]
498
+ )
499
+
500
+ st.write("### πŸ’­ Story Ideas")
501
+ ideas = ideas_response.choices[0].message.content.split('\n')
502
+ for i, idea in enumerate(ideas, 1):
503
+ if idea.strip():
504
+ with st.expander(f"Idea {i}"):
505
+ st.write(idea)
506
+
507
+ # Add story element suggestions
508
+ st.write("### 🎨 Try adding:")
509
+ elements = ["a new character", "a surprise event", "a funny moment", "a problem to solve"]
510
+ cols = st.columns(len(elements))
511
+ for col, element in zip(cols, elements):
512
+ with col:
513
+ st.button(element, key=f"element_{element}")
514
+
515
+ except Exception as e:
516
+ # Fallback ideas
517
+ st.write("### Story Ideas:")
518
+ st.write("1. Introduce a new character")
519
+ st.write("2. Add an unexpected event")
520
+ st.write("3. Create a problem to solve")
521
+
522
+ def show_achievements():
523
+ """Display achievements and badges with animations"""
524
+ if st.session_state.badges:
525
+ st.write("### πŸ† Your Achievements")
526
+ cols = st.columns(3)
527
+ for i, (badge, count) in enumerate(st.session_state.badges.items()):
528
+ with cols[i % 3]:
529
+ st.markdown(f'''
530
+ <div class="badge-container" style="animation: bounce 1s infinite;">
531
+ <div style="font-size: 2em;">🌟</div>
532
+ <div style="font-weight: bold;">{badge}</div>
533
+ <div>x{count}</div>
534
+ </div>
535
+ ''', unsafe_allow_html=True)
536
+
537
+ # Add progress towards next badge
538
+ st.write("### πŸ“ˆ Progress to Next Badge:")
539
+ current_words = len(st.session_state.vocabulary_used)
540
+ next_milestone = (current_words // 10 + 1) * 10
541
+ progress = current_words / next_milestone
542
+ st.progress(progress)
543
+ st.write(f"Use {next_milestone - current_words} more unique words for next badge!")
544
+
545
+ def save_story():
546
+ """Save story with additional information"""
547
+ if st.session_state.story:
548
+ # Prepare story text with formatting
549
+ story_parts = []
550
+ story_parts.append("=== My English Story Adventure ===\n")
551
+ story_parts.append(f"Level: {st.session_state.current_level}")
552
+ story_parts.append(f"Date: {datetime.now().strftime('%Y-%m-%d')}\n")
553
+
554
+ # Add story content
555
+ for entry in st.session_state.story:
556
+ author = "πŸ‘€ You:" if entry['author'] == 'Player' else "πŸ€– AI:"
557
+ story_parts.append(f"{author} {entry['text']}")
558
+
559
+ # Add achievements
560
+ story_parts.append("\n=== Achievements ===")
561
+ for badge, count in st.session_state.badges.items():
562
+ story_parts.append(f"🌟 {badge}: x{count}")
563
+
564
+ # Create the full story text
565
+ story_text = "\n".join(story_parts)
566
+
567
+ # Offer download options
568
+ col1, col2 = st.columns(2)
569
+ with col1:
570
+ st.download_button(
571
+ label="πŸ“ Download Story (Text)",
572
+ data=story_text,
573
+ file_name="my_story.txt",
574
+ mime="text/plain"
575
+ )
576
+ with col2:
577
+ # Create JSON version with more details
578
+ story_data = {
579
+ "metadata": {
580
+ "level": st.session_state.current_level,
581
+ "date": datetime.now().isoformat(),
582
+ "vocabulary_used": list(st.session_state.vocabulary_used),
583
+ "achievements": dict(st.session_state.badges)
584
+ },
585
+ "story": st.session_state.story
586
+ }
587
+ st.download_button(
588
+ label="πŸ’Ύ Download Progress Report (JSON)",
589
+ data=json.dumps(story_data, indent=2),
590
+ file_name="story_progress.json",
591
+ mime="application/json"
592
+ )
593
+
594
+ def reset_story():
595
+ """Reset all story-related session state"""
596
+ if st.button("πŸ”„ Start New Story", key="reset_button"):
597
+ st.session_state.story = []
598
+ st.session_state.story_started = False
599
+ st.session_state.first_turn = None
600
+ st.session_state.current_turn = None
601
+ st.session_state.vocabulary_used = set()
602
+ # Keep badges for long-term progress
603
+ st.balloons()
604
+ st.success("Ready for a new adventure! Your achievements have been saved.")
605
+ st.rerun()
606
+
607
 
608
  if __name__ == "__main__":
609
  main()