Update app.py
Browse files
app.py
CHANGED
|
@@ -65,32 +65,37 @@ def update_student(student_id: str, updates: dict) -> str:
|
|
| 65 |
# FAQs (Arabic + English)
|
| 66 |
# -----------------------------
|
| 67 |
FAQS = {
|
| 68 |
-
|
| 69 |
-
"ه
|
| 70 |
-
"
|
| 71 |
-
"ال
|
| 72 |
-
"
|
| 73 |
-
"
|
| 74 |
-
"
|
| 75 |
-
"هل
|
| 76 |
-
"
|
| 77 |
-
"هل في
|
| 78 |
-
"ه
|
| 79 |
-
"
|
| 80 |
-
"ل
|
| 81 |
-
|
| 82 |
-
"
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
"What is
|
| 86 |
-
"
|
| 87 |
-
"
|
| 88 |
-
"
|
| 89 |
-
"
|
| 90 |
-
"
|
| 91 |
-
"
|
| 92 |
-
"Is
|
| 93 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
}
|
| 95 |
|
| 96 |
def _normalize(text: str) -> str:
|
|
@@ -114,11 +119,45 @@ def find_faq_answer(user_input: str, cutoff: float = 0.6) -> str | None:
|
|
| 114 |
# Prompting
|
| 115 |
# -----------------------------
|
| 116 |
ROADMAP_QUERY = """
|
| 117 |
-
Generate a personalized learning roadmap for a student
|
| 118 |
- Beginner
|
| 119 |
- Intermediate
|
| 120 |
- Advanced
|
| 121 |
- Challenge
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
"""
|
| 123 |
|
| 124 |
def _compose_profile(student: dict) -> str:
|
|
@@ -129,27 +168,105 @@ def _compose_profile(student: dict) -> str:
|
|
| 129 |
if v:
|
| 130 |
parts.append(f"{k}: {v}")
|
| 131 |
return " | ".join(parts) if parts else "No data"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
|
| 133 |
-
def get_gemini_response(query: str, student: dict | None = None) -> str:
|
| 134 |
-
profile = _compose_profile(student or {})
|
| 135 |
-
prompt = f"Student Profile: {profile}\nTask:\n{query}"
|
| 136 |
-
if _gemini_model:
|
| 137 |
-
try:
|
| 138 |
-
resp = _gemini_model.generate_content(prompt)
|
| 139 |
-
return getattr(resp, "text", "").strip()
|
| 140 |
-
except Exception as e:
|
| 141 |
-
return f"(Gemini error) {e}"
|
| 142 |
-
return f"(Simulated) {prompt[:400]}..."
|
| 143 |
-
|
| 144 |
-
def generate_ai_insights(student: dict) -> str:
|
| 145 |
-
profile = _compose_profile(student or {})
|
| 146 |
-
if _gemini_model:
|
| 147 |
-
try:
|
| 148 |
-
resp = _gemini_model.generate_content(f"Insights for: {profile}")
|
| 149 |
-
return getattr(resp, "text", "").strip()
|
| 150 |
-
except Exception as e:
|
| 151 |
-
return f"(Gemini error) {e}"
|
| 152 |
-
return f"(Simulated insights) {profile}"
|
| 153 |
|
| 154 |
# -----------------------------
|
| 155 |
# Chat logic
|
|
|
|
| 65 |
# FAQs (Arabic + English)
|
| 66 |
# -----------------------------
|
| 67 |
FAQS = {
|
| 68 |
+
# Arabic
|
| 69 |
+
"إيه هو ThinkPal؟": "ThinkPal منصة بتساعدك تعرف نفسك أكتر وتتعلم بالطريقة اللي تناسبك وكمان تديك خطة تعليمية واضحة خطوة بخطوة علشان توصل لهدفك.",
|
| 70 |
+
"هل الموقع للثانوي ولا الجامعة؟": "ThinkPal معمول بالأساس لطلاب الجامعة لكن أي طالب حابب يطور من نفسه أو يكتشف طريقه يقدر يستخدمه.",
|
| 71 |
+
"أنا ليه أجاوب على الأسئلة أول ما أدخل؟": "لأن الأسئلة دي بتساعد المنصة تفهم شخصيتك وطريقة تفكيرك وتعلمك ومن هنا تقدر تبني لك خطة تناسبك أنت بالذات.",
|
| 72 |
+
"الأسئلة اللي بتظهر صعبة شوية أجاوب إزاي؟": "دا مش امتحان ومفيش إجابة صح أو غلط، جاوب بطريقتك وباللي يمثلك. كل إجابة بتقرب الصورة أكتر.",
|
| 73 |
+
"الخطة التعليمية بتكون إيه بالظبط؟": "الخطة عبارة عن خطوات من مستوى مبتدئ لحد مستوى متقدم ومع كل خطوة هتلاقي مصادر موثوقة للتعلم وتدريبات تساعدك تطبق اللي بتتعلمه.",
|
| 74 |
+
"هل المصادر كلها مجانية؟": "فيه مصادر كتير مجانية وفيه كمان مصادر مدفوعة بنرشحها أحيانًا علشان تبقى قدامك كل الاختيارات.",
|
| 75 |
+
"هل لازم أمشي بالخطة زي ما هي؟": "الخطة معمولة علشان تسهل عليك لكن في الآخر إنت بتختار سرعة العملية التعليمية.",
|
| 76 |
+
"يعني ThinkPal بديل للدروس أو الكورسات؟": "لأ ThinkPal مش بديل هو زي دليل أو صديق بيرتب لك الطريق ويقولك تبدأ منين وتروح فين.",
|
| 77 |
+
"هل في متابعة لتقدمي؟": "أيوة عندك Dashboard شخصي يوضح إنجازاتك، الاختبارات اللي عملتها، تقييمك، Badges، وأي نقاط محتاجة تشتغل عليها.",
|
| 78 |
+
"إيه هي Insights اللي بتظهرلي؟": "دي ملاحظات بتقولك إيه نقاط قوتك وإيه الحاجات اللي محتاجة تحسين وكمان نصايح عملية تساعدك تطور نفسك.",
|
| 79 |
+
"هل فيه تواصل مع طلاب تانيين؟": "أيوة فيه مجتمع جوا المنصة تقدر تتكلم فيه مع طلبة زيك وكمان فيه Mentors يساعدوك لو محتاج.",
|
| 80 |
+
"هل المنصة بتركز على الدراسة بس؟": "لأ ThinkPal بيساعدك في الدراسة وكمان في تطوير شخصيتك و مهاراتك وحتى في إنك تحدد وتختار مستقبلك بشكل أوضح.",
|
| 81 |
+
"الخصوصية آمنة؟": "أكيد بياناتك محمية ومفيش حد يقدر يشوفها غيرك.",
|
| 82 |
+
"لو وقفت في نص الطريق؟": "مفيش مشكلة، تقدر ترجع في أي وقت وتكمل من نفس المكان اللي وصلتله.",
|
| 83 |
+
|
| 84 |
+
# English
|
| 85 |
+
"What is ThinkPal?": "ThinkPal is a platform that helps you understand yourself better, learn in the way that suits you, and gives you a clear step-by-step learning plan to achieve your goals.",
|
| 86 |
+
"Is the platform for high school or university students?": "ThinkPal is mainly designed for university students, but any student who wants to improve or discover their path can use it.",
|
| 87 |
+
"Why should I answer the questions when I first join?": "These questions help the platform understand your personality, thinking, and learning style, so it can build a plan tailored to you.",
|
| 88 |
+
"The questions seem difficult, how should I answer?": "This is not an exam, and there are no right or wrong answers. Just answer in your own way with what represents you.",
|
| 89 |
+
"What exactly is the learning roadmap?": "It’s a step-by-step plan from beginner to advanced levels. Each step includes trusted resources and exercises to help you apply what you learn.",
|
| 90 |
+
"Are all resources free?": "Many resources are free, but we sometimes recommend paid resources to give you all available options.",
|
| 91 |
+
"Do I have to follow the roadmap exactly as it is?": "The roadmap is designed to make it easier for you, but in the end, you choose the pace of your learning.",
|
| 92 |
+
"Is ThinkPal a replacement for lessons or courses?": "No, ThinkPal is not a replacement. It’s more like a guide or a friend that organizes your path and tells you where to start and where to go.",
|
| 93 |
+
"Is my progress tracked?": "Yes, you have a personal dashboard that shows your achievements, completed tests, evaluations, badges, and areas you need to work on.",
|
| 94 |
+
"What are the insights shown to me?": "They are notes that highlight your strengths, areas for improvement, and practical tips to help you develop.",
|
| 95 |
+
"Can I connect with other students?": "Yes, there’s a community inside the platform where you can talk with other students and get support from mentors if needed.",
|
| 96 |
+
"Does the platform focus only on studying?": "No, ThinkPal helps with studying, but also with personal growth, skills development, and even clarifying your future direction.",
|
| 97 |
+
"Is my privacy safe?": "Of course, your data is protected and no one can see it except you.",
|
| 98 |
+
"What if I stop halfway?": "No problem, you can return anytime and continue from where you left off.",
|
| 99 |
}
|
| 100 |
|
| 101 |
def _normalize(text: str) -> str:
|
|
|
|
| 119 |
# Prompting
|
| 120 |
# -----------------------------
|
| 121 |
ROADMAP_QUERY = """
|
| 122 |
+
Generate a personalized learning roadmap for a student, structured into distinct phases:
|
| 123 |
- Beginner
|
| 124 |
- Intermediate
|
| 125 |
- Advanced
|
| 126 |
- Challenge
|
| 127 |
+
|
| 128 |
+
When creating the roadmap, consider the student's:
|
| 129 |
+
- Learning style
|
| 130 |
+
- Academic progress
|
| 131 |
+
- Personality
|
| 132 |
+
- Interests
|
| 133 |
+
- Goals
|
| 134 |
+
- Current level
|
| 135 |
+
- Preferred learning methods
|
| 136 |
+
- IQ level
|
| 137 |
+
- EQ level
|
| 138 |
+
- Decision-making style
|
| 139 |
+
- Motivation level
|
| 140 |
+
- Preferred study environment
|
| 141 |
+
|
| 142 |
+
The roadmap should help the student achieve their stated goals based on their unique characteristics.
|
| 143 |
+
|
| 144 |
+
For each phase, suggest specific types of resources tailored to the student's profile, such as:
|
| 145 |
+
- Online courses
|
| 146 |
+
- Books
|
| 147 |
+
- Interactive tools
|
| 148 |
+
- Hands-on projects
|
| 149 |
+
- Community engagement opportunities
|
| 150 |
+
|
| 151 |
+
Formatting requirements:
|
| 152 |
+
- Use plain text only (no **bold**, no markdown, no emojis, no AI disclaimers).
|
| 153 |
+
- Organize information with numbered lists and subheadings.
|
| 154 |
+
- Keep the tone professional, concise, and human-like.
|
| 155 |
+
|
| 156 |
+
Finally, structure the roadmap into the following sections:
|
| 157 |
+
1. Current Status
|
| 158 |
+
2. Goals
|
| 159 |
+
3. Recommended Resources & Activities (by Phase)
|
| 160 |
+
4. Milestones (by Phase)
|
| 161 |
"""
|
| 162 |
|
| 163 |
def _compose_profile(student: dict) -> str:
|
|
|
|
| 168 |
if v:
|
| 169 |
parts.append(f"{k}: {v}")
|
| 170 |
return " | ".join(parts) if parts else "No data"
|
| 171 |
+
def get_gemini_response(query: str, student_data: dict | None = None) -> str:
|
| 172 |
+
"""Sends query to Gemini API with optional student data (ThinkPal context)."""
|
| 173 |
+
try:
|
| 174 |
+
if not genai:
|
| 175 |
+
return f"(Simulated) {query[:400]}..."
|
| 176 |
+
|
| 177 |
+
model = genai.GenerativeModel("models/gemma-3n-e2b-it")
|
| 178 |
+
personalized_prompt = query
|
| 179 |
+
|
| 180 |
+
if student_data:
|
| 181 |
+
# Build profile dynamically
|
| 182 |
+
profile_parts = []
|
| 183 |
+
for key, label in [
|
| 184 |
+
("learning_style", "Learning Style"),
|
| 185 |
+
("academic_progress", "Academic Progress"),
|
| 186 |
+
("personality", "Personality"),
|
| 187 |
+
("interests", "Interests"),
|
| 188 |
+
("goals", "Goals"),
|
| 189 |
+
("level", "Level"),
|
| 190 |
+
("preferred_methods", "Preferred Methods"),
|
| 191 |
+
("iq_level", "IQ Level"),
|
| 192 |
+
("eq_level", "EQ Level"),
|
| 193 |
+
("decision_making_style", "Decision-Making Style"),
|
| 194 |
+
("motivation_level", "Motivation Level"),
|
| 195 |
+
("preferred_study_environment", "Preferred Study Environment"),
|
| 196 |
+
("community_groups", "Community Groups"),
|
| 197 |
+
]:
|
| 198 |
+
value = student_data.get(key)
|
| 199 |
+
if isinstance(value, list):
|
| 200 |
+
value = ", ".join(value)
|
| 201 |
+
if value:
|
| 202 |
+
profile_parts.append(f"{label}: {value}")
|
| 203 |
+
|
| 204 |
+
student_profile = ", ".join(profile_parts) if profile_parts else "No student data provided."
|
| 205 |
+
|
| 206 |
+
personalized_prompt = f"""
|
| 207 |
+
The student's profile is: {student_profile}.
|
| 208 |
+
|
| 209 |
+
Based on this profile, generate the following:
|
| 210 |
+
|
| 211 |
+
{query}
|
| 212 |
+
|
| 213 |
+
Formatting requirements:
|
| 214 |
+
- Use plain text only (no **bold**, no markdown, no emojis, no AI disclaimers).
|
| 215 |
+
- Organize information with numbered lists and subheadings.
|
| 216 |
+
- Keep the tone professional, concise, and human-like.
|
| 217 |
+
"""
|
| 218 |
+
|
| 219 |
+
response = model.generate_content(personalized_prompt)
|
| 220 |
+
return getattr(response, "text", "").strip() or "(Empty response)"
|
| 221 |
+
|
| 222 |
+
except Exception as e:
|
| 223 |
+
return f"(Gemini error fallback) {str(e)[:160]}"
|
| 224 |
+
|
| 225 |
+
|
| 226 |
+
def generate_ai_insights(student_data: dict) -> str:
|
| 227 |
+
"""Generates AI-driven insights based on student data."""
|
| 228 |
+
if not student_data:
|
| 229 |
+
return "Student data not available for generating insights."
|
| 230 |
+
|
| 231 |
+
profile_parts = []
|
| 232 |
+
for key, label in [
|
| 233 |
+
("learning_style", "Learning Style"),
|
| 234 |
+
("academic_progress", "Academic Progress"),
|
| 235 |
+
("personality", "Personality"),
|
| 236 |
+
("interests", "Interests"),
|
| 237 |
+
("goals", "Goals"),
|
| 238 |
+
("level", "Level"),
|
| 239 |
+
("preferred_methods", "Preferred Methods"),
|
| 240 |
+
("iq_level", "IQ Level"),
|
| 241 |
+
("eq_level", "EQ Level"),
|
| 242 |
+
("decision_making_style", "Decision-Making Style"),
|
| 243 |
+
("motivation_level", "Motivation Level"),
|
| 244 |
+
("preferred_study_environment", "Preferred Study Environment"),
|
| 245 |
+
("community_groups", "Community Groups"),
|
| 246 |
+
]:
|
| 247 |
+
value = student_data.get(key)
|
| 248 |
+
if isinstance(value, list):
|
| 249 |
+
value = ", ".join(value)
|
| 250 |
+
if value:
|
| 251 |
+
profile_parts.append(f"- {label}: {value}")
|
| 252 |
+
|
| 253 |
+
student_profile = "\n".join(profile_parts) if profile_parts else "No detailed data provided."
|
| 254 |
+
|
| 255 |
+
insights_prompt = f"""
|
| 256 |
+
Analyze the following student profile and provide AI-driven insights,
|
| 257 |
+
highlighting their strengths and potential areas for improvement.
|
| 258 |
+
|
| 259 |
+
Student Profile:
|
| 260 |
+
{student_profile}
|
| 261 |
+
|
| 262 |
+
Formatting requirements:
|
| 263 |
+
- Use plain text only (no **bold**, no markdown, no emojis, no AI disclaimers).
|
| 264 |
+
- Organize insights clearly with numbered or bulleted points.
|
| 265 |
+
- Keep the tone professional, concise, and human-like.
|
| 266 |
+
"""
|
| 267 |
+
|
| 268 |
+
return get_gemini_response(insights_prompt, student_data)
|
| 269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
|
| 271 |
# -----------------------------
|
| 272 |
# Chat logic
|