Mahdi Naser Moghadasi commited on
Commit
6cff14b
·
1 Parent(s): 9ffab0c

Refactor app.py into modular architecture

Browse files

- Created config.py for configuration and constants
- Created database.py for database operations
- Created email_service.py for email functionality
- Created ai_services.py for AI/ML related functions
- Created content_generators.py for lesson plan and quiz generation
- Created ui_components.py for Gradio interface components
- Created utils.py for utility functions
- Created app_modular.py as new main entry point
- Updated generate_image_with_huggingface with improved error handling and multiple model fallbacks
- Improved code organization and maintainability

Files changed (8) hide show
  1. ai_services.py +280 -0
  2. app_modular.py +37 -0
  3. config.py +65 -0
  4. content_generators.py +643 -0
  5. database.py +143 -0
  6. email_service.py +101 -0
  7. ui_components.py +577 -0
  8. utils.py +254 -0
ai_services.py ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ AI services module for BrightMind AI
3
+ Handles all AI/ML related functionality including Hugging Face API calls and image generation
4
+ """
5
+
6
+ import requests
7
+ import base64
8
+ from config import HF_TOKEN, HUGGINGFACE_HEADERS
9
+
10
+
11
+ def call_hugging_face_api(prompt):
12
+ """Call Hugging Face API for Albert chatbot"""
13
+ if not HF_TOKEN:
14
+ return None
15
+
16
+ headers = {
17
+ "Authorization": f"Bearer {HF_TOKEN}",
18
+ "Content-Type": "application/json"
19
+ }
20
+
21
+ data = {
22
+ "model": "deepseek-ai/DeepSeek-V3-0324",
23
+ "messages": [
24
+ {
25
+ "role": "user",
26
+ "content": prompt
27
+ }
28
+ ],
29
+ "max_tokens": 200,
30
+ "temperature": 0.7
31
+ }
32
+
33
+ try:
34
+ response = requests.post(
35
+ "https://router.huggingface.co/v1/chat/completions",
36
+ headers=headers,
37
+ json=data,
38
+ timeout=30
39
+ )
40
+
41
+ if response.status_code == 200:
42
+ result = response.json()
43
+ return result['choices'][0]['message']['content']
44
+ else:
45
+ print(f"❌ Albert API error: {response.status_code}")
46
+ return None
47
+ except Exception as e:
48
+ print(f"❌ Albert API error: {str(e)}")
49
+ return None
50
+
51
+
52
+ def call_hugging_face_api_content(prompt):
53
+ """Call Hugging Face API for content generation with more tokens"""
54
+ if not HF_TOKEN:
55
+ return None
56
+
57
+ headers = {
58
+ "Authorization": f"Bearer {HF_TOKEN}",
59
+ "Content-Type": "application/json"
60
+ }
61
+
62
+ data = {
63
+ "model": "deepseek-ai/DeepSeek-V3-0324",
64
+ "messages": [
65
+ {
66
+ "role": "user",
67
+ "content": prompt
68
+ }
69
+ ],
70
+ "max_tokens": 1000, # More tokens for content generation
71
+ "temperature": 0.7
72
+ }
73
+
74
+ try:
75
+ print(f"🌐 Making API call for content generation...")
76
+ print(f"🔗 Endpoint: https://router.huggingface.co/v1/chat/completions")
77
+ print(f"🔑 Token available: {HF_TOKEN is not None}")
78
+ print(f"📝 Prompt length: {len(prompt)} characters")
79
+
80
+ response = requests.post(
81
+ "https://router.huggingface.co/v1/chat/completions",
82
+ headers=headers,
83
+ json=data,
84
+ timeout=60 # Longer timeout for content generation
85
+ )
86
+
87
+ print(f"📊 Response status: {response.status_code}")
88
+
89
+ if response.status_code == 200:
90
+ result = response.json()
91
+ content = result['choices'][0]['message']['content']
92
+ print(f"✅ Content generation successful! Length: {len(content)} characters")
93
+ return content
94
+ else:
95
+ print(f"❌ Content API error: {response.status_code}")
96
+ print(f"❌ Response: {response.text}")
97
+ return None
98
+ except Exception as e:
99
+ print(f"❌ Content API error: {str(e)}")
100
+ return None
101
+
102
+
103
+ def generate_image_with_huggingface(prompt, topic, content_type):
104
+ """Generate image using only Hugging Face Inference API models"""
105
+ try:
106
+ if not HF_TOKEN:
107
+ print("No HF_TOKEN available for image generation")
108
+ return None
109
+
110
+ headers = {
111
+ "Authorization": f"Bearer {HF_TOKEN}",
112
+ "Content-Type": "application/json"
113
+ }
114
+
115
+ # Models available on Hugging Face Inference API
116
+ models = [
117
+ "runwayml/stable-diffusion-v1-5",
118
+ "CompVis/stable-diffusion-v1-4",
119
+ "stabilityai/stable-diffusion-2-1",
120
+ "prompthero/openjourney",
121
+ "dreamlike-art/dreamlike-diffusion-1.0"
122
+ ]
123
+
124
+ # Simple prompt optimized for educational content
125
+ clean_prompt = f"educational diagram of {topic}, simple illustration, clean design, white background"
126
+
127
+ print(f"Generating image for: {topic}")
128
+ print(f"Using prompt: {clean_prompt}")
129
+
130
+ for model_name in models:
131
+ try:
132
+ print(f"Trying model: {model_name}")
133
+
134
+ # Use the correct API format for HF Inference API
135
+ payload = {"inputs": clean_prompt}
136
+
137
+ response = requests.post(
138
+ f"https://api-inference.huggingface.co/models/{model_name}",
139
+ headers=headers,
140
+ json=payload,
141
+ timeout=60
142
+ )
143
+
144
+ print(f"Response status: {response.status_code}")
145
+
146
+ if response.status_code == 200:
147
+ content_length = len(response.content)
148
+ print(f"Content length: {content_length} bytes")
149
+
150
+ # Check if we got actual image data (not error JSON)
151
+ if content_length > 5000:
152
+ try:
153
+ # Try to decode as JSON first to check for errors
154
+ json_response = response.json()
155
+ if "error" in json_response:
156
+ print(f"API error: {json_response['error']}")
157
+ continue
158
+ except:
159
+ # If it's not JSON, it should be binary image data
160
+ import base64
161
+ image_base64 = base64.b64encode(response.content).decode('utf-8')
162
+ print(f"Successfully generated image with {model_name}")
163
+ return f"data:image/png;base64,{image_base64}"
164
+ else:
165
+ print("Response too small, likely an error")
166
+
167
+ elif response.status_code == 503:
168
+ # Model is loading - this is common on first request
169
+ try:
170
+ error_info = response.json()
171
+ if "estimated_time" in error_info:
172
+ print(f"Model loading, estimated time: {error_info['estimated_time']} seconds")
173
+ else:
174
+ print("Model is currently loading")
175
+ except:
176
+ print("Model unavailable (503)")
177
+ continue
178
+
179
+ elif response.status_code == 401:
180
+ print("Authentication failed - invalid HF_TOKEN")
181
+ break
182
+
183
+ else:
184
+ print(f"HTTP {response.status_code}: {response.text[:200]}")
185
+
186
+ except requests.exceptions.Timeout:
187
+ print(f"Timeout with model {model_name}")
188
+ continue
189
+ except Exception as model_error:
190
+ print(f"Error with model {model_name}: {str(model_error)}")
191
+ continue
192
+
193
+ print("All models failed or unavailable")
194
+ return None
195
+
196
+ except Exception as e:
197
+ print(f"Critical error in image generation: {str(e)}")
198
+ return None
199
+
200
+
201
+ def get_educational_image_url(topic, description, content_type):
202
+ """Get educational image URL using Hugging Face generation first, then fallbacks"""
203
+ try:
204
+ # Create a detailed prompt for image generation
205
+ image_prompt = f"Educational illustration of {topic}, {description}, {content_type}, clean diagram, colorful, professional, suitable for middle school students"
206
+
207
+ print(f"🎨 Generating image with prompt: {image_prompt}")
208
+
209
+ # Try to generate image with Hugging Face first
210
+ generated_image = generate_image_with_huggingface(image_prompt, topic, content_type)
211
+
212
+ if generated_image:
213
+ print(f"✅ Generated image successfully")
214
+ return generated_image
215
+
216
+ # Fallback to reliable sources if generation fails
217
+ print("🔄 Image generation failed, using fallback sources")
218
+
219
+ educational_sources = [
220
+ # 1. Lorem Picsum (reliable placeholder)
221
+ f"https://picsum.photos/800/600?random={hash(topic) % 1000}",
222
+
223
+ # 2. Placeholder with educational styling
224
+ f"https://via.placeholder.com/800x600/667eea/ffffff?text={topic.replace(' ', '+')}+Educational+Content",
225
+
226
+ # 3. Educational diagram generator
227
+ f"https://via.placeholder.com/800x600/4f46e5/ffffff?text={content_type.replace(' ', '+')}+{topic.replace(' ', '+')}",
228
+ ]
229
+
230
+ # Try each fallback source
231
+ for i, url in enumerate(educational_sources):
232
+ try:
233
+ print(f"🔍 Trying fallback source {i+1}: {url}")
234
+ response = requests.head(url, timeout=5)
235
+ if response.status_code == 200:
236
+ print(f"✅ Found working fallback image: {url}")
237
+ return url
238
+ except:
239
+ continue
240
+
241
+ # Final fallback
242
+ return f"https://via.placeholder.com/800x600/667eea/ffffff?text={topic.replace(' ', '+')}+{content_type.replace(' ', '+')}"
243
+
244
+ except Exception as e:
245
+ print(f"❌ Image URL generation error: {str(e)}")
246
+ return f"https://via.placeholder.com/800x600/667eea/ffffff?text={topic.replace(' ', '+')}+{content_type.replace(' ', '+')}"
247
+
248
+
249
+ def generate_real_image(description, topic, content_type):
250
+ """Generate actual image for educational content"""
251
+ try:
252
+ # Try to generate image with Hugging Face
253
+ image_data = generate_image_with_huggingface(description, topic, content_type)
254
+
255
+ if image_data:
256
+ return f'\n<img src="{image_data}" alt="{description}" style="max-width: 100%; height: auto; border-radius: 8px; margin: 20px 0;">\n'
257
+ else:
258
+ # Fallback to text placeholder
259
+ return f"\n**[📸 Image: {description}]**\n*Visual content would appear here*\n"
260
+
261
+ except Exception as e:
262
+ return f"\n**[📸 Image: {description}]**\n*Visual content would appear here*\n"
263
+
264
+
265
+ def generate_image_placeholder(description, topic, content_type):
266
+ """Generate image placeholder with description for educational content (fallback)"""
267
+ # Create a structured image placeholder that can be replaced with real images
268
+ image_placeholder = f"""
269
+ <div style="border: 2px dashed #667eea; padding: 20px; margin: 20px 0; text-align: center; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); border-radius: 12px;">
270
+ <div style="font-size: 48px; margin-bottom: 10px;">🖼️</div>
271
+ <h3 style="color: #667eea; margin: 10px 0;">📸 Image Placeholder</h3>
272
+ <p style="color: #4a5568; margin: 10px 0;"><strong>Description:</strong> {description}</p>
273
+ <p style="color: #718096; font-size: 14px; margin: 5px 0;"><strong>Topic:</strong> {topic}</p>
274
+ <p style="color: #718096; font-size: 14px; margin: 5px 0;"><strong>Content Type:</strong> {content_type}</p>
275
+ <div style="background: #667eea; color: white; padding: 8px 16px; border-radius: 6px; display: inline-block; margin-top: 10px; font-size: 12px;">
276
+ 💡 This image would enhance the learning experience
277
+ </div>
278
+ </div>
279
+ """
280
+ return image_placeholder
app_modular.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ BrightMind AI - Modular Educational Assistant
3
+ Main application file using modular architecture
4
+ """
5
+
6
+ import gradio as gr
7
+ from config import debug_token_status
8
+ from database import init_database
9
+ from ui_components import create_main_interface
10
+
11
+
12
+ def main():
13
+ """Main application entry point"""
14
+
15
+ # Debug token status
16
+ debug_token_status()
17
+
18
+ # Initialize database
19
+ print("🔧 Initializing database...")
20
+ init_database()
21
+
22
+ # Create and launch the interface
23
+ print("🚀 Starting BrightMind AI...")
24
+ interface = create_main_interface()
25
+
26
+ # Launch the application
27
+ interface.launch(
28
+ server_name="0.0.0.0",
29
+ server_port=7860,
30
+ share=False,
31
+ debug=True,
32
+ show_error=True
33
+ )
34
+
35
+
36
+ if __name__ == "__main__":
37
+ main()
config.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Configuration module for BrightMind AI
3
+ Contains all configuration constants and environment variables
4
+ """
5
+
6
+ import os
7
+
8
+ # Get Hugging Face token from environment variable
9
+ HF_TOKEN = os.getenv("HUGGINGFACE_TOKEN")
10
+
11
+ # Database configuration
12
+ DATABASE_FILE = "feedback.db"
13
+
14
+ # Email configuration (private)
15
+ FEEDBACK_EMAIL = "mahdi@brightmind-ai.com"
16
+ SMTP_SERVER = "smtp.gmail.com"
17
+ SMTP_PORT = 587
18
+ SMTP_USERNAME = os.getenv("SMTP_USERNAME", "")
19
+ SMTP_PASSWORD = os.getenv("SMTP_PASSWORD", "")
20
+
21
+ # Debug token detection
22
+ def debug_token_status():
23
+ """Print debug information about token status"""
24
+ print(f"🔍 Token detection debug:")
25
+ print(f" - HF_TOKEN exists: {HF_TOKEN is not None}")
26
+ print(f" - HF_TOKEN length: {len(HF_TOKEN) if HF_TOKEN else 0}")
27
+ print(f" - HF_TOKEN starts with hf_: {HF_TOKEN.startswith('hf_') if HF_TOKEN else False}")
28
+ print(f" - SMTP configured: {SMTP_USERNAME != '' and SMTP_PASSWORD != ''}")
29
+
30
+ # Hugging Face API configuration
31
+ HUGGINGFACE_API_URL = "https://api-inference.huggingface.co/models/microsoft/DialoGPT-medium"
32
+ HUGGINGFACE_HEADERS = {
33
+ "Authorization": f"Bearer {HF_TOKEN}" if HF_TOKEN else None
34
+ }
35
+
36
+ # Content generation settings
37
+ DEFAULT_DIFFICULTY = "intermediate"
38
+ DEFAULT_QUESTION_COUNT = 5
39
+ DEFAULT_DURATION = 60
40
+
41
+ # UI Configuration
42
+ PROGRESS_HTML = """
43
+ <div class="progress-container">
44
+ <div class="generation-status">🤖 Generating your lesson plan...</div>
45
+ <div class="progress-bar">
46
+ <div class="progress-fill"></div>
47
+ </div>
48
+ <div class="generation-status">Analyzing requirements and creating content...</div>
49
+ </div>
50
+ """
51
+
52
+ COMPLETION_HTML = """
53
+ <div class="progress-container">
54
+ <div class="generation-status">✅ Lesson Plan Generated Successfully!</div>
55
+ </div>
56
+ """
57
+
58
+ FALLBACK_HTML = """
59
+ <div class="progress-container">
60
+ <div class="generation-status">🔄 Using educational algorithms...</div>
61
+ <div class="progress-bar">
62
+ <div class="progress-fill"></div>
63
+ </div>
64
+ </div>
65
+ """
content_generators.py ADDED
@@ -0,0 +1,643 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Content generators module for BrightMind AI
3
+ Handles lesson plan and quiz generation functionality
4
+ """
5
+
6
+ from config import HF_TOKEN, PROGRESS_HTML, COMPLETION_HTML, FALLBACK_HTML
7
+ from ai_services import call_hugging_face_api_content
8
+ from utils import typewriter_effect, process_content_with_images, apply_content_styling
9
+
10
+
11
+ def generate_lesson_plan_with_progress(topic, subject, grade_level, duration, difficulty="intermediate"):
12
+ """Generate a lesson plan with progress updates"""
13
+
14
+ # Show progress bar
15
+ yield PROGRESS_HTML, ""
16
+
17
+ print(f"🚀 Starting lesson plan generation for: {topic}")
18
+ print(f"📚 Subject: {subject}, Grade: {grade_level}, Duration: {duration}min")
19
+
20
+ # Try Hugging Face API first if token is available
21
+ if HF_TOKEN:
22
+ print("🤖 Token found! Attempting Hugging Face API call...")
23
+ try:
24
+ prompt = f"""Create a comprehensive lesson plan for:
25
+ Topic: {topic}
26
+ Subject: {subject}
27
+ Grade Level: {grade_level}
28
+ Duration: {duration} minutes
29
+ Difficulty: {difficulty}
30
+
31
+ Include:
32
+ 1. Learning objectives
33
+ 2. Activities with time allocations
34
+ 3. Materials needed
35
+ 4. Assessment methods
36
+ 5. Differentiation strategies
37
+ 6. Educational standards
38
+ 7. Real-world connections
39
+ 8. Extension activities
40
+
41
+ Make it practical, engaging, and ready for classroom use."""
42
+
43
+ result = call_hugging_face_api_content(prompt)
44
+
45
+ if result:
46
+ print("✅ Successfully generated with Hugging Face API")
47
+
48
+ # Show completion and return result
49
+ yield COMPLETION_HTML, result
50
+ else:
51
+ print("❌ API call returned no content, falling back to algorithms")
52
+ raise Exception("No content returned from API")
53
+
54
+ except Exception as e:
55
+ print(f"❌ Hugging Face API failed: {e}")
56
+ print("🔄 Falling back to educational algorithms...")
57
+
58
+ # Show fallback progress
59
+ yield FALLBACK_HTML, ""
60
+
61
+ result = generate_with_algorithms(topic, subject, grade_level, duration, difficulty)
62
+ print("✅ Generated with educational algorithms")
63
+
64
+ # Show completion
65
+ yield COMPLETION_HTML, result
66
+ else:
67
+ print("⚠️ No Hugging Face token found, using educational algorithms...")
68
+
69
+ # Show progress for algorithms
70
+ yield FALLBACK_HTML, ""
71
+
72
+ result = generate_with_algorithms(topic, subject, grade_level, duration, difficulty)
73
+ print("✅ Generated with educational algorithms")
74
+
75
+ # Show completion
76
+ yield COMPLETION_HTML, result
77
+
78
+
79
+ def generate_lesson_plan(topic, subject, grade_level, duration, difficulty="intermediate"):
80
+ """Generate a lesson plan using Hugging Face API or fallback algorithms"""
81
+
82
+ print(f"🚀 Starting lesson plan generation for: {topic}")
83
+ print(f"📚 Subject: {subject}, Grade: {grade_level}, Duration: {duration}min")
84
+
85
+ # Try Hugging Face API first if token is available
86
+ if HF_TOKEN:
87
+ print("🤖 Token found! Attempting Hugging Face API call...")
88
+ try:
89
+ result = generate_with_hugging_face(topic, subject, grade_level, duration, difficulty)
90
+ print("✅ Successfully generated with Hugging Face API")
91
+ return result
92
+ except Exception as e:
93
+ print(f"❌ Hugging Face API failed: {e}")
94
+ print("🔄 Falling back to educational algorithms...")
95
+ else:
96
+ print("⚠️ No Hugging Face token found, using educational algorithms...")
97
+
98
+ # Fallback to educational algorithms
99
+ result = generate_with_algorithms(topic, subject, grade_level, duration, difficulty)
100
+ print("✅ Generated with educational algorithms")
101
+ return result
102
+
103
+
104
+ def generate_with_hugging_face(topic, subject, grade_level, duration, difficulty):
105
+ """Generate lesson plan using Hugging Face API"""
106
+ prompt = f"""Create a comprehensive lesson plan for:
107
+ Topic: {topic}
108
+ Subject: {subject}
109
+ Grade Level: {grade_level}
110
+ Duration: {duration} minutes
111
+ Difficulty: {difficulty}
112
+
113
+ Include:
114
+ 1. Learning objectives
115
+ 2. Activities with time allocations
116
+ 3. Materials needed
117
+ 4. Assessment methods
118
+ 5. Differentiation strategies
119
+ 6. Educational standards
120
+ 7. Real-world connections
121
+ 8. Extension activities
122
+
123
+ Make it practical, engaging, and ready for classroom use."""
124
+
125
+ result = call_hugging_face_api_content(prompt)
126
+
127
+ if result:
128
+ return format_lesson_plan(result, topic, subject, grade_level, duration, True)
129
+ else:
130
+ raise Exception("No content returned from API")
131
+
132
+
133
+ def generate_with_algorithms(topic, subject, grade_level, duration, difficulty):
134
+ """Generate lesson plan using educational algorithms"""
135
+
136
+ # Generate lesson plan components
137
+ objectives = generate_objectives(topic, grade_level)
138
+ activities = generate_activities(topic, duration, grade_level)
139
+ materials = generate_materials(subject, grade_level)
140
+ assessment = generate_assessment(grade_level)
141
+ differentiation = generate_differentiation()
142
+
143
+ # Create structured lesson plan
144
+ lesson_plan = {
145
+ "topic": topic,
146
+ "subject": subject,
147
+ "grade_level": grade_level,
148
+ "duration": duration,
149
+ "difficulty": difficulty,
150
+ "objectives": objectives,
151
+ "activities": activities,
152
+ "materials": materials,
153
+ "assessment": assessment,
154
+ "differentiation": differentiation
155
+ }
156
+
157
+ return format_lesson_plan_from_dict(lesson_plan)
158
+
159
+
160
+ def generate_objectives(topic, grade):
161
+ """Generate learning objectives for a topic and grade level"""
162
+ objectives = [
163
+ f"Students will understand the key concepts of {topic}",
164
+ f"Students will be able to explain {topic} in their own words",
165
+ f"Students will apply knowledge of {topic} to solve problems"
166
+ ]
167
+
168
+ if grade in ["6th", "7th", "8th"]:
169
+ objectives.append(f"Students will analyze the relationship between {topic} and real-world applications")
170
+ elif grade in ["9th", "10th", "11th", "12th"]:
171
+ objectives.append(f"Students will evaluate different perspectives on {topic}")
172
+ objectives.append(f"Students will create original work demonstrating understanding of {topic}")
173
+
174
+ return objectives
175
+
176
+
177
+ def generate_activities(topic, duration, grade):
178
+ """Generate activities for a lesson plan"""
179
+ activities = []
180
+
181
+ # Opening activity (10% of duration)
182
+ opening_time = max(5, duration // 10)
183
+ activities.append({
184
+ "name": f"Introduction to {topic}",
185
+ "duration": f"{opening_time} minutes",
186
+ "description": f"Engage students with a thought-provoking question about {topic}"
187
+ })
188
+
189
+ # Main activities (70% of duration)
190
+ main_time = int(duration * 0.7)
191
+ if main_time > 20:
192
+ activities.append({
193
+ "name": f"Explore {topic}",
194
+ "duration": f"{main_time // 2} minutes",
195
+ "description": f"Hands-on exploration of {topic} concepts"
196
+ })
197
+ activities.append({
198
+ "name": f"Practice with {topic}",
199
+ "duration": f"{main_time - main_time // 2} minutes",
200
+ "description": f"Guided practice and application of {topic}"
201
+ })
202
+ else:
203
+ activities.append({
204
+ "name": f"Learn about {topic}",
205
+ "duration": f"{main_time} minutes",
206
+ "description": f"Interactive learning about {topic}"
207
+ })
208
+
209
+ # Closing activity (20% of duration)
210
+ closing_time = max(5, duration - opening_time - main_time)
211
+ activities.append({
212
+ "name": f"Reflect on {topic}",
213
+ "duration": f"{closing_time} minutes",
214
+ "description": f"Students share what they learned about {topic}"
215
+ })
216
+
217
+ return activities
218
+
219
+
220
+ def generate_materials(subject, grade):
221
+ """Generate materials list for a lesson"""
222
+ base_materials = [
223
+ "Whiteboard and markers",
224
+ "Student notebooks",
225
+ "Pencils and erasers"
226
+ ]
227
+
228
+ if subject.lower() in ["science", "biology", "chemistry", "physics"]:
229
+ base_materials.extend([
230
+ "Safety goggles",
231
+ "Lab materials (as needed)",
232
+ "Scientific calculator"
233
+ ])
234
+ elif subject.lower() in ["math", "mathematics", "algebra", "geometry"]:
235
+ base_materials.extend([
236
+ "Graph paper",
237
+ "Ruler and compass",
238
+ "Calculator"
239
+ ])
240
+ elif subject.lower() in ["english", "language arts", "literature"]:
241
+ base_materials.extend([
242
+ "Texts or reading materials",
243
+ "Dictionary",
244
+ "Highlighters"
245
+ ])
246
+
247
+ return base_materials
248
+
249
+
250
+ def generate_assessment(grade):
251
+ """Generate assessment methods for a lesson"""
252
+ assessments = [
253
+ "Exit ticket with key questions",
254
+ "Class participation and discussion",
255
+ "Quick quiz on main concepts"
256
+ ]
257
+
258
+ if grade in ["9th", "10th", "11th", "12th"]:
259
+ assessments.append("Short written reflection")
260
+ assessments.append("Peer review activity")
261
+
262
+ return assessments
263
+
264
+
265
+ def generate_differentiation():
266
+ """Generate differentiation strategies"""
267
+ return [
268
+ "Provide visual aids for visual learners",
269
+ "Offer hands-on activities for kinesthetic learners",
270
+ "Use audio explanations for auditory learners",
271
+ "Provide additional support for struggling students",
272
+ "Offer extension activities for advanced students"
273
+ ]
274
+
275
+
276
+ def format_lesson_plan(content, topic, subject, grade_level, duration, ai_generated):
277
+ """Format lesson plan content with proper styling"""
278
+
279
+ # Process content with images and math
280
+ processed_content = process_content_with_images(content, topic, "lesson plan")
281
+
282
+ # Apply content styling
283
+ styled_content = apply_content_styling(processed_content, "lesson plan")
284
+
285
+ # Add header information
286
+ header = f"""# 📚 Lesson Plan: {topic}
287
+
288
+ **Subject:** {subject}
289
+ **Grade Level:** {grade_level}
290
+ **Duration:** {duration} minutes
291
+ **Generated by:** {'AI Assistant' if ai_generated else 'Educational Algorithms'}
292
+
293
+ ---
294
+
295
+ """
296
+
297
+ return header + styled_content
298
+
299
+
300
+ def format_lesson_plan_from_dict(lesson_plan):
301
+ """Format lesson plan from dictionary structure"""
302
+
303
+ content = f"""# 📚 Lesson Plan: {lesson_plan['topic']}
304
+
305
+ **Subject:** {lesson_plan['subject']}
306
+ **Grade Level:** {lesson_plan['grade_level']}
307
+ **Duration:** {lesson_plan['duration']} minutes
308
+ **Difficulty:** {lesson_plan['difficulty']}
309
+ **Generated by:** Educational Algorithms
310
+
311
+ ---
312
+
313
+ ## 🎯 Learning Objectives
314
+
315
+ """
316
+
317
+ for i, objective in enumerate(lesson_plan['objectives'], 1):
318
+ content += f"{i}. {objective}\n"
319
+
320
+ content += "\n## 📋 Activities\n\n"
321
+
322
+ for activity in lesson_plan['activities']:
323
+ content += f"### {activity['name']} ({activity['duration']})\n"
324
+ content += f"{activity['description']}\n\n"
325
+
326
+ content += "## 📦 Materials Needed\n\n"
327
+ for material in lesson_plan['materials']:
328
+ content += f"- {material}\n"
329
+
330
+ content += "\n## 📊 Assessment Methods\n\n"
331
+ for assessment in lesson_plan['assessment']:
332
+ content += f"- {assessment}\n"
333
+
334
+ content += "\n## 🎨 Differentiation Strategies\n\n"
335
+ for strategy in lesson_plan['differentiation']:
336
+ content += f"- {strategy}\n"
337
+
338
+ return content
339
+
340
+
341
+ def generate_quiz_with_progress(topic, subject, grade_level, question_count, question_types):
342
+ """Generate quiz with progress updates"""
343
+
344
+ # Show progress bar
345
+ yield PROGRESS_HTML, ""
346
+
347
+ print(f"🚀 Starting quiz generation for: {topic}")
348
+ print(f"📚 Subject: {subject}, Grade: {grade_level}, Questions: {question_count}")
349
+
350
+ # Try Hugging Face API first if token is available
351
+ if HF_TOKEN:
352
+ print("🤖 Token found! Attempting Hugging Face API call...")
353
+ try:
354
+ result = generate_quiz_with_hugging_face(topic, subject, grade_level, question_count, question_types)
355
+ print("✅ Successfully generated with Hugging Face API")
356
+
357
+ # Show completion and return result
358
+ yield COMPLETION_HTML, result
359
+ except Exception as e:
360
+ print(f"❌ Hugging Face API failed: {e}")
361
+ print("🔄 Falling back to educational algorithms...")
362
+
363
+ # Show fallback progress
364
+ yield FALLBACK_HTML, ""
365
+
366
+ result = generate_quiz_with_algorithms(topic, subject, grade_level, question_count, question_types)
367
+ print("✅ Generated with educational algorithms")
368
+
369
+ # Show completion
370
+ yield COMPLETION_HTML, result
371
+ else:
372
+ print("⚠️ No Hugging Face token found, using educational algorithms...")
373
+
374
+ # Show progress for algorithms
375
+ yield FALLBACK_HTML, ""
376
+
377
+ result = generate_quiz_with_algorithms(topic, subject, grade_level, question_count, question_types)
378
+ print("✅ Generated with educational algorithms")
379
+
380
+ # Show completion
381
+ yield COMPLETION_HTML, result
382
+
383
+
384
+ def generate_quiz(topic, subject, grade_level, question_count, question_types):
385
+ """Generate quiz using Hugging Face API or fallback algorithms"""
386
+
387
+ print(f"🚀 Starting quiz generation for: {topic}")
388
+ print(f"📚 Subject: {subject}, Grade: {grade_level}, Questions: {question_count}")
389
+
390
+ # Try Hugging Face API first if token is available
391
+ if HF_TOKEN:
392
+ print("🤖 Token found! Attempting Hugging Face API call...")
393
+ try:
394
+ result = generate_quiz_with_hugging_face(topic, subject, grade_level, question_count, question_types)
395
+ print("✅ Successfully generated with Hugging Face API")
396
+ return result
397
+ except Exception as e:
398
+ print(f"❌ Hugging Face API failed: {e}")
399
+ print("🔄 Falling back to educational algorithms...")
400
+ else:
401
+ print("⚠️ No Hugging Face token found, using educational algorithms...")
402
+
403
+ # Fallback to educational algorithms
404
+ result = generate_quiz_with_algorithms(topic, subject, grade_level, question_count, question_types)
405
+ print("✅ Generated with educational algorithms")
406
+ return result
407
+
408
+
409
+ def generate_quiz_with_hugging_face(topic, subject, grade_level, question_count, question_types):
410
+ """Generate quiz using Hugging Face API"""
411
+ prompt = f"""Create a {question_count}-question quiz about {topic} for {grade_level} grade {subject} students.
412
+
413
+ Question types to include: {', '.join(question_types)}
414
+
415
+ Make the questions:
416
+ - Age-appropriate for {grade_level} grade
417
+ - Clear and unambiguous
418
+ - Cover different aspects of {topic}
419
+ - Include a mix of difficulty levels
420
+ - Provide clear answer choices for multiple choice questions
421
+
422
+ Format each question with:
423
+ 1. Question number
424
+ 2. Question text
425
+ 3. Answer choices (for multiple choice)
426
+ 4. Correct answer
427
+ 5. Brief explanation
428
+
429
+ Topic: {topic}
430
+ Subject: {subject}
431
+ Grade: {grade_level}
432
+ Number of questions: {question_count}"""
433
+
434
+ result = call_hugging_face_api_content(prompt)
435
+
436
+ if result:
437
+ return format_quiz(result, topic, subject, grade_level, question_count, True)
438
+ else:
439
+ raise Exception("No content returned from API")
440
+
441
+
442
+ def generate_quiz_with_algorithms(topic, subject, grade_level, question_count, question_types):
443
+ """Generate quiz using educational algorithms"""
444
+
445
+ questions = []
446
+
447
+ for i in range(question_count):
448
+ # Select question type (cycle through available types)
449
+ question_type = question_types[i % len(question_types)]
450
+
451
+ question = generate_question_by_type(question_type, topic, subject, grade_level, i + 1)
452
+ questions.append(question)
453
+
454
+ # Create quiz structure
455
+ quiz = {
456
+ "topic": topic,
457
+ "subject": subject,
458
+ "grade_level": grade_level,
459
+ "question_count": question_count,
460
+ "questions": questions
461
+ }
462
+
463
+ return format_quiz_from_dict(quiz)
464
+
465
+
466
+ def generate_question_by_type(question_type, topic, subject, grade, question_number):
467
+ """Generate a question of specific type"""
468
+
469
+ if question_type == "Multiple Choice":
470
+ return generate_multiple_choice_question(topic, subject, grade, question_number)
471
+ elif question_type == "True/False":
472
+ return generate_true_false_question(topic, subject, grade, question_number)
473
+ elif question_type == "Short Answer":
474
+ return generate_short_answer_question(topic, subject, grade, question_number)
475
+ elif question_type == "Fill in the Blank":
476
+ return generate_fill_in_blank_question(topic, subject, grade, question_number)
477
+ else:
478
+ return generate_multiple_choice_question(topic, subject, grade, question_number)
479
+
480
+
481
+ def generate_multiple_choice_question(topic, subject, grade, question_number):
482
+ """Generate a multiple choice question"""
483
+
484
+ questions = [
485
+ {
486
+ "question": f"What is the main concept of {topic}?",
487
+ "options": [
488
+ f"The primary idea behind {topic}",
489
+ f"A secondary aspect of {topic}",
490
+ f"An unrelated concept to {topic}",
491
+ f"A complex theory about {topic}"
492
+ ],
493
+ "correct": 0,
494
+ "explanation": f"The main concept of {topic} is the primary idea that students need to understand."
495
+ },
496
+ {
497
+ "question": f"Which of the following best describes {topic}?",
498
+ "options": [
499
+ f"A simple explanation of {topic}",
500
+ f"A complex theory about {topic}",
501
+ f"An advanced concept in {topic}",
502
+ f"A basic principle of {topic}"
503
+ ],
504
+ "correct": 3,
505
+ "explanation": f"{topic} is best described as a basic principle that students should learn."
506
+ }
507
+ ]
508
+
509
+ selected = questions[question_number % len(questions)]
510
+ return {
511
+ "type": "Multiple Choice",
512
+ "question": selected["question"],
513
+ "options": selected["options"],
514
+ "correct_answer": selected["options"][selected["correct"]],
515
+ "explanation": selected["explanation"]
516
+ }
517
+
518
+
519
+ def generate_true_false_question(topic, subject, grade, question_number):
520
+ """Generate a true/false question"""
521
+
522
+ questions = [
523
+ {
524
+ "question": f"{topic} is an important concept in {subject}.",
525
+ "answer": True,
526
+ "explanation": f"Yes, {topic} is indeed an important concept that students need to understand in {subject}."
527
+ },
528
+ {
529
+ "question": f"Understanding {topic} requires advanced knowledge.",
530
+ "answer": False,
531
+ "explanation": f"While {topic} can be complex, it can be understood at the {grade} grade level with proper instruction."
532
+ }
533
+ ]
534
+
535
+ selected = questions[question_number % len(questions)]
536
+ return {
537
+ "type": "True/False",
538
+ "question": selected["question"],
539
+ "correct_answer": "True" if selected["answer"] else "False",
540
+ "explanation": selected["explanation"]
541
+ }
542
+
543
+
544
+ def generate_short_answer_question(topic, subject, grade, question_number):
545
+ """Generate a short answer question"""
546
+
547
+ questions = [
548
+ {
549
+ "question": f"Explain {topic} in your own words.",
550
+ "explanation": f"Students should provide a clear explanation of {topic} using their own understanding."
551
+ },
552
+ {
553
+ "question": f"What are the key components of {topic}?",
554
+ "explanation": f"Students should identify and explain the main parts or elements that make up {topic}."
555
+ }
556
+ ]
557
+
558
+ selected = questions[question_number % len(questions)]
559
+ return {
560
+ "type": "Short Answer",
561
+ "question": selected["question"],
562
+ "correct_answer": "Open-ended response",
563
+ "explanation": selected["explanation"]
564
+ }
565
+
566
+
567
+ def generate_fill_in_blank_question(topic, subject, grade, question_number):
568
+ """Generate a fill in the blank question"""
569
+
570
+ questions = [
571
+ {
572
+ "question": f"_______ is the main concept we learned about {topic}.",
573
+ "answer": topic,
574
+ "explanation": f"The blank should be filled with '{topic}' as it's the main concept being studied."
575
+ },
576
+ {
577
+ "question": f"In {subject}, we study _______ to understand {topic}.",
578
+ "answer": "concepts",
579
+ "explanation": f"The blank should be filled with 'concepts' as we study various concepts to understand {topic}."
580
+ }
581
+ ]
582
+
583
+ selected = questions[question_number % len(questions)]
584
+ return {
585
+ "type": "Fill in the Blank",
586
+ "question": selected["question"],
587
+ "correct_answer": selected["answer"],
588
+ "explanation": selected["explanation"]
589
+ }
590
+
591
+
592
+ def format_quiz(content, topic, subject, grade_level, question_count, ai_generated):
593
+ """Format quiz content with proper styling"""
594
+
595
+ # Process content with images and math
596
+ processed_content = process_content_with_images(content, topic, "quiz")
597
+
598
+ # Apply content styling
599
+ styled_content = apply_content_styling(processed_content, "quiz")
600
+
601
+ # Add header information
602
+ header = f"""# 📝 Quiz: {topic}
603
+
604
+ **Subject:** {subject}
605
+ **Grade Level:** {grade_level}
606
+ **Number of Questions:** {question_count}
607
+ **Generated by:** {'AI Assistant' if ai_generated else 'Educational Algorithms'}
608
+
609
+ ---
610
+
611
+ """
612
+
613
+ return header + styled_content
614
+
615
+
616
+ def format_quiz_from_dict(quiz):
617
+ """Format quiz from dictionary structure"""
618
+
619
+ content = f"""# 📝 Quiz: {quiz['topic']}
620
+
621
+ **Subject:** {quiz['subject']}
622
+ **Grade Level:** {quiz['grade_level']}
623
+ **Number of Questions:** {quiz['question_count']}
624
+ **Generated by:** Educational Algorithms
625
+
626
+ ---
627
+
628
+ """
629
+
630
+ for i, question in enumerate(quiz['questions'], 1):
631
+ content += f"## Question {i} ({question['type']})\n\n"
632
+ content += f"{question['question']}\n\n"
633
+
634
+ if question['type'] == "Multiple Choice":
635
+ for j, option in enumerate(question['options'], 1):
636
+ content += f"{j}. {option}\n"
637
+ content += "\n"
638
+
639
+ content += f"**Answer:** {question['correct_answer']}\n\n"
640
+ content += f"**Explanation:** {question['explanation']}\n\n"
641
+ content += "---\n\n"
642
+
643
+ return content
database.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Database module for BrightMind AI
3
+ Handles all database operations including feedback storage and retrieval
4
+ """
5
+
6
+ import sqlite3
7
+ from datetime import datetime
8
+ from config import DATABASE_FILE
9
+
10
+
11
+ def init_database():
12
+ """Initialize the SQLite database"""
13
+ try:
14
+ conn = sqlite3.connect(DATABASE_FILE)
15
+ cursor = conn.cursor()
16
+
17
+ # Create feedback table
18
+ cursor.execute('''
19
+ CREATE TABLE IF NOT EXISTS feedback (
20
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
21
+ timestamp TEXT NOT NULL,
22
+ feedback_type TEXT NOT NULL,
23
+ rating INTEGER NOT NULL,
24
+ comments TEXT NOT NULL,
25
+ user_email TEXT,
26
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
27
+ )
28
+ ''')
29
+
30
+ conn.commit()
31
+ conn.close()
32
+ print("✅ Database initialized successfully")
33
+ return True
34
+ except Exception as e:
35
+ print(f"❌ Database initialization error: {e}")
36
+ return False
37
+
38
+
39
+ def save_feedback_to_db(feedback_type, rating, comments, user_email=""):
40
+ """Save feedback to SQLite database"""
41
+ try:
42
+ conn = sqlite3.connect(DATABASE_FILE)
43
+ cursor = conn.cursor()
44
+
45
+ # Convert feedback_type list to string
46
+ feedback_type_str = ', '.join(feedback_type) if isinstance(feedback_type, list) else str(feedback_type)
47
+
48
+ cursor.execute('''
49
+ INSERT INTO feedback (timestamp, feedback_type, rating, comments, user_email)
50
+ VALUES (?, ?, ?, ?, ?)
51
+ ''', (
52
+ datetime.now().isoformat(),
53
+ feedback_type_str,
54
+ rating,
55
+ comments,
56
+ user_email
57
+ ))
58
+
59
+ conn.commit()
60
+ conn.close()
61
+ print("✅ Feedback saved to database successfully")
62
+ return True
63
+ except Exception as e:
64
+ print(f"❌ Database save error: {e}")
65
+ return False
66
+
67
+
68
+ def get_feedback_stats():
69
+ """Get feedback statistics for admin"""
70
+ try:
71
+ conn = sqlite3.connect(DATABASE_FILE)
72
+ cursor = conn.cursor()
73
+
74
+ # Get total feedback count
75
+ cursor.execute('SELECT COUNT(*) FROM feedback')
76
+ total_feedback = cursor.fetchone()[0]
77
+
78
+ # Get average rating
79
+ cursor.execute('SELECT AVG(rating) FROM feedback')
80
+ avg_rating = cursor.fetchone()[0]
81
+ avg_rating = round(avg_rating, 2) if avg_rating else 0
82
+
83
+ # Get recent feedback (last 5)
84
+ cursor.execute('''
85
+ SELECT timestamp, feedback_type, rating, comments, user_email
86
+ FROM feedback
87
+ ORDER BY created_at DESC
88
+ LIMIT 5
89
+ ''')
90
+ recent_feedback = cursor.fetchall()
91
+
92
+ conn.close()
93
+
94
+ return {
95
+ 'total_feedback': total_feedback,
96
+ 'avg_rating': avg_rating,
97
+ 'recent_feedback': recent_feedback
98
+ }
99
+ except Exception as e:
100
+ print(f"❌ Database stats error: {e}")
101
+ return {
102
+ 'total_feedback': 0,
103
+ 'avg_rating': 0,
104
+ 'recent_feedback': []
105
+ }
106
+
107
+
108
+ def view_feedback_admin():
109
+ """Admin function to view all feedback"""
110
+ try:
111
+ conn = sqlite3.connect(DATABASE_FILE)
112
+ cursor = conn.cursor()
113
+
114
+ cursor.execute('''
115
+ SELECT id, timestamp, feedback_type, rating, comments, user_email, created_at
116
+ FROM feedback
117
+ ORDER BY created_at DESC
118
+ ''')
119
+
120
+ feedback_data = cursor.fetchall()
121
+ conn.close()
122
+
123
+ if not feedback_data:
124
+ return "No feedback found in database."
125
+
126
+ # Format feedback data
127
+ result = "# 📊 Feedback Database\n\n"
128
+ result += f"**Total Feedback Entries:** {len(feedback_data)}\n\n"
129
+
130
+ for entry in feedback_data:
131
+ id_val, timestamp, feedback_type, rating, comments, user_email, created_at = entry
132
+ result += f"## Entry #{id_val}\n"
133
+ result += f"**Date:** {timestamp}\n"
134
+ result += f"**Type:** {feedback_type}\n"
135
+ result += f"**Rating:** {rating}/5 ⭐\n"
136
+ result += f"**Comments:** {comments}\n"
137
+ result += f"**Email:** {user_email if user_email else 'Not provided'}\n"
138
+ result += f"**Created:** {created_at}\n"
139
+ result += "---\n\n"
140
+
141
+ return result
142
+ except Exception as e:
143
+ return f"❌ Error accessing database: {str(e)}"
email_service.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Email service module for BrightMind AI
3
+ Handles email functionality including feedback notifications
4
+ """
5
+
6
+ import json
7
+ import smtplib
8
+ from datetime import datetime
9
+ from email.mime.text import MIMEText
10
+ from email.mime.multipart import MIMEMultipart
11
+ from config import FEEDBACK_EMAIL, SMTP_SERVER, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD
12
+ from database import save_feedback_to_db
13
+
14
+
15
+ def send_feedback_email(feedback_type, rating, comments, user_email=""):
16
+ """Send feedback email to admin"""
17
+
18
+ if not SMTP_USERNAME or not SMTP_PASSWORD:
19
+ print("⚠️ SMTP credentials not configured, storing feedback locally")
20
+ # Store feedback locally if no email configured
21
+ feedback_data = {
22
+ "timestamp": datetime.now().isoformat(),
23
+ "feedback_type": feedback_type,
24
+ "rating": rating,
25
+ "comments": comments,
26
+ "user_email": user_email
27
+ }
28
+
29
+ # Save to local file
30
+ try:
31
+ with open("feedback_log.json", "a") as f:
32
+ f.write(json.dumps(feedback_data) + "\n")
33
+ return "✅ Feedback saved successfully! (Email not configured)"
34
+ except Exception as e:
35
+ return f"❌ Error saving feedback: {str(e)}"
36
+
37
+ try:
38
+ # Create message
39
+ msg = MIMEMultipart()
40
+ msg['From'] = SMTP_USERNAME
41
+ msg['To'] = FEEDBACK_EMAIL
42
+ msg['Subject'] = f"BrightMind AI Feedback - {feedback_type}"
43
+
44
+ # Create email body
45
+ body = f"""
46
+ New Feedback Received from BrightMind AI Platform
47
+
48
+ Feedback Type: {', '.join(feedback_type) if isinstance(feedback_type, list) else feedback_type}
49
+ Rating: {rating}/5
50
+ User Email: {user_email if user_email else 'Not provided'}
51
+ Comments: {comments}
52
+
53
+ Timestamp: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
54
+
55
+ ---
56
+ This feedback was automatically sent from the BrightMind AI platform.
57
+ """
58
+
59
+ msg.attach(MIMEText(body, 'plain'))
60
+
61
+ # Send email
62
+ server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
63
+ server.starttls()
64
+ server.login(SMTP_USERNAME, SMTP_PASSWORD)
65
+ text = msg.as_string()
66
+ server.sendmail(SMTP_USERNAME, FEEDBACK_EMAIL, text)
67
+ server.quit()
68
+
69
+ print(f"✅ Feedback email sent successfully to {FEEDBACK_EMAIL}")
70
+ return "✅ Thank you! Your feedback has been sent successfully."
71
+
72
+ except Exception as e:
73
+ print(f"❌ Error sending feedback email: {str(e)}")
74
+ return f"❌ Error sending feedback: {str(e)}"
75
+
76
+
77
+ def submit_feedback(feedback_type, rating, comments, user_email):
78
+ """Handle feedback submission"""
79
+
80
+ if not feedback_type:
81
+ return "❌ Please select at least one feedback type."
82
+
83
+ if not rating:
84
+ return "❌ Please provide a rating."
85
+
86
+ if not comments.strip():
87
+ return "❌ Please provide your comments."
88
+
89
+ # Save to database first
90
+ db_success = save_feedback_to_db(feedback_type, rating, comments, user_email)
91
+
92
+ if not db_success:
93
+ return "❌ Error saving feedback to database. Please try again."
94
+
95
+ # Try to send email (optional)
96
+ email_result = send_feedback_email(feedback_type, rating, comments, user_email)
97
+
98
+ if "✅" in email_result:
99
+ return "✅ Thank you! Your feedback has been saved and sent successfully."
100
+ else:
101
+ return "✅ Thank you! Your feedback has been saved successfully. (Email notification not available)"
ui_components.py ADDED
@@ -0,0 +1,577 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ UI components module for BrightMind AI
3
+ Contains Gradio interface components and styling
4
+ """
5
+
6
+ import gradio as gr
7
+ from config import debug_token_status
8
+ from content_generators import (
9
+ generate_lesson_plan_with_progress,
10
+ generate_quiz_with_progress,
11
+ generate_content_with_progress
12
+ )
13
+ from email_service import submit_feedback
14
+ from database import get_feedback_stats, view_feedback_admin
15
+ from ai_services import generate_albert_response
16
+
17
+
18
+ def create_main_interface():
19
+ """Create the main Gradio interface"""
20
+
21
+ # Debug token status
22
+ debug_token_status()
23
+
24
+ # Custom CSS for modern styling
25
+ custom_css = """
26
+ .modern-card {
27
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
28
+ border-radius: 20px;
29
+ padding: 30px;
30
+ margin: 20px 0;
31
+ box-shadow: 0 10px 30px rgba(0,0,0,0.1);
32
+ color: white;
33
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
34
+ }
35
+
36
+ .modern-card:hover {
37
+ transform: translateY(-5px);
38
+ box-shadow: 0 15px 40px rgba(0,0,0,0.2);
39
+ }
40
+
41
+ .slide-in-left {
42
+ animation: slideInLeft 0.6s ease-out;
43
+ }
44
+
45
+ .slide-in-right {
46
+ animation: slideInRight 0.6s ease-out;
47
+ }
48
+
49
+ @keyframes slideInLeft {
50
+ from { transform: translateX(-100px); opacity: 0; }
51
+ to { transform: translateX(0); opacity: 1; }
52
+ }
53
+
54
+ @keyframes slideInRight {
55
+ from { transform: translateX(100px); opacity: 0; }
56
+ to { transform: translateX(0); opacity: 1; }
57
+ }
58
+
59
+ .progress-container {
60
+ background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
61
+ border-radius: 15px;
62
+ padding: 20px;
63
+ margin: 20px 0;
64
+ text-align: center;
65
+ border: 2px solid #667eea;
66
+ }
67
+
68
+ .progress-bar {
69
+ width: 100%;
70
+ height: 8px;
71
+ background: #e9ecef;
72
+ border-radius: 4px;
73
+ overflow: hidden;
74
+ margin: 15px 0;
75
+ }
76
+
77
+ .progress-fill {
78
+ height: 100%;
79
+ background: linear-gradient(90deg, #667eea, #764ba2);
80
+ border-radius: 4px;
81
+ animation: progress 2s ease-in-out infinite;
82
+ }
83
+
84
+ @keyframes progress {
85
+ 0% { width: 0%; }
86
+ 50% { width: 70%; }
87
+ 100% { width: 100%; }
88
+ }
89
+
90
+ .generation-status {
91
+ font-weight: 600;
92
+ color: #667eea;
93
+ margin: 10px 0;
94
+ font-size: 1.1rem;
95
+ }
96
+
97
+ .typewriter-container {
98
+ background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
99
+ border-radius: 15px;
100
+ padding: 20px;
101
+ margin: 20px 0;
102
+ border-left: 4px solid #667eea;
103
+ }
104
+
105
+ .typewriter-header {
106
+ display: flex;
107
+ align-items: center;
108
+ margin-bottom: 15px;
109
+ }
110
+
111
+ .book-icon {
112
+ font-size: 24px;
113
+ margin-right: 10px;
114
+ }
115
+
116
+ .typing-dots span {
117
+ animation: typing 1.4s infinite;
118
+ margin: 0 2px;
119
+ }
120
+
121
+ .typing-dots span:nth-child(2) { animation-delay: 0.2s; }
122
+ .typing-dots span:nth-child(3) { animation-delay: 0.4s; }
123
+
124
+ @keyframes typing {
125
+ 0%, 60%, 100% { opacity: 0; }
126
+ 30% { opacity: 1; }
127
+ }
128
+ """
129
+
130
+ with gr.Blocks(css=custom_css, title="BrightMind AI - Educational Assistant") as interface:
131
+
132
+ # Header
133
+ gr.HTML("""
134
+ <div style="text-align: center; padding: 40px 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 20px; margin-bottom: 30px;">
135
+ <h1 style="font-size: 3rem; margin: 0; text-shadow: 2px 2px 4px rgba(0,0,0,0.3);">🧠 BrightMind AI</h1>
136
+ <p style="font-size: 1.3rem; margin: 10px 0; opacity: 0.9;">Your Intelligent Educational Assistant</p>
137
+ <p style="font-size: 1rem; margin: 0; opacity: 0.8;">Generate lesson plans, quizzes, and educational content with AI</p>
138
+ </div>
139
+ """)
140
+
141
+ # Main tabs
142
+ with gr.Tabs():
143
+
144
+ # Albert Chat Tab
145
+ with gr.TabItem("🤖 Albert Chat"):
146
+ create_albert_chat_tab()
147
+
148
+ # Lesson Plan Generator Tab
149
+ with gr.TabItem("📚 Lesson Plan Generator"):
150
+ create_lesson_plan_tab()
151
+
152
+ # Quiz Generator Tab
153
+ with gr.TabItem("📝 Quiz Generator"):
154
+ create_quiz_tab()
155
+
156
+ # Content Generator Tab
157
+ with gr.TabItem("📄 Content Generator"):
158
+ create_content_tab()
159
+
160
+ # Feedback Tab
161
+ with gr.TabItem("💬 Feedback"):
162
+ create_feedback_tab()
163
+
164
+ # Admin Tab
165
+ with gr.TabItem("⚙️ Admin"):
166
+ create_admin_tab()
167
+
168
+ return interface
169
+
170
+
171
+ def create_albert_chat_tab():
172
+ """Create the Albert chat interface"""
173
+
174
+ with gr.Row():
175
+ with gr.Column(scale=1):
176
+ gr.HTML("""
177
+ <div class="modern-card slide-in-left">
178
+ <h2 style="color: white; margin-bottom: 20px; font-size: 1.8rem;">🤖 Albert Chat</h2>
179
+ <p style="color: white; font-size: 1.1rem; margin-bottom: 20px;">Chat with Albert, your AI learning buddy!</p>
180
+ """)
181
+
182
+ user_name = gr.Textbox(
183
+ label="👤 Your Name",
184
+ placeholder="Enter your name to start chatting",
185
+ value=""
186
+ )
187
+
188
+ user_age_group = gr.Dropdown(
189
+ choices=["Elementary (K-5)", "Middle School (6-8)", "High School (9-12)", "College", "Adult"],
190
+ label="🎓 Age Group",
191
+ value="Middle School (6-8)",
192
+ interactive=True
193
+ )
194
+
195
+ gr.HTML("</div>")
196
+
197
+ with gr.Column(scale=2):
198
+ gr.HTML("""
199
+ <div class="modern-card slide-in-right">
200
+ <h3 style="color: white; margin-bottom: 20px; font-size: 1.4rem;">💬 Chat with Albert</h3>
201
+ """)
202
+
203
+ chat_display = gr.Chatbot(
204
+ label="",
205
+ height=400,
206
+ show_label=False,
207
+ container=True,
208
+ bubble_full_width=False
209
+ )
210
+
211
+ chat_input = gr.Textbox(
212
+ label="Type your message here...",
213
+ placeholder="Ask Albert anything about learning!",
214
+ lines=2
215
+ )
216
+
217
+ with gr.Row():
218
+ send_btn = gr.Button("Send", variant="primary")
219
+ clear_btn = gr.Button("Clear Chat", variant="secondary")
220
+
221
+ context_display = gr.HTML("", visible=False)
222
+ typing_indicator = gr.HTML("", visible=False)
223
+
224
+ gr.HTML("</div>")
225
+
226
+ # Event handlers
227
+ def send_message_with_typing(message, name, age_group, history):
228
+ """Send message with typing effect"""
229
+ if not message.strip():
230
+ return history, "", "", ""
231
+
232
+ if history is None:
233
+ history = []
234
+
235
+ history.append([f"{name}: {message}", None])
236
+
237
+ # Generate Albert's response
238
+ albert_response = generate_albert_response(message, name, age_group, history)
239
+ history[-1][1] = albert_response
240
+
241
+ return history, "", "", ""
242
+
243
+ def clear_chat():
244
+ return [], "", "", ""
245
+
246
+ def initialize_chat(name, age_group):
247
+ if not name.strip():
248
+ return [], "", ""
249
+
250
+ welcome_message = f"Hi {name}! 🧠✨ I'm Albert, your learning buddy! What would you like to know about today? 😊🚀"
251
+ return [[None, welcome_message]], "", ""
252
+
253
+ # Connect event handlers
254
+ send_btn.click(
255
+ fn=send_message_with_typing,
256
+ inputs=[chat_input, user_name, user_age_group, chat_display],
257
+ outputs=[chat_display, chat_input, context_display, typing_indicator]
258
+ )
259
+
260
+ clear_btn.click(
261
+ fn=clear_chat,
262
+ outputs=[chat_display, context_display, context_display, typing_indicator]
263
+ )
264
+
265
+ user_name.change(
266
+ fn=initialize_chat,
267
+ inputs=[user_name, user_age_group],
268
+ outputs=[chat_display, context_display, context_display]
269
+ )
270
+
271
+
272
+ def create_lesson_plan_tab():
273
+ """Create the lesson plan generator interface"""
274
+
275
+ with gr.Row():
276
+ with gr.Column():
277
+ gr.HTML("""
278
+ <div class="modern-card slide-in-left">
279
+ <h2 style="color: white; margin-bottom: 20px; font-size: 1.8rem;">📚 Lesson Plan Generator</h2>
280
+ <p style="color: white; font-size: 1.1rem; margin-bottom: 20px;">Create comprehensive lesson plans with AI assistance</p>
281
+ """)
282
+
283
+ topic = gr.Textbox(label="📝 Topic", placeholder="e.g., Photosynthesis, World War II, Algebra")
284
+ subject = gr.Dropdown(
285
+ choices=["Science", "Mathematics", "History", "English Language Arts", "Geography", "Art"],
286
+ label="📚 Subject",
287
+ value="Science",
288
+ interactive=True
289
+ )
290
+ grade_level = gr.Dropdown(
291
+ choices=["K-2", "3-5", "6-8", "9-12"],
292
+ label="🎓 Grade Level",
293
+ value="6-8",
294
+ interactive=True
295
+ )
296
+ duration = gr.Slider(
297
+ minimum=30,
298
+ maximum=180,
299
+ step=15,
300
+ value=60,
301
+ label="⏱️ Duration (minutes)"
302
+ )
303
+ difficulty = gr.Dropdown(
304
+ choices=["Beginner", "Intermediate", "Advanced"],
305
+ label="🎯 Difficulty",
306
+ value="Intermediate",
307
+ interactive=True
308
+ )
309
+
310
+ generate_lesson_btn = gr.Button("🚀 Generate Lesson Plan", variant="primary")
311
+
312
+ gr.HTML("</div>")
313
+
314
+ with gr.Column():
315
+ gr.HTML("""
316
+ <div class="modern-card slide-in-right">
317
+ <h3 style="color: white; margin-bottom: 20px; font-size: 1.4rem;">📋 Generated Lesson Plan</h3>
318
+ """)
319
+
320
+ progress_display = gr.HTML("", visible=False)
321
+ lesson_plan_output = gr.Markdown(label="")
322
+
323
+ gr.HTML("</div>")
324
+
325
+ # Event handler
326
+ generate_lesson_btn.click(
327
+ fn=generate_lesson_plan_with_progress,
328
+ inputs=[topic, subject, grade_level, duration, difficulty],
329
+ outputs=[progress_display, lesson_plan_output]
330
+ )
331
+
332
+
333
+ def create_quiz_tab():
334
+ """Create the quiz generator interface"""
335
+
336
+ with gr.Row():
337
+ with gr.Column():
338
+ gr.HTML("""
339
+ <div class="modern-card slide-in-left">
340
+ <h2 style="color: white; margin-bottom: 20px; font-size: 1.8rem;">📝 Quiz Generator</h2>
341
+ <p style="color: white; font-size: 1.1rem; margin-bottom: 20px;">Create engaging quizzes with AI assistance</p>
342
+ """)
343
+
344
+ quiz_topic = gr.Textbox(label="📝 Topic", placeholder="e.g., Photosynthesis, World War II, Algebra")
345
+ quiz_subject = gr.Dropdown(
346
+ choices=["Science", "Mathematics", "History", "English Language Arts", "Geography", "Art"],
347
+ label="📚 Subject",
348
+ value="Science",
349
+ interactive=True
350
+ )
351
+ quiz_grade_level = gr.Dropdown(
352
+ choices=["K-2", "3-5", "6-8", "9-12"],
353
+ label="🎓 Grade Level",
354
+ value="6-8",
355
+ interactive=True
356
+ )
357
+ question_count = gr.Slider(
358
+ minimum=3,
359
+ maximum=20,
360
+ step=1,
361
+ value=5,
362
+ label="❓ Number of Questions"
363
+ )
364
+ question_types = gr.CheckboxGroup(
365
+ choices=["Multiple Choice", "True/False", "Short Answer", "Fill in the Blank"],
366
+ label="📋 Question Types",
367
+ value=["Multiple Choice", "True/False"]
368
+ )
369
+
370
+ generate_quiz_btn = gr.Button("🚀 Generate Quiz", variant="primary")
371
+
372
+ gr.HTML("</div>")
373
+
374
+ with gr.Column():
375
+ gr.HTML("""
376
+ <div class="modern-card slide-in-right">
377
+ <h3 style="color: white; margin-bottom: 20px; font-size: 1.4rem;">📝 Generated Quiz</h3>
378
+ """)
379
+
380
+ quiz_progress_display = gr.HTML("", visible=False)
381
+ quiz_output = gr.Markdown(label="")
382
+
383
+ gr.HTML("</div>")
384
+
385
+ # Event handler
386
+ generate_quiz_btn.click(
387
+ fn=generate_quiz_with_progress,
388
+ inputs=[quiz_topic, quiz_subject, quiz_grade_level, question_count, question_types],
389
+ outputs=[quiz_progress_display, quiz_output]
390
+ )
391
+
392
+
393
+ def create_content_tab():
394
+ """Create the content generator interface"""
395
+
396
+ with gr.Row():
397
+ with gr.Column():
398
+ gr.HTML("""
399
+ <div class="modern-card slide-in-left">
400
+ <h2 style="color: white; margin-bottom: 20px; font-size: 1.8rem;">📄 Content Generator</h2>
401
+ <p style="color: white; font-size: 1.1rem; margin-bottom: 20px;">Generate educational content with AI assistance</p>
402
+ """)
403
+
404
+ content_topic = gr.Textbox(label="📝 Topic", placeholder="e.g., Photosynthesis, World War II, Algebra")
405
+ content_subject = gr.Dropdown(
406
+ choices=["Science", "Mathematics", "History", "English Language Arts", "Geography", "Art"],
407
+ label="📚 Subject",
408
+ value="Science",
409
+ interactive=True
410
+ )
411
+ content_grade_level = gr.Dropdown(
412
+ choices=["K-2", "3-5", "6-8", "9-12"],
413
+ label="🎓 Grade Level",
414
+ value="6-8",
415
+ interactive=True
416
+ )
417
+ content_type = gr.Dropdown(
418
+ choices=["Study Guide", "Worksheet", "Reading Material", "Summary", "Notes"],
419
+ label="📄 Content Type",
420
+ value="Study Guide",
421
+ interactive=True
422
+ )
423
+ content_length = gr.Dropdown(
424
+ choices=["Short (1-2 pages)", "Medium (3-5 pages)", "Long (6+ pages)"],
425
+ label="📏 Length",
426
+ value="Medium (3-5 pages)",
427
+ interactive=True
428
+ )
429
+ content_difficulty = gr.Dropdown(
430
+ choices=["Beginner", "Intermediate", "Advanced"],
431
+ label="🎯 Difficulty",
432
+ value="Intermediate",
433
+ interactive=True
434
+ )
435
+
436
+ generate_content_btn = gr.Button("🚀 Generate Content", variant="primary")
437
+
438
+ gr.HTML("</div>")
439
+
440
+ with gr.Column():
441
+ gr.HTML("""
442
+ <div class="modern-card slide-in-right">
443
+ <h3 style="color: white; margin-bottom: 20px; font-size: 1.4rem;">📄 Generated Content</h3>
444
+ """)
445
+
446
+ content_progress_display = gr.HTML("", visible=False)
447
+ content_output = gr.Markdown(label="")
448
+
449
+ gr.HTML("</div>")
450
+
451
+ # Event handler
452
+ generate_content_btn.click(
453
+ fn=generate_content_with_progress,
454
+ inputs=[content_topic, content_subject, content_grade_level, content_difficulty, content_type, content_length],
455
+ outputs=[content_progress_display, content_output]
456
+ )
457
+
458
+
459
+ def create_feedback_tab():
460
+ """Create the feedback interface"""
461
+
462
+ with gr.Row():
463
+ with gr.Column():
464
+ gr.HTML("""
465
+ <div class="modern-card slide-in-left">
466
+ <h2 style="color: white; margin-bottom: 20px; font-size: 1.8rem;">💬 Feedback</h2>
467
+ <p style="color: white; font-size: 1.1rem; margin-bottom: 20px;">Help us improve BrightMind AI</p>
468
+ """)
469
+
470
+ feedback_type = gr.CheckboxGroup(
471
+ choices=["Lesson Plan Generator", "Quiz Generator", "Content Generator", "Albert Chat", "Overall Experience"],
472
+ label="📋 What would you like to provide feedback on?",
473
+ value=["Overall Experience"]
474
+ )
475
+
476
+ rating = gr.Radio(
477
+ choices=[1, 2, 3, 4, 5],
478
+ label="⭐ Rating (1-5 stars)",
479
+ value=5
480
+ )
481
+
482
+ comments = gr.Textbox(
483
+ label="💭 Comments",
484
+ placeholder="Please share your thoughts, suggestions, or any issues you encountered...",
485
+ lines=4
486
+ )
487
+
488
+ user_email = gr.Textbox(
489
+ label="📧 Email (optional)",
490
+ placeholder="your.email@example.com"
491
+ )
492
+
493
+ submit_feedback_btn = gr.Button("📤 Submit Feedback", variant="primary")
494
+
495
+ gr.HTML("</div>")
496
+
497
+ with gr.Column():
498
+ gr.HTML("""
499
+ <div class="modern-card slide-in-right">
500
+ <h3 style="color: white; margin-bottom: 20px; font-size: 1.4rem;">📊 Feedback Status</h3>
501
+ """)
502
+
503
+ feedback_status = gr.Markdown("Your feedback helps us improve! Please fill out the form and click submit.")
504
+
505
+ gr.HTML("</div>")
506
+
507
+ # Event handler
508
+ submit_feedback_btn.click(
509
+ fn=submit_feedback,
510
+ inputs=[feedback_type, rating, comments, user_email],
511
+ outputs=[feedback_status]
512
+ )
513
+
514
+
515
+ def create_admin_tab():
516
+ """Create the admin interface"""
517
+
518
+ with gr.Row():
519
+ with gr.Column():
520
+ gr.HTML("""
521
+ <div class="modern-card slide-in-left">
522
+ <h2 style="color: white; margin-bottom: 20px; font-size: 1.8rem;">⚙️ Admin Panel</h2>
523
+ <p style="color: white; font-size: 1.1rem; margin-bottom: 20px;">View feedback statistics and system information</p>
524
+ """)
525
+
526
+ refresh_stats_btn = gr.Button("🔄 Refresh Statistics", variant="primary")
527
+ view_feedback_btn = gr.Button("📊 View All Feedback", variant="secondary")
528
+
529
+ gr.HTML("</div>")
530
+
531
+ with gr.Column():
532
+ gr.HTML("""
533
+ <div class="modern-card slide-in-right">
534
+ <h3 style="color: white; margin-bottom: 20px; font-size: 1.4rem;">📈 Statistics</h3>
535
+ """)
536
+
537
+ stats_display = gr.Markdown("Click 'Refresh Statistics' to view feedback data.")
538
+ feedback_display = gr.Markdown("Click 'View All Feedback' to see detailed feedback entries.")
539
+
540
+ gr.HTML("</div>")
541
+
542
+ # Event handlers
543
+ def refresh_stats():
544
+ stats = get_feedback_stats()
545
+ return f"""
546
+ ## 📊 Feedback Statistics
547
+
548
+ **Total Feedback Entries:** {stats['total_feedback']}
549
+ **Average Rating:** {stats['avg_rating']}/5 ⭐
550
+
551
+ **Recent Feedback:**
552
+ {format_recent_feedback(stats['recent_feedback'])}
553
+ """
554
+
555
+ def view_all_feedback():
556
+ return view_feedback_admin()
557
+
558
+ def format_recent_feedback(recent_feedback):
559
+ if not recent_feedback:
560
+ return "No recent feedback available."
561
+
562
+ formatted = ""
563
+ for entry in recent_feedback:
564
+ timestamp, feedback_type, rating, comments, user_email = entry
565
+ formatted += f"- **{timestamp}**: {rating}/5 ⭐ - {comments[:100]}{'...' if len(comments) > 100 else ''}\n"
566
+
567
+ return formatted
568
+
569
+ refresh_stats_btn.click(
570
+ fn=refresh_stats,
571
+ outputs=[stats_display]
572
+ )
573
+
574
+ view_feedback_btn.click(
575
+ fn=view_all_feedback,
576
+ outputs=[feedback_display]
577
+ )
utils.py ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Utility functions module for BrightMind AI
3
+ Contains helper functions for content processing, math conversion, and styling
4
+ """
5
+
6
+ import re
7
+ from algebra_solver import AlgebraSolver
8
+
9
+ # Initialize algebra solver
10
+ algebra_solver = AlgebraSolver()
11
+
12
+
13
+ def convert_math_to_html(text):
14
+ """Convert LaTeX-style math expressions to HTML"""
15
+
16
+ # Handle LaTeX math delimiters first
17
+ # Convert \[ ... \] to display math
18
+ text = re.sub(r'\\\[([^\]]+)\\\]', r'<div style="text-align: center; margin: 10px 0; padding: 10px; background: #f8f9fa; border-radius: 5px; font-family: \'Times New Roman\', serif; font-size: 1.1em;">\1</div>', text)
19
+
20
+ # Convert \( ... \) to inline math
21
+ text = re.sub(r'\\\(([^)]+)\\\)', r'<span style="font-family: \'Times New Roman\', serif; font-size: 1.05em; background: #f0f0f0; padding: 2px 4px; border-radius: 3px;">\1</span>', text)
22
+
23
+ # Handle fractions: \frac{a}{b}
24
+ text = re.sub(r'\\frac\{([^}]+)\}\{([^}]+)\}', r'<div style="display: inline-block; text-align: center; vertical-align: middle; margin: 0 5px;"><div style="border-bottom: 1px solid #333; padding-bottom: 2px; font-size: 0.9em;">\1</div><div style="padding-top: 2px; font-size: 0.9em;">\2</div></div>', text)
25
+
26
+ # Handle simple fractions like 120/2
27
+ text = re.sub(r'(\d+)/(\d+)', r'<div style="display: inline-block; text-align: center; vertical-align: middle; margin: 0 3px;"><div style="border-bottom: 1px solid #333; padding-bottom: 1px; font-size: 0.9em;">\1</div><div style="padding-top: 1px; font-size: 0.9em;">\2</div></div>', text)
28
+
29
+ # Handle superscripts: ^{text}
30
+ text = re.sub(r'\^\{([^}]+)\}', r'<sup>\1</sup>', text)
31
+ text = re.sub(r'\^(\w)', r'<sup>\1</sup>', text)
32
+
33
+ # Handle subscripts: _{text}
34
+ text = re.sub(r'_\{([^}]+)\}', r'<sub>\1</sub>', text)
35
+ text = re.sub(r'_(\w)', r'<sub>\1</sub>', text)
36
+
37
+ # Handle \text{} commands first (before other processing)
38
+ text = re.sub(r'\\text\{([^}]+)\}', r'\1', text)
39
+
40
+ # Handle \boxed{} commands
41
+ text = re.sub(r'\\boxed\{([^}]+)\}', r'<span style="border: 2px solid #333; padding: 2px 4px; background: #f0f0f0; border-radius: 3px;">\1</span>', text)
42
+
43
+ # Handle underscore patterns that are not subscripts (like \_\_\_)
44
+ text = re.sub(r'\\_+', r'<span style="border-bottom: 2px solid #333; min-width: 20px; display: inline-block;">&nbsp;</span>', text)
45
+
46
+ # Re-process fractions after text commands are handled
47
+ text = re.sub(r'\\frac\{([^}]+)\}\{([^}]+)\}', r'<div style="display: inline-block; text-align: center; vertical-align: middle; margin: 0 5px;"><div style="border-bottom: 1px solid #333; padding-bottom: 2px; font-size: 0.9em;">\1</div><div style="padding-top: 2px; font-size: 0.9em;">\2</div></div>', text)
48
+
49
+ # Handle common math symbols
50
+ text = text.replace('\\times', '×')
51
+ text = text.replace('\\rightarrow', '→')
52
+ text = text.replace('\\leftarrow', '←')
53
+ text = text.replace('\\leq', '≤')
54
+ text = text.replace('\\geq', '≥')
55
+ text = text.replace('\\neq', '≠')
56
+ text = text.replace('\\approx', '≈')
57
+ text = text.replace('\\pm', '±')
58
+ text = text.replace('\\sqrt', '√')
59
+ text = text.replace('\\pi', 'π')
60
+
61
+ return text
62
+
63
+
64
+ def solve_algebra_problem(problem_type, *args):
65
+ """Solve algebra problems interactively"""
66
+ try:
67
+ if problem_type == "speed":
68
+ distance, time = args
69
+ result = algebra_solver.solve_speed_problem(float(distance), float(time))
70
+ elif problem_type == "volume":
71
+ mass, density = args
72
+ result = algebra_solver.solve_volume_problem(float(mass), float(density))
73
+ elif problem_type == "linear":
74
+ a, b, c = args
75
+ result = algebra_solver.solve_linear_equation(float(a), float(b), float(c))
76
+ elif problem_type == "quadratic":
77
+ h, coefficient = args
78
+ result = algebra_solver.solve_quadratic_equation(float(h), float(coefficient))
79
+ else:
80
+ return "❌ Unknown problem type"
81
+
82
+ if "error" in result:
83
+ return f"❌ Error: {result['error']}"
84
+
85
+ # Format the solution nicely
86
+ solution_text = f"✅ **{result['solution']}**\n\n"
87
+ if "steps" in result:
88
+ solution_text += "**Steps:**\n"
89
+ for i, step in enumerate(result["steps"], 1):
90
+ solution_text += f"{i}. {step}\n"
91
+ elif "formula" in result:
92
+ solution_text += f"**Formula:** {result['formula']}\n"
93
+ solution_text += f"**Calculation:** {result['calculation']}\n"
94
+
95
+ return solution_text
96
+
97
+ except Exception as e:
98
+ return f"❌ Error solving problem: {str(e)}"
99
+
100
+
101
+ def apply_content_styling(content, content_type):
102
+ """Apply simple and robust styling to educational content"""
103
+
104
+ # Clean up any malformed HTML first
105
+ content = re.sub(r'="[^"]*style="[^"]*"[^"]*"', '', content)
106
+ content = re.sub(r'="[^"]*color: [^"]*"[^"]*"', '', content)
107
+ content = re.sub(r'="[^"]*background: [^"]*"[^"]*"', '', content)
108
+ content = re.sub(r'="[^"]*border: [^"]*"[^"]*"', '', content)
109
+ content = re.sub(r'="[^"]*padding: [^"]*"[^"]*"', '', content)
110
+ content = re.sub(r'="[^"]*margin: [^"]*"[^"]*"', '', content)
111
+
112
+ # Fix broken image tags and malformed HTML
113
+ content = re.sub(r'<div style>.*?</div>', '', content)
114
+ content = re.sub(r'stylelazy">', 'loading="lazy">', content)
115
+ content = re.sub(r'<img[^>]*style[^>]*>', '', content)
116
+
117
+ # Fix malformed button attributes
118
+ content = re.sub(r'styleselectRating\(\d+\)"', '', content)
119
+ content = re.sub(r'styletext"', '', content)
120
+ content = re.sub(r'style="[^"]*"[^"]*style="[^"]*"', 'style="margin-right: 8px; transform: scale(1.2);"', content)
121
+
122
+ # Fix broken input attributes
123
+ content = re.sub(r'<input typeready-check"', '<input type="checkbox" id="ready-check"', content)
124
+ content = re.sub(r'styleSolve"', 'onclick="solveSpeed()"', content)
125
+
126
+ # Clean up any remaining malformed attributes
127
+ content = re.sub(r'="[^"]*"[^"]*"', '', content)
128
+
129
+ # Return content as-is for Markdown rendering
130
+ styled_content = content
131
+
132
+ # Apply Markdown-friendly styling
133
+ styled_content = re.sub(r'\[ANSWER: ([^\]]+)\]', r'**Answer:** \1', styled_content)
134
+
135
+ styled_content = re.sub(r'___+', r'_________________', styled_content)
136
+
137
+ styled_content = re.sub(r'\[ \]', r'☐', styled_content)
138
+ styled_content = re.sub(r'☑', r'☑', styled_content)
139
+
140
+ styled_content = re.sub(r'\[(\d+)\]', r'**\1**', styled_content)
141
+
142
+ return styled_content
143
+
144
+
145
+ def process_content_with_images(content, topic, content_type):
146
+ """Process generated content to include real images and multimedia elements"""
147
+ from ai_services import get_educational_image_url, generate_image_placeholder
148
+
149
+ # Replace image placeholders with actual images
150
+ # Convert LaTeX-style math expressions to HTML first
151
+ content = convert_math_to_html(content)
152
+
153
+ # Fix LaTeX math rendering by converting to HTML
154
+ def fix_latex_math(match):
155
+ latex_formula = match.group(1)
156
+
157
+ # Handle fractions first (most complex) - improved regex
158
+ def process_fraction(match):
159
+ numerator = match.group(1)
160
+ denominator = match.group(2)
161
+ return f'<div style="display: inline-block; text-align: center; vertical-align: middle; margin: 0 5px;"><div style="border-bottom: 1px solid #333; padding-bottom: 2px; font-size: 0.9em;">{numerator}</div><div style="padding-top: 2px; font-size: 0.9em;">{denominator}</div></div>'
162
+
163
+ # Process fractions: \frac{numerator}{denominator} - more robust regex
164
+ latex_formula = re.sub(r'\\frac\{([^{}]+)\}\{([^{}]+)\}', process_fraction, latex_formula)
165
+
166
+ # Handle text commands more carefully
167
+ latex_formula = latex_formula.replace('\\text{', '<span style="font-style: normal;">')
168
+
169
+ # Handle math symbols
170
+ latex_formula = latex_formula.replace('\\times', '×')
171
+ latex_formula = latex_formula.replace('\\rightarrow', '→')
172
+ latex_formula = latex_formula.replace('\\leftarrow', '←')
173
+ latex_formula = latex_formula.replace('\\leq', '≤')
174
+ latex_formula = latex_formula.replace('\\geq', '≥')
175
+ latex_formula = latex_formula.replace('\\neq', '≠')
176
+ latex_formula = latex_formula.replace('\\approx', '≈')
177
+ latex_formula = latex_formula.replace('\\pm', '±')
178
+ latex_formula = latex_formula.replace('\\sqrt{', '√(')
179
+ latex_formula = latex_formula.replace('\\pi', 'π')
180
+ latex_formula = latex_formula.replace('\\alpha', 'α')
181
+ latex_formula = latex_formula.replace('\\beta', 'β')
182
+ latex_formula = latex_formula.replace('\\gamma', 'γ')
183
+ latex_formula = latex_formula.replace('\\delta', 'δ')
184
+ latex_formula = latex_formula.replace('\\theta', 'θ')
185
+ latex_formula = latex_formula.replace('\\lambda', 'λ')
186
+ latex_formula = latex_formula.replace('\\mu', 'μ')
187
+ latex_formula = latex_formula.replace('\\sigma', 'σ')
188
+ latex_formula = latex_formula.replace('\\tau', 'τ')
189
+ latex_formula = latex_formula.replace('\\phi', 'φ')
190
+ latex_formula = latex_formula.replace('\\omega', 'ω')
191
+
192
+ # Handle superscripts and subscripts
193
+ latex_formula = re.sub(r'\^(\w+)', r'<sup>\1</sup>', latex_formula)
194
+ latex_formula = re.sub(r'_(\w+)', r'<sub>\1</sub>', latex_formula)
195
+
196
+ # Clean up any remaining unmatched braces
197
+ latex_formula = latex_formula.replace('{', '').replace('}', '')
198
+
199
+ return f'<div style="text-align: center; margin: 20px 0; padding: 15px; background: #f8f9fa; border-radius: 8px; border-left: 4px solid #667eea; font-family: \'Times New Roman\', serif; font-size: 1.1em;">{latex_formula}</div>'
200
+
201
+ # Find LaTeX math formulas and convert them (both [formula] and (formula) formats)
202
+ # Updated patterns to be more specific to LaTeX commands
203
+ latex_patterns = [
204
+ re.compile(r'\[([^\[\]]*\\[a-zA-Z]+[^\[\]]*)\]', re.MULTILINE), # [formula with LaTeX commands]
205
+ re.compile(r'\(([^()]*\\[a-zA-Z]+[^()]*)\)', re.MULTILINE) # (formula with LaTeX commands)
206
+ ]
207
+
208
+ for pattern in latex_patterns:
209
+ content = pattern.sub(fix_latex_math, content)
210
+
211
+ # Find all IMAGE: description patterns (both [IMAGE: description] and IMAGE: description)
212
+ image_patterns = [
213
+ re.compile(r'\[IMAGE:\s*([^\]]+)\]', re.IGNORECASE),
214
+ re.compile(r'IMAGE:\s*([^\n]+)', re.IGNORECASE)
215
+ ]
216
+
217
+ for pattern in image_patterns:
218
+ def replace_image(match):
219
+ description = match.group(1).strip()
220
+ print(f"🖼️ Processing image: {description}")
221
+
222
+ # Try to get a real image URL
223
+ image_url = get_educational_image_url(topic, description, content_type)
224
+
225
+ if image_url and not image_url.startswith('https://via.placeholder.com'):
226
+ # Real image found
227
+ return f'\n<img src="{image_url}" alt="{description}" style="max-width: 100%; height: auto; border-radius: 8px; margin: 20px 0; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">\n'
228
+ else:
229
+ # Use placeholder
230
+ return generate_image_placeholder(description, topic, content_type)
231
+
232
+ content = pattern.sub(replace_image, content)
233
+
234
+ return content
235
+
236
+
237
+ def typewriter_effect(text, status_message):
238
+ """Create a typewriter effect for text display"""
239
+ import time
240
+
241
+ if not text:
242
+ return status_message
243
+
244
+ # Split text into words for smoother effect
245
+ words = text.split()
246
+ result = ""
247
+
248
+ for i, word in enumerate(words):
249
+ result += word + " "
250
+ if i % 10 == 0: # Yield every 10 words
251
+ yield result, status_message
252
+ time.sleep(0.05) # Small delay for effect
253
+
254
+ yield result, status_message