Spaces:
Runtime error
Runtime error
| """ | |
| ThutoAI - Complete Student Assistant with School Management | |
| Enhanced version for Hugging Face deployment | |
| """ | |
| import os | |
| from flask import Flask, request, jsonify, render_template | |
| from dotenv import load_dotenv | |
| from school_service import school_service | |
| from admin_service import admin_service | |
| import json | |
| # Load environment variables | |
| load_dotenv() | |
| app = Flask(__name__) | |
| # Get the API key from environment variables | |
| api_key = os.getenv("OPENAI_API_KEY") | |
| if not api_key: | |
| print("WARNING: OPENAI_API_KEY is not set. Chat functionality will not work.") | |
| client = None | |
| else: | |
| try: | |
| from openai import OpenAI | |
| client = OpenAI() # Will use OPENAI_API_KEY from environment | |
| print("OpenAI client initialized successfully") | |
| except Exception as e: | |
| print(f"Error initializing OpenAI client: {e}") | |
| client = None | |
| def home(): | |
| """Serve the enhanced chat web interface""" | |
| return render_template('index.html') | |
| def dashboard(): | |
| """Serve the student dashboard""" | |
| try: | |
| student_summary = school_service.get_student_summary() | |
| return jsonify({ | |
| "success": True, | |
| "data": student_summary | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| "success": False, | |
| "error": str(e) | |
| }), 500 | |
| def get_announcements(): | |
| """Get recent announcements""" | |
| try: | |
| announcements = school_service.get_recent_announcements() | |
| return jsonify({ | |
| "success": True, | |
| "announcements": announcements | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| "success": False, | |
| "error": str(e) | |
| }), 500 | |
| def get_exams(): | |
| """Get upcoming exams""" | |
| try: | |
| exams = school_service.get_upcoming_exams() | |
| return jsonify({ | |
| "success": True, | |
| "exams": exams | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| "success": False, | |
| "error": str(e) | |
| }), 500 | |
| def get_tests(): | |
| """Get upcoming tests and assignments""" | |
| try: | |
| tests = school_service.get_upcoming_tests_assignments() | |
| return jsonify({ | |
| "success": True, | |
| "tests": tests | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| "success": False, | |
| "error": str(e) | |
| }), 500 | |
| def get_grades(): | |
| """Get student grades""" | |
| try: | |
| student_id = request.args.get('student_id', 'STU001') | |
| subject = request.args.get('subject', None) | |
| grades = school_service.get_student_grades(student_id, subject) | |
| return jsonify({ | |
| "success": True, | |
| "grades": grades | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| "success": False, | |
| "error": str(e) | |
| }), 500 | |
| def get_events(): | |
| """Get upcoming school events""" | |
| try: | |
| events = school_service.get_upcoming_events() | |
| return jsonify({ | |
| "success": True, | |
| "events": events | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| "success": False, | |
| "error": str(e) | |
| }), 500 | |
| def search_school_info(): | |
| """Search school information""" | |
| try: | |
| query = request.args.get('q', '') | |
| if not query: | |
| return jsonify({ | |
| "success": False, | |
| "error": "Search query is required" | |
| }), 400 | |
| results = school_service.search_school_info(query) | |
| return jsonify({ | |
| "success": True, | |
| "results": results, | |
| "query": query | |
| }) | |
| except Exception as e: | |
| return jsonify({ | |
| "success": False, | |
| "error": str(e) | |
| }), 500 | |
| def chat(): | |
| """Enhanced chat with school context""" | |
| try: | |
| if not client: | |
| return jsonify({"error": "OpenAI API key not configured"}), 500 | |
| data = request.json | |
| user_message = data.get("message", "") | |
| if not user_message: | |
| return jsonify({"error": "Message is required"}), 400 | |
| # Get school context for AI | |
| school_context = school_service.format_school_context_for_ai() | |
| # Enhanced system prompt for student assistant | |
| 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. | |
| {school_context} | |
| Your role is to: | |
| 1. Help students with academic questions and study support | |
| 2. Provide information about school announcements, exams, tests, and events | |
| 3. Offer study tips, time management advice, and motivation | |
| 4. Help with stress management and emotional support | |
| 5. Answer questions about grades and academic performance | |
| 6. Remind students about important dates and deadlines | |
| 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.""" | |
| # Use the enhanced OpenAI client | |
| response = client.chat.completions.create( | |
| model="gpt-3.5-turbo", | |
| messages=[ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": user_message} | |
| ], | |
| temperature=0.7, | |
| max_tokens=1000 | |
| ) | |
| reply = response.choices[0].message.content | |
| # Check if the query might be school-specific and add relevant info | |
| school_keywords = ['exam', 'test', 'grade', 'announcement', 'assignment', 'due', 'schedule'] | |
| if any(keyword in user_message.lower() for keyword in school_keywords): | |
| search_results = school_service.search_school_info(user_message) | |
| if search_results: | |
| reply += "\n\n📚 **Related School Information:**\n" | |
| for result in search_results[:3]: # Show top 3 results | |
| if result['type'] == 'exam': | |
| reply += f"• **{result['name']}** ({result['subject']}) - {result['date']} at {result['time']}\n" | |
| elif result['type'] == 'announcement': | |
| reply += f"• **{result['title']}** - {result['content'][:100]}...\n" | |
| elif result['type'] == 'test_assignment': | |
| reply += f"• **{result['title']}** ({result['subject']}) - Due: {result['due_date']}\n" | |
| return jsonify({"reply": reply}) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| # ==================== ADMIN ROUTES ==================== | |
| def admin_login_page(): | |
| """Serve admin login page""" | |
| return render_template('admin_login.html') | |
| def admin_login(): | |
| """Handle admin login""" | |
| try: | |
| data = request.json | |
| username = data.get("username") | |
| password = data.get("password") | |
| if not username or not password: | |
| return jsonify({"success": False, "error": "Username and password required"}), 400 | |
| admin = admin_service.authenticate_admin(username, password) | |
| if admin: | |
| return jsonify({"success": True, "admin": admin}) | |
| else: | |
| return jsonify({"success": False, "error": "Invalid credentials"}), 401 | |
| except Exception as e: | |
| return jsonify({"success": False, "error": str(e)}), 500 | |
| def admin_dashboard(): | |
| """Serve admin dashboard""" | |
| return render_template('admin_dashboard.html') | |
| def admin_stats(): | |
| """Get admin dashboard statistics""" | |
| try: | |
| stats = admin_service.get_admin_dashboard_stats() | |
| return jsonify({"success": True, "stats": stats}) | |
| except Exception as e: | |
| return jsonify({"success": False, "error": str(e)}), 500 | |
| # Announcement management routes | |
| def admin_get_announcements(): | |
| """Get all announcements for admin""" | |
| try: | |
| announcements = admin_service.get_all_announcements() | |
| return jsonify({"success": True, "announcements": announcements}) | |
| except Exception as e: | |
| return jsonify({"success": False, "error": str(e)}), 500 | |
| def admin_create_announcement(): | |
| """Create new announcement""" | |
| try: | |
| data = request.json | |
| announcement_id = admin_service.create_announcement( | |
| title=data.get("title"), | |
| content=data.get("content"), | |
| priority=data.get("priority", "normal"), | |
| target_audience=data.get("target_audience", "all"), | |
| expires_at=data.get("expires_at") | |
| ) | |
| return jsonify({"success": True, "id": announcement_id}) | |
| except Exception as e: | |
| return jsonify({"success": False, "error": str(e)}), 500 | |
| def admin_delete_announcement(announcement_id): | |
| """Delete announcement""" | |
| try: | |
| admin_service.delete_announcement(announcement_id) | |
| return jsonify({"success": True}) | |
| except Exception as e: | |
| return jsonify({"success": False, "error": str(e)}), 500 | |
| # Syllabus management routes | |
| def admin_get_syllabus(): | |
| """Get all syllabus entries""" | |
| try: | |
| syllabus = admin_service.get_syllabus() | |
| return jsonify({"success": True, "syllabus": syllabus}) | |
| except Exception as e: | |
| return jsonify({"success": False, "error": str(e)}), 500 | |
| def admin_create_syllabus(): | |
| """Create new syllabus entry""" | |
| try: | |
| data = request.json | |
| syllabus_id = admin_service.create_syllabus( | |
| subject=data.get("subject"), | |
| grade_level=data.get("grade_level"), | |
| chapter_number=data.get("chapter_number"), | |
| chapter_title=data.get("chapter_title"), | |
| topics=data.get("topics"), | |
| learning_objectives=data.get("learning_objectives"), | |
| duration_weeks=data.get("duration_weeks"), | |
| resources=data.get("resources"), | |
| assessment_methods=data.get("assessment_methods") | |
| ) | |
| return jsonify({"success": True, "id": syllabus_id}) | |
| except Exception as e: | |
| return jsonify({"success": False, "error": str(e)}), 500 | |
| def admin_delete_syllabus(syllabus_id): | |
| """Delete syllabus entry""" | |
| try: | |
| admin_service.update_syllabus(syllabus_id, is_active=False) | |
| return jsonify({"success": True}) | |
| except Exception as e: | |
| return jsonify({"success": False, "error": str(e)}), 500 | |
| # Timetable management routes | |
| def admin_get_timetable(): | |
| """Get all timetable entries""" | |
| try: | |
| timetable = admin_service.get_timetable() | |
| return jsonify({"success": True, "timetable": timetable}) | |
| except Exception as e: | |
| return jsonify({"success": False, "error": str(e)}), 500 | |
| def admin_create_timetable(): | |
| """Create new timetable entry""" | |
| try: | |
| data = request.json | |
| timetable_id = admin_service.create_timetable_entry( | |
| class_section=data.get("class_section"), | |
| day_of_week=data.get("day_of_week"), | |
| period_number=data.get("period_number"), | |
| start_time=data.get("start_time"), | |
| end_time=data.get("end_time"), | |
| subject=data.get("subject"), | |
| teacher_name=data.get("teacher_name"), | |
| room_number=data.get("room_number") | |
| ) | |
| return jsonify({"success": True, "id": timetable_id}) | |
| except Exception as e: | |
| return jsonify({"success": False, "error": str(e)}), 500 | |
| def admin_delete_timetable(timetable_id): | |
| """Delete timetable entry""" | |
| try: | |
| admin_service.delete_timetable_entry(timetable_id) | |
| return jsonify({"success": True}) | |
| except Exception as e: | |
| return jsonify({"success": False, "error": str(e)}), 500 | |
| def health(): | |
| """Health check endpoint""" | |
| return jsonify({ | |
| "status": "healthy", | |
| "service": "ThutoAI Enhanced", | |
| "features": ["AI Chat", "School Integration", "Student Dashboard", "Admin Panel"] | |
| }) | |
| if __name__ == "__main__": | |
| # Initialize database with sample data | |
| try: | |
| from models import DatabaseManager | |
| db = DatabaseManager() | |
| db.add_sample_data() | |
| print("Database initialized with sample data") | |
| except Exception as e: | |
| print(f"Database initialization error: {e}") | |
| print("Starting ThutoAI Enhanced - Your Complete Student Assistant") | |
| print("Features: AI Chat + School Info + Student Dashboard + Admin Panel") | |
| print("Access at: http://0.0.0.0:7860") | |
| app.run(host="0.0.0.0", port=7860, debug=True) |