ngwakomadikwe commited on
Commit
31ac6a0
·
verified ·
1 Parent(s): 8742ebb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +342 -8
app.py CHANGED
@@ -1,10 +1,20 @@
 
 
 
 
1
  import os
2
- from openai import OpenAI
3
  from flask import Flask, request, jsonify, render_template
 
 
 
 
 
 
 
4
 
5
  app = Flask(__name__)
6
 
7
- # Get the API key from environment variables
8
  api_key = os.getenv("OPENAI_API_KEY")
9
 
10
  if not api_key:
@@ -13,18 +23,135 @@ if not api_key:
13
  else:
14
  try:
15
  from openai import OpenAI
16
- client = OpenAI(api_key=api_key)
 
17
  except Exception as e:
18
  print(f"Error initializing OpenAI client: {e}")
19
  client = None
20
 
21
  @app.route("/")
22
  def home():
23
- """Serve the chat web interface"""
24
  return render_template('index.html')
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  @app.route("/chat", methods=["POST"])
27
  def chat():
 
28
  try:
29
  if not client:
30
  return jsonify({"error": "OpenAI API key not configured"}), 500
@@ -35,24 +162,231 @@ def chat():
35
  if not user_message:
36
  return jsonify({"error": "Message is required"}), 400
37
 
38
- # Use the new OpenAI client
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  response = client.chat.completions.create(
40
  model="gpt-3.5-turbo",
41
- messages=[{"role": "user", "content": user_message}],
 
 
 
42
  temperature=0.7,
43
  max_tokens=1000
44
  )
45
 
46
  reply = response.choices[0].message.content
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  return jsonify({"reply": reply})
48
 
49
  except Exception as e:
50
  return jsonify({"error": str(e)}), 500
51
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  @app.route("/health")
53
  def health():
54
  """Health check endpoint"""
55
- return jsonify({"status": "healthy", "service": "ThutoAI"})
 
 
 
 
56
 
57
  if __name__ == "__main__":
58
- app.run(host="0.0.0.0", port=7860)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ThutoAI - Complete Student Assistant with School Management
3
+ Enhanced version for Hugging Face deployment
4
+ """
5
  import os
 
6
  from flask import Flask, request, jsonify, render_template
7
+ from dotenv import load_dotenv
8
+ from school_service import school_service
9
+ from admin_service import admin_service
10
+ import json
11
+
12
+ # Load environment variables
13
+ load_dotenv()
14
 
15
  app = Flask(__name__)
16
 
17
+ # Get the API key from environment variables
18
  api_key = os.getenv("OPENAI_API_KEY")
19
 
20
  if not api_key:
 
23
  else:
24
  try:
25
  from openai import OpenAI
26
+ client = OpenAI() # Will use OPENAI_API_KEY from environment
27
+ print("OpenAI client initialized successfully")
28
  except Exception as e:
29
  print(f"Error initializing OpenAI client: {e}")
30
  client = None
31
 
32
  @app.route("/")
33
  def home():
34
+ """Serve the enhanced chat web interface"""
35
  return render_template('index.html')
36
 
37
+ @app.route("/dashboard")
38
+ def dashboard():
39
+ """Serve the student dashboard"""
40
+ try:
41
+ student_summary = school_service.get_student_summary()
42
+ return jsonify({
43
+ "success": True,
44
+ "data": student_summary
45
+ })
46
+ except Exception as e:
47
+ return jsonify({
48
+ "success": False,
49
+ "error": str(e)
50
+ }), 500
51
+
52
+ @app.route("/announcements")
53
+ def get_announcements():
54
+ """Get recent announcements"""
55
+ try:
56
+ announcements = school_service.get_recent_announcements()
57
+ return jsonify({
58
+ "success": True,
59
+ "announcements": announcements
60
+ })
61
+ except Exception as e:
62
+ return jsonify({
63
+ "success": False,
64
+ "error": str(e)
65
+ }), 500
66
+
67
+ @app.route("/exams")
68
+ def get_exams():
69
+ """Get upcoming exams"""
70
+ try:
71
+ exams = school_service.get_upcoming_exams()
72
+ return jsonify({
73
+ "success": True,
74
+ "exams": exams
75
+ })
76
+ except Exception as e:
77
+ return jsonify({
78
+ "success": False,
79
+ "error": str(e)
80
+ }), 500
81
+
82
+ @app.route("/tests")
83
+ def get_tests():
84
+ """Get upcoming tests and assignments"""
85
+ try:
86
+ tests = school_service.get_upcoming_tests_assignments()
87
+ return jsonify({
88
+ "success": True,
89
+ "tests": tests
90
+ })
91
+ except Exception as e:
92
+ return jsonify({
93
+ "success": False,
94
+ "error": str(e)
95
+ }), 500
96
+
97
+ @app.route("/grades")
98
+ def get_grades():
99
+ """Get student grades"""
100
+ try:
101
+ student_id = request.args.get('student_id', 'STU001')
102
+ subject = request.args.get('subject', None)
103
+ grades = school_service.get_student_grades(student_id, subject)
104
+ return jsonify({
105
+ "success": True,
106
+ "grades": grades
107
+ })
108
+ except Exception as e:
109
+ return jsonify({
110
+ "success": False,
111
+ "error": str(e)
112
+ }), 500
113
+
114
+ @app.route("/events")
115
+ def get_events():
116
+ """Get upcoming school events"""
117
+ try:
118
+ events = school_service.get_upcoming_events()
119
+ return jsonify({
120
+ "success": True,
121
+ "events": events
122
+ })
123
+ except Exception as e:
124
+ return jsonify({
125
+ "success": False,
126
+ "error": str(e)
127
+ }), 500
128
+
129
+ @app.route("/search")
130
+ def search_school_info():
131
+ """Search school information"""
132
+ try:
133
+ query = request.args.get('q', '')
134
+ if not query:
135
+ return jsonify({
136
+ "success": False,
137
+ "error": "Search query is required"
138
+ }), 400
139
+
140
+ results = school_service.search_school_info(query)
141
+ return jsonify({
142
+ "success": True,
143
+ "results": results,
144
+ "query": query
145
+ })
146
+ except Exception as e:
147
+ return jsonify({
148
+ "success": False,
149
+ "error": str(e)
150
+ }), 500
151
+
152
  @app.route("/chat", methods=["POST"])
153
  def chat():
154
+ """Enhanced chat with school context"""
155
  try:
156
  if not client:
157
  return jsonify({"error": "OpenAI API key not configured"}), 500
 
162
  if not user_message:
163
  return jsonify({"error": "Message is required"}), 400
164
 
165
+ # Get school context for AI
166
+ school_context = school_service.format_school_context_for_ai()
167
+
168
+ # Enhanced system prompt for student assistant
169
+ system_prompt = f"""You are ThutoAI, an AI assistant specifically designed to help students with their academic life. You have access to real-time school information and should use it to provide contextual, helpful responses.
170
+
171
+ {school_context}
172
+
173
+ Your role is to:
174
+ 1. Help students with academic questions and study support
175
+ 2. Provide information about school announcements, exams, tests, and events
176
+ 3. Offer study tips, time management advice, and motivation
177
+ 4. Help with stress management and emotional support
178
+ 5. Answer questions about grades and academic performance
179
+ 6. Remind students about important dates and deadlines
180
+
181
+ Always be encouraging, supportive, and student-friendly. Use the school information context to provide specific, relevant answers. If asked about school-specific information, refer to the context provided above."""
182
+
183
+ # Use the enhanced OpenAI client
184
  response = client.chat.completions.create(
185
  model="gpt-3.5-turbo",
186
+ messages=[
187
+ {"role": "system", "content": system_prompt},
188
+ {"role": "user", "content": user_message}
189
+ ],
190
  temperature=0.7,
191
  max_tokens=1000
192
  )
193
 
194
  reply = response.choices[0].message.content
195
+
196
+ # Check if the query might be school-specific and add relevant info
197
+ school_keywords = ['exam', 'test', 'grade', 'announcement', 'assignment', 'due', 'schedule']
198
+ if any(keyword in user_message.lower() for keyword in school_keywords):
199
+ search_results = school_service.search_school_info(user_message)
200
+ if search_results:
201
+ reply += "\n\n📚 **Related School Information:**\n"
202
+ for result in search_results[:3]: # Show top 3 results
203
+ if result['type'] == 'exam':
204
+ reply += f"• **{result['name']}** ({result['subject']}) - {result['date']} at {result['time']}\n"
205
+ elif result['type'] == 'announcement':
206
+ reply += f"• **{result['title']}** - {result['content'][:100]}...\n"
207
+ elif result['type'] == 'test_assignment':
208
+ reply += f"• **{result['title']}** ({result['subject']}) - Due: {result['due_date']}\n"
209
+
210
  return jsonify({"reply": reply})
211
 
212
  except Exception as e:
213
  return jsonify({"error": str(e)}), 500
214
 
215
+ # ==================== ADMIN ROUTES ====================
216
+
217
+ @app.route("/admin/login")
218
+ def admin_login_page():
219
+ """Serve admin login page"""
220
+ return render_template('admin_login.html')
221
+
222
+ @app.route("/admin/login", methods=["POST"])
223
+ def admin_login():
224
+ """Handle admin login"""
225
+ try:
226
+ data = request.json
227
+ username = data.get("username")
228
+ password = data.get("password")
229
+
230
+ if not username or not password:
231
+ return jsonify({"success": False, "error": "Username and password required"}), 400
232
+
233
+ admin = admin_service.authenticate_admin(username, password)
234
+
235
+ if admin:
236
+ return jsonify({"success": True, "admin": admin})
237
+ else:
238
+ return jsonify({"success": False, "error": "Invalid credentials"}), 401
239
+
240
+ except Exception as e:
241
+ return jsonify({"success": False, "error": str(e)}), 500
242
+
243
+ @app.route("/admin/dashboard")
244
+ def admin_dashboard():
245
+ """Serve admin dashboard"""
246
+ return render_template('admin_dashboard.html')
247
+
248
+ @app.route("/admin/stats")
249
+ def admin_stats():
250
+ """Get admin dashboard statistics"""
251
+ try:
252
+ stats = admin_service.get_admin_dashboard_stats()
253
+ return jsonify({"success": True, "stats": stats})
254
+ except Exception as e:
255
+ return jsonify({"success": False, "error": str(e)}), 500
256
+
257
+ # Announcement management routes
258
+ @app.route("/admin/announcements", methods=["GET"])
259
+ def admin_get_announcements():
260
+ """Get all announcements for admin"""
261
+ try:
262
+ announcements = admin_service.get_all_announcements()
263
+ return jsonify({"success": True, "announcements": announcements})
264
+ except Exception as e:
265
+ return jsonify({"success": False, "error": str(e)}), 500
266
+
267
+ @app.route("/admin/announcements", methods=["POST"])
268
+ def admin_create_announcement():
269
+ """Create new announcement"""
270
+ try:
271
+ data = request.json
272
+ announcement_id = admin_service.create_announcement(
273
+ title=data.get("title"),
274
+ content=data.get("content"),
275
+ priority=data.get("priority", "normal"),
276
+ target_audience=data.get("target_audience", "all"),
277
+ expires_at=data.get("expires_at")
278
+ )
279
+ return jsonify({"success": True, "id": announcement_id})
280
+ except Exception as e:
281
+ return jsonify({"success": False, "error": str(e)}), 500
282
+
283
+ @app.route("/admin/announcements/<int:announcement_id>", methods=["DELETE"])
284
+ def admin_delete_announcement(announcement_id):
285
+ """Delete announcement"""
286
+ try:
287
+ admin_service.delete_announcement(announcement_id)
288
+ return jsonify({"success": True})
289
+ except Exception as e:
290
+ return jsonify({"success": False, "error": str(e)}), 500
291
+
292
+ # Syllabus management routes
293
+ @app.route("/admin/syllabus", methods=["GET"])
294
+ def admin_get_syllabus():
295
+ """Get all syllabus entries"""
296
+ try:
297
+ syllabus = admin_service.get_syllabus()
298
+ return jsonify({"success": True, "syllabus": syllabus})
299
+ except Exception as e:
300
+ return jsonify({"success": False, "error": str(e)}), 500
301
+
302
+ @app.route("/admin/syllabus", methods=["POST"])
303
+ def admin_create_syllabus():
304
+ """Create new syllabus entry"""
305
+ try:
306
+ data = request.json
307
+ syllabus_id = admin_service.create_syllabus(
308
+ subject=data.get("subject"),
309
+ grade_level=data.get("grade_level"),
310
+ chapter_number=data.get("chapter_number"),
311
+ chapter_title=data.get("chapter_title"),
312
+ topics=data.get("topics"),
313
+ learning_objectives=data.get("learning_objectives"),
314
+ duration_weeks=data.get("duration_weeks"),
315
+ resources=data.get("resources"),
316
+ assessment_methods=data.get("assessment_methods")
317
+ )
318
+ return jsonify({"success": True, "id": syllabus_id})
319
+ except Exception as e:
320
+ return jsonify({"success": False, "error": str(e)}), 500
321
+
322
+ @app.route("/admin/syllabus/<int:syllabus_id>", methods=["DELETE"])
323
+ def admin_delete_syllabus(syllabus_id):
324
+ """Delete syllabus entry"""
325
+ try:
326
+ admin_service.update_syllabus(syllabus_id, is_active=False)
327
+ return jsonify({"success": True})
328
+ except Exception as e:
329
+ return jsonify({"success": False, "error": str(e)}), 500
330
+
331
+ # Timetable management routes
332
+ @app.route("/admin/timetable", methods=["GET"])
333
+ def admin_get_timetable():
334
+ """Get all timetable entries"""
335
+ try:
336
+ timetable = admin_service.get_timetable()
337
+ return jsonify({"success": True, "timetable": timetable})
338
+ except Exception as e:
339
+ return jsonify({"success": False, "error": str(e)}), 500
340
+
341
+ @app.route("/admin/timetable", methods=["POST"])
342
+ def admin_create_timetable():
343
+ """Create new timetable entry"""
344
+ try:
345
+ data = request.json
346
+ timetable_id = admin_service.create_timetable_entry(
347
+ class_section=data.get("class_section"),
348
+ day_of_week=data.get("day_of_week"),
349
+ period_number=data.get("period_number"),
350
+ start_time=data.get("start_time"),
351
+ end_time=data.get("end_time"),
352
+ subject=data.get("subject"),
353
+ teacher_name=data.get("teacher_name"),
354
+ room_number=data.get("room_number")
355
+ )
356
+ return jsonify({"success": True, "id": timetable_id})
357
+ except Exception as e:
358
+ return jsonify({"success": False, "error": str(e)}), 500
359
+
360
+ @app.route("/admin/timetable/<int:timetable_id>", methods=["DELETE"])
361
+ def admin_delete_timetable(timetable_id):
362
+ """Delete timetable entry"""
363
+ try:
364
+ admin_service.delete_timetable_entry(timetable_id)
365
+ return jsonify({"success": True})
366
+ except Exception as e:
367
+ return jsonify({"success": False, "error": str(e)}), 500
368
+
369
  @app.route("/health")
370
  def health():
371
  """Health check endpoint"""
372
+ return jsonify({
373
+ "status": "healthy",
374
+ "service": "ThutoAI Enhanced",
375
+ "features": ["AI Chat", "School Integration", "Student Dashboard", "Admin Panel"]
376
+ })
377
 
378
  if __name__ == "__main__":
379
+ # Initialize database with sample data
380
+ try:
381
+ from models import DatabaseManager
382
+ db = DatabaseManager()
383
+ db.add_sample_data()
384
+ print("Database initialized with sample data")
385
+ except Exception as e:
386
+ print(f"Database initialization error: {e}")
387
+
388
+ print("Starting ThutoAI Enhanced - Your Complete Student Assistant")
389
+ print("Features: AI Chat + School Info + Student Dashboard + Admin Panel")
390
+ print("Access at: http://0.0.0.0:7860")
391
+
392
+ app.run(host="0.0.0.0", port=7860, debug=True)