ngwakomadikwe commited on
Commit
db985c5
Β·
verified Β·
1 Parent(s): e692840

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +182 -1
app.py CHANGED
@@ -112,10 +112,191 @@ Use this context to answer accurately:
112
  {school_service.get_school_context_for_ai()}
113
 
114
  Be helpful, encouraging, and accurate. If unsure, say so."""
 
 
115
  response = client.chat.completions.create(
116
  model="gpt-3.5-turbo",
117
  messages=[
118
  {"role": "system", "content": system_prompt},
119
  {"role": "user", "content": message}
120
  ],
121
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  {school_service.get_school_context_for_ai()}
113
 
114
  Be helpful, encouraging, and accurate. If unsure, say so."""
115
+
116
+ # βœ… FIXED: Added missing closing parenthesis
117
  response = client.chat.completions.create(
118
  model="gpt-3.5-turbo",
119
  messages=[
120
  {"role": "system", "content": system_prompt},
121
  {"role": "user", "content": message}
122
  ],
123
+ temperature=0.7,
124
+ max_tokens=500
125
+ ) # ← THIS WAS MISSING!
126
+
127
+ reply = response.choices[0].message.content.strip()
128
+
129
+ # Add related announcements if keywords detected
130
+ keywords = ["exam", "test", "due", "assignment", "deadline", "when", "what"]
131
+ if any(kw in message.lower() for kw in keywords):
132
+ matches = school_service.get_announcements()
133
+ relevant = [a for a in matches if any(kw in a["title"].lower() or kw in a["content"].lower() for kw in keywords)]
134
+ if relevant:
135
+ reply += "\n\nπŸ“Œ **Relevant School Info:**"
136
+ for ann in relevant[:2]:
137
+ reply += f"\n- **{ann['title']}** ({ann['course']}) β†’ {ann['content'][:70]}..."
138
+
139
+ return reply
140
+ except Exception as e:
141
+ return f"⚠️ AI Error: {str(e)}"
142
+ else:
143
+ return f"πŸ‘‹ Hi! I’m ThutoAI. You asked: '{message}'. *(Set OPENAI_API_KEY in HF Secrets for real AI.)*"
144
+
145
+
146
+ # ==================== GRADIO INTERFACE ====================
147
+
148
+ def render_announcements(course: str) -> str:
149
+ announcements = school_service.get_announcements(course)
150
+ if not announcements:
151
+ return "<p style='color: #6c757d; text-align: center;'>No announcements for this course.</p>"
152
+ html = ""
153
+ for ann in announcements:
154
+ color = "red" if ann["priority"] == "high" else "orange" if ann["priority"] == "normal" else "gray"
155
+ html += f"""
156
+ <div style="
157
+ border: 1px solid #e0e0e0;
158
+ border-radius: 8px;
159
+ padding: 12px;
160
+ margin: 8px 0;
161
+ background: white;
162
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
163
+ ">
164
+ <div style="display: flex; justify-content: space-between; align-items: flex-start;">
165
+ <strong style="font-size: 1.1em;">{ann['title']}</strong>
166
+ <span style="
167
+ background: {color};
168
+ color: white;
169
+ padding: 3px 8px;
170
+ border-radius: 4px;
171
+ font-size: 0.75em;
172
+ font-weight: bold;
173
+ text-transform: uppercase;
174
+ ">{ann['priority']}</span>
175
+ </div>
176
+ <div style="margin: 8px 0; color: #555; line-height: 1.4;">{ann['content']}</div>
177
+ <div style="font-size: 0.85em; color: #999; display: flex; justify-content: space-between;">
178
+ <span>πŸ“š {ann['course']}</span>
179
+ <span>πŸ“… {ann['date']}</span>
180
+ </div>
181
+ </div>
182
+ """
183
+ return html
184
+
185
+
186
+ # State for admin login
187
+ IS_ADMIN = False
188
+
189
+ def admin_login(username: str, password: str) -> tuple:
190
+ global IS_ADMIN
191
+ if admin_service.authenticate(username, password):
192
+ IS_ADMIN = True
193
+ return (
194
+ gr.update(visible=False), # Hide login
195
+ gr.update(visible=True), # Show dashboard
196
+ "βœ… Welcome, Teacher! You can now post announcements.",
197
+ gr.update(visible=True) # Show post form
198
+ )
199
+ return (
200
+ gr.update(visible=True),
201
+ gr.update(visible=False),
202
+ "❌ Invalid username or password",
203
+ gr.update(visible=False)
204
+ )
205
+
206
+ def admin_logout():
207
+ global IS_ADMIN
208
+ IS_ADMIN = False
209
+ return (
210
+ gr.update(visible=True),
211
+ gr.update(visible=False),
212
+ "",
213
+ gr.update(visible=False)
214
+ )
215
+
216
+ def post_announcement(title: str, content: str, course: str, priority: str) -> str:
217
+ if not IS_ADMIN:
218
+ return "πŸ”’ Only logged-in teachers can post announcements."
219
+ if not title.strip() or not content.strip():
220
+ return "⚠️ Title and content cannot be empty."
221
+ school_service.add_announcement(title, content, course, priority)
222
+ return "βœ… Announcement posted successfully! Refresh to see it."
223
+
224
+ # ==================== BUILD UI ====================
225
+
226
+ with gr.Blocks(css="""
227
+ .gradio-container {
228
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
229
+ }
230
+ """, theme=gr.themes.Soft()) as demo:
231
+ gr.Markdown("# πŸŽ“ ThutoAI β€” Your Learning Assistant")
232
+
233
+ with gr.Tab("πŸ“’ Announcements"):
234
+ gr.Markdown("### Filter by Course or Subject")
235
+ course_filter = gr.Dropdown(choices=school_service.courses, value="All", label="Select Course")
236
+ announcements_html = gr.HTML()
237
+ course_filter.change(fn=render_announcements, inputs=course_filter, outputs=announcements_html)
238
+ demo.load(fn=render_announcements, inputs=course_filter, outputs=announcements_html)
239
+
240
+ with gr.Tab("πŸ’¬ Ask ThutoAI"):
241
+ gr.Markdown("### Ask me anything β€” homework, deadlines, school info, or study tips!")
242
+ chatbot = gr.Chatbot(height=420, bubble_full_width=False)
243
+ msg = gr.Textbox(label="Type your question", placeholder="E.g., When is the Math test?")
244
+ clear = gr.Button("πŸ—‘οΈ Clear Chat")
245
+
246
+ def respond(message, chat_history):
247
+ bot_reply = ai_chat(message, chat_history)
248
+ chat_history.append((message, bot_reply))
249
+ return "", chat_history
250
+
251
+ msg.submit(respond, [msg, chatbot], [msg, chatbot])
252
+ clear.click(lambda: None, None, chatbot, queue=False)
253
+
254
+ with gr.Tab("πŸ“‚ Upload Notes & Files"):
255
+ gr.Markdown("### Upload study materials (PDFs, DOCs, TXT, etc.)")
256
+ file_input = gr.File(label="Choose a file")
257
+ upload_btn = gr.Button("πŸ“€ Upload")
258
+ status = gr.Textbox(label="Upload Status", interactive=False)
259
+ upload_btn.click(fn=school_service.upload_file, inputs=file_input, outputs=status)
260
+
261
+ with gr.Tab("πŸ” Teacher Admin"):
262
+ gr.Markdown("### Post Announcements to Students")
263
+
264
+ with gr.Group() as login_group:
265
+ gr.Markdown("#### πŸ‘©β€πŸ« Teacher Login")
266
+ username = gr.Textbox(label="Username", placeholder="e.g., [email protected]")
267
+ password = gr.Textbox(label="Password", type="password", placeholder="β€’β€’β€’β€’β€’β€’β€’β€’")
268
+ login_btn = gr.Button("πŸ”“ Login")
269
+ login_status = gr.Textbox(label="Login Status", interactive=False)
270
+
271
+ with gr.Group(visible=False) as dashboard:
272
+ gr.Markdown("#### ✍️ Create New Announcement")
273
+ with gr.Row():
274
+ title = gr.Textbox(label="Announcement Title", placeholder="e.g., Science Quiz Date Changed")
275
+ course = gr.Dropdown(choices=school_service.courses[1:], label="Course", value="General")
276
+ content = gr.Textbox(label="Details for Students", placeholder="Explain clearly...", lines=3)
277
+ priority = gr.Radio(["low", "normal", "high"], label="Priority Level", value="normal")
278
+ post_btn = gr.Button("πŸ“¬ Post Announcement")
279
+ post_result = gr.Textbox(label="Result", interactive=False)
280
+
281
+ logout_btn = gr.Button("⬅️ Logout")
282
+
283
+ # Connect buttons
284
+ login_btn.click(
285
+ fn=admin_login,
286
+ inputs=[username, password],
287
+ outputs=[login_group, dashboard, login_status, post_btn]
288
+ )
289
+ logout_btn.click(
290
+ fn=admin_logout,
291
+ inputs=None,
292
+ outputs=[login_group, dashboard, login_status, post_result]
293
+ )
294
+ post_btn.click(
295
+ fn=post_announcement,
296
+ inputs=[title, content, course, priority],
297
+ outputs=post_result
298
+ )
299
+
300
+
301
+ if __name__ == "__main__":
302
+ demo.launch()