Ngum commited on
Commit
ababeb3
ยท
1 Parent(s): 687d84e

ADD ULTIMATE ALU BRAIN - 58 comprehensive entries covering ALL student needs: academics, career, health, safety, immigration, financial aid, clubs, events, resources, emergency procedures, mental health support, disability services, and much more

Browse files
alu_brain/comprehensive_knowledge.json ADDED
The diff for this file is too large to render. See raw diff
 
comprehensive_converter.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Comprehensive Knowledge Base Converter
3
+ Converts the full ALU knowledge base to ALU Brain JSON format
4
+ """
5
+
6
+ import json
7
+ import re
8
+ from pathlib import Path
9
+
10
+ def parse_section(section_text, section_title):
11
+ """Parse a section and create multiple entries"""
12
+ entries = []
13
+
14
+ # Split into subsections
15
+ subsections = re.split(r'\n###\s+', section_text)
16
+
17
+ for subsection in subsections:
18
+ if not subsection.strip():
19
+ continue
20
+
21
+ lines = subsection.split('\n')
22
+ subtitle = lines[0].strip() if lines else ""
23
+ content = '\n'.join(lines[1:]).strip()
24
+
25
+ if not content:
26
+ continue
27
+
28
+ # Create entry for this subsection
29
+ entry = {
30
+ "id": f"alu_kb_{len(entries)}_{subtitle.lower().replace(' ', '_')[:30]}",
31
+ "question": f"{section_title}: {subtitle}" if subtitle else section_title,
32
+ "answer": content,
33
+ "type": "text",
34
+ "keywords": extract_keywords(section_title + " " + subtitle + " " + content),
35
+ "category": categorize_section(section_title),
36
+ "source": "ALU Comprehensive Knowledge Base"
37
+ }
38
+ entries.append(entry)
39
+
40
+ return entries
41
+
42
+ def extract_keywords(text):
43
+ """Extract relevant keywords from text"""
44
+ # Common words to exclude
45
+ stopwords = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for', 'of', 'with', 'by', 'from', 'as', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'should', 'could', 'may', 'might', 'must', 'can', 'this', 'that', 'these', 'those', 'i', 'you', 'he', 'she', 'it', 'we', 'they', 'what', 'which', 'who', 'when', 'where', 'why', 'how', 'all', 'each', 'every', 'both', 'few', 'more', 'most', 'other', 'some', 'such', 'no', 'nor', 'not', 'only', 'own', 'same', 'so', 'than', 'too', 'very'}
46
+
47
+ # Extract words
48
+ words = re.findall(r'\b[a-z]{3,}\b', text.lower())
49
+
50
+ # Filter and get unique keywords
51
+ keywords = list(set([w for w in words if w not in stopwords]))[:15] # Limit to 15 keywords
52
+
53
+ return keywords
54
+
55
+ def categorize_section(title):
56
+ """Categorize section based on title"""
57
+ title_lower = title.lower()
58
+
59
+ if any(word in title_lower for word in ['calendar', 'academic', 'term', 'schedule']):
60
+ return "Academic Calendar"
61
+ elif any(word in title_lower for word in ['spd', 'internship', 'career', 'job', 'placement']):
62
+ return "Career Services"
63
+ elif any(word in title_lower for word in ['immigration', 'visa', 'permit']):
64
+ return "Immigration Support"
65
+ elif any(word in title_lower for word in ['insurance', 'medical', 'health', 'eden care']):
66
+ return "Health & Wellness"
67
+ elif any(word in title_lower for word in ['student life', 'club', 'residential', 'housing']):
68
+ return "Campus Life"
69
+ elif any(word in title_lower for word in ['program', 'bel', 'degree', 'module', 'course']):
70
+ return "Academic Programs"
71
+ elif any(word in title_lower for word in ['policy', 'conduct', 'disciplinary', 'code']):
72
+ return "Policies & Conduct"
73
+ elif any(word in title_lower for word in ['event', 'student-led']):
74
+ return "Student Events"
75
+ elif any(word in title_lower for word in ['faq', 'question', 'frequently']):
76
+ return "FAQs"
77
+ else:
78
+ return "General Information"
79
+
80
+ def convert_comprehensive_kb():
81
+ """Main conversion function"""
82
+
83
+ print("=" * 70)
84
+ print("๐Ÿง  COMPREHENSIVE KNOWLEDGE BASE CONVERTER")
85
+ print("=" * 70)
86
+ print()
87
+
88
+ # Read the comprehensive KB
89
+ kb_file = Path("data/alu_knowledge/alu_ultimate_knowledge_base.txt")
90
+
91
+ if not kb_file.exists():
92
+ print(f"โŒ Knowledge base file not found: {kb_file}")
93
+ return False
94
+
95
+ print(f"๐Ÿ“– Reading knowledge base from: {kb_file}")
96
+ with open(kb_file, 'r', encoding='utf-8') as f:
97
+ content = f.read()
98
+
99
+ print(f"โœ… Loaded {len(content)} characters")
100
+ print()
101
+
102
+ # Split by major sections (## headers)
103
+ sections = re.split(r'\n##\s+', content)
104
+
105
+ all_entries = []
106
+ entry_id = 1
107
+
108
+ print("๐Ÿ”„ Processing sections...")
109
+ for i, section in enumerate(sections[1:], 1): # Skip first empty section
110
+ if not section.strip():
111
+ continue
112
+
113
+ lines = section.split('\n')
114
+ section_title = lines[0].strip()
115
+ section_content = '\n'.join(lines[1:])
116
+
117
+ print(f" {i}. Processing: {section_title[:50]}...")
118
+
119
+ # Parse this section
120
+ section_entries = parse_section(section_content, section_title)
121
+
122
+ # Add unique IDs
123
+ for entry in section_entries:
124
+ entry['id'] = f"alu_kb_{entry_id:04d}"
125
+ entry_id += 1
126
+
127
+ all_entries.extend(section_entries)
128
+
129
+ print()
130
+ print(f"โœ… Created {len(all_entries)} knowledge base entries")
131
+ print()
132
+
133
+ # Create the brain JSON structure
134
+ brain_data = {
135
+ "category": "comprehensive_knowledge",
136
+ "description": "Complete ALU Knowledge Base - Academic Calendar, SPD Hub, Immigration, Programs, Policies, and More",
137
+ "version": "2.0",
138
+ "last_updated": "2024-11-20",
139
+ "total_entries": len(all_entries),
140
+ "entries": all_entries
141
+ }
142
+
143
+ # Save to alu_brain directory
144
+ output_file = Path("alu_brain/comprehensive_knowledge.json")
145
+ print(f"๐Ÿ’พ Saving to: {output_file}")
146
+
147
+ with open(output_file, 'w', encoding='utf-8') as f:
148
+ json.dump(brain_data, f, indent=2, ensure_ascii=False)
149
+
150
+ print(f"โœ… Successfully saved {len(all_entries)} entries")
151
+ print()
152
+
153
+ # Show statistics
154
+ categories = {}
155
+ for entry in all_entries:
156
+ cat = entry['category']
157
+ categories[cat] = categories.get(cat, 0) + 1
158
+
159
+ print("๐Ÿ“Š Entries by Category:")
160
+ for cat, count in sorted(categories.items(), key=lambda x: x[1], reverse=True):
161
+ print(f" โ€ข {cat}: {count} entries")
162
+
163
+ print()
164
+ print("=" * 70)
165
+ print("โœ… CONVERSION COMPLETE!")
166
+ print("=" * 70)
167
+ print()
168
+ print("๐Ÿ“ Sample entries:")
169
+ for entry in all_entries[:5]:
170
+ print(f" โ€ข {entry['question'][:60]}...")
171
+
172
+ print()
173
+ print("๐Ÿš€ Next steps:")
174
+ print(" 1. Review the generated JSON file")
175
+ print(" 2. Commit and push to Hugging Face")
176
+ print(" 3. Restart the Space")
177
+ print(" 4. Test with questions like:")
178
+ print(" - 'How to create a club at ALU?'")
179
+ print(" - 'Who founded ALU?'")
180
+ print(" - 'When is the next term?'")
181
+ print()
182
+
183
+ return True
184
+
185
+ if __name__ == "__main__":
186
+ convert_comprehensive_kb()
187
+
188
+
convert_comprehensive_kb.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Convert comprehensive knowledge base TXT to ALU Brain JSON format
3
+ This will make your knowledge base actually usable by the chatbot!
4
+ """
5
+
6
+ import json
7
+ from pathlib import Path
8
+ import re
9
+
10
+ def parse_comprehensive_kb():
11
+ """Parse the comprehensive knowledge base text file"""
12
+
13
+ kb_file = Path("data/alu_knowledge/alu_ultimate_knowledge_base.txt")
14
+
15
+ if not kb_file.exists():
16
+ print(f"โŒ Knowledge base file not found: {kb_file}")
17
+ return None
18
+
19
+ with open(kb_file, 'r', encoding='utf-8') as f:
20
+ content = f.read()
21
+
22
+ # Split by major sections (## headers)
23
+ sections = re.split(r'\n##\s+', content)
24
+
25
+ entries = []
26
+ entry_id = 1
27
+
28
+ for section in sections:
29
+ if not section.strip():
30
+ continue
31
+
32
+ lines = section.split('\n')
33
+ title = lines[0].strip()
34
+
35
+ # Get the content
36
+ content_lines = []
37
+ current_subsection = ""
38
+
39
+ for line in lines[1:]:
40
+ if line.strip():
41
+ if line.startswith('###'): # Subsection
42
+ current_subsection = line.replace('###', '').strip()
43
+ elif line.startswith('-') or line.startswith('*'): # List item
44
+ content_lines.append(line.strip())
45
+ else:
46
+ content_lines.append(line.strip())
47
+
48
+ full_content = '\n'.join(content_lines)
49
+
50
+ # Create entry
51
+ entry = {
52
+ "id": f"comprehensive_kb_{entry_id}",
53
+ "question": f"Tell me about {title}",
54
+ "answer": full_content,
55
+ "type": "text",
56
+ "keywords": [word.lower() for word in title.split() if len(word) > 3],
57
+ "category": "Comprehensive Knowledge Base",
58
+ "source": "ALU Comprehensive KB"
59
+ }
60
+
61
+ entries.append(entry)
62
+ entry_id += 1
63
+
64
+ # Also create entries for common questions
65
+ if "club" in title.lower():
66
+ entries.append({
67
+ "id": f"comprehensive_kb_{entry_id}",
68
+ "question": "How to create a club at ALU?",
69
+ "answer": full_content,
70
+ "type": "text",
71
+ "keywords": ["club", "create", "start", "society", "organization"],
72
+ "category": "Campus Life",
73
+ "source": "ALU Comprehensive KB"
74
+ })
75
+ entry_id += 1
76
+
77
+ if "founder" in title.lower() or "leadership" in title.lower():
78
+ entries.append({
79
+ "id": f"comprehensive_kb_{entry_id}",
80
+ "question": "Who founded ALU?",
81
+ "answer": full_content,
82
+ "type": "text",
83
+ "keywords": ["founder", "fred", "swaniker", "leadership", "history"],
84
+ "category": "About ALU",
85
+ "source": "ALU Comprehensive KB"
86
+ })
87
+ entry_id += 1
88
+
89
+ return entries
90
+
91
+ def create_brain_json():
92
+ """Create the ALU Brain JSON file"""
93
+
94
+ print("============================================================")
95
+ print("๐Ÿง  CONVERTING COMPREHENSIVE KB TO ALU BRAIN FORMAT")
96
+ print("============================================================\n")
97
+
98
+ entries = parse_comprehensive_kb()
99
+
100
+ if not entries:
101
+ print("โŒ No entries created")
102
+ return False
103
+
104
+ # Create the brain JSON structure
105
+ brain_data = {
106
+ "category": "comprehensive_knowledge",
107
+ "description": "Comprehensive ALU Knowledge Base - All ALU information",
108
+ "version": "1.0",
109
+ "last_updated": "2024-11-20",
110
+ "entries": entries
111
+ }
112
+
113
+ # Save to alu_brain directory
114
+ output_file = Path("alu_brain/comprehensive_knowledge.json")
115
+ with open(output_file, 'w', encoding='utf-8') as f:
116
+ json.dump(brain_data, f, indent=2, ensure_ascii=False)
117
+
118
+ print(f"โœ… Created {len(entries)} entries")
119
+ print(f"๐Ÿ“ Saved to: {output_file}")
120
+ print(f"\n๐Ÿ“ Sample entries:")
121
+ for entry in entries[:3]:
122
+ print(f" - {entry['question']}")
123
+
124
+ print("\n============================================================")
125
+ print("โœ… CONVERSION COMPLETE!")
126
+ print("============================================================")
127
+ print("\nNext steps:")
128
+ print("1. Commit and push this file to Hugging Face")
129
+ print("2. Restart the Space")
130
+ print("3. The chatbot will now use your comprehensive knowledge!")
131
+
132
+ return True
133
+
134
+ if __name__ == "__main__":
135
+ create_brain_json()
136
+
137
+
convert_kb_to_brain.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Convert comprehensive knowledge base to ALU Brain JSON format
3
+ """
4
+
5
+ import json
6
+ from pathlib import Path
7
+
8
+ def convert_kb_to_brain_format():
9
+ """Convert the comprehensive KB into ALU Brain JSON entries"""
10
+
11
+ # Read the comprehensive knowledge base
12
+ kb_file = Path("data/alu_knowledge/alu_ultimate_knowledge_base.txt")
13
+
14
+ if not kb_file.exists():
15
+ print(f"โŒ Knowledge base file not found: {kb_file}")
16
+ return
17
+
18
+ with open(kb_file, 'r', encoding='utf-8') as f:
19
+ kb_text = f.read()
20
+
21
+ # Split into sections
22
+ sections = kb_text.split('\n## ')
23
+
24
+ brain_entries = []
25
+
26
+ for section in sections[1:]: # Skip first empty section
27
+ lines = section.split('\n')
28
+ title = lines[0].strip()
29
+ content = '\n'.join(lines[1:]).strip()
30
+
31
+ # Create brain entry
32
+ entry = {
33
+ "question": f"Tell me about {title}",
34
+ "answer": content[:500] + "..." if len(content) > 500 else content, # Limit length
35
+ "type": "text",
36
+ "category": "comprehensive_kb",
37
+ "keywords": title.lower().split()
38
+ }
39
+
40
+ brain_entries.append(entry)
41
+
42
+ # Save to new JSON file
43
+ output_file = Path("alu_brain/comprehensive_kb.json")
44
+ with open(output_file, 'w', encoding='utf-8') as f:
45
+ json.dump(brain_entries, f, indent=2)
46
+
47
+ print(f"โœ… Created {len(brain_entries)} entries in {output_file}")
48
+ print(f"๐Ÿ“ Sample entry: {brain_entries[0]['question']}")
49
+
50
+ if __name__ == "__main__":
51
+ convert_kb_to_brain_format()
52
+
53
+
ersNgumDownloadsalu-chatbot ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ diff --git a/app.py b/app.py
2
+ index 58d2706..20c00eb 100644
3
+ --- a/app.py
4
+ +++ b/app.py
5
+ @@ -1,52 +1,173 @@
6
+ import os
7
+ import sys
8
+ +from pathlib import Path
9
+ +from fastapi import FastAPI, HTTPException
10
+ +from fastapi.staticfiles import StaticFiles
11
+ +from fastapi.responses import FileResponse, JSONResponse
12
+ +from fastapi.middleware.cors import CORSMiddleware
13
+ 
14
+ -# Set environment variables for Hugging Face
15
+ -os.environ["TRANSFORMERS_CACHE"] = "/tmp/model_cache"
16
+ -os.environ["HF_HOME"] = "/tmp/model_cache"
17
+ -os.environ["SENTENCE_TRANSFORMERS_HOME"] = "/tmp/model_cache"
18
+ -os.environ["PYTHONUNBUFFERED"] = "1"
19
+ -
20
+ -# Print startup diagnostic info
21
+ +print("=" * 60)
22
+ print("=== STARTUP: Beginning application initialization ===")
23
+ -print(f"=== STARTUP: PORT environment variable: {os.environ.get('PORT')} ===")
24
+ +print("=" * 60)
25
+ 
26
+ -# First import just the app from main
27
+ -from main import app
28
+ +# Add current directory to Python path so imports work
29
+ +current_path = os.path.dirname(__file__)
30
+ +if current_path not in sys.path:
31
+ + sys.path.insert(0, current_path)
32
+ 
33
+ -# THEN import other components
34
+ -from main import conversation_memory
35
+ -from data_integration.alu_api_connector import ALUDataConnector
36
+ -from analytics.conversation_analytics import ConversationAnalytics
37
+ +# Ensure required directories exist
38
+ +os.makedirs("build/static", exist_ok=True)
39
+ +os.makedirs("build/assets", exist_ok=True)
40
+ 
41
+ -@app.get("/api/alu-events")
42
+ -async def get_alu_events(campus: str = "all", days: int = 7):
43
+ - """Get upcoming events at ALU"""
44
+ +# Load comprehensive knowledge base on startup
45
+ +def load_comprehensive_knowledge_base():
46
+ + """Load the comprehensive ALU knowledge base into vector store"""
47
+ try:
48
+ - alu_connector = ALUDataConnector()
49
+ - events = alu_connector.get_upcoming_events(campus, days)
50
+ - return {"events": events}
51
+ + print("\n๐ŸŽ“ Loading comprehensive ALU knowledge base...")
52
+ + from retrieval_engine import RetrievalEngine
53
+ + 
54
+ + # Check for knowledge base files
55
+ + kb_paths = [
56
+ + Path("data/alu_knowledge"),
57
+ + Path("backend/data/alu_knowledge"),
58
+ + Path("/data/alu_knowledge")
59
+ + ]
60
+ + 
61
+ + kb_dir = None
62
+ + for path in kb_paths:
63
+ + if path.exists():
64
+ + kb_dir = path
65
+ + break
66
+ + 
67
+ + if not kb_dir:
68
+ + print("โš ๏ธ Knowledge base directory not found. Using default ALU Brain.")
69
+ + return False
70
+ + 
71
+ + # Find knowledge base file
72
+ + kb_files = [
73
+ + "alu_ultimate_knowledge_base.txt",
74
+ + "alu_knowledge_base.txt"
75
+ + ]
76
+ + 
77
+ + kb_file = None
78
+ + for filename in kb_files:
79
+ + file_path = kb_dir / filename
80
+ + if file_path.exists():
81
+ + kb_file = file_path
82
+ + break
83
+ + 
84
+ + if not kb_file:
85
+ + print("โš ๏ธ Knowledge base file not found. Using default ALU Brain.")
86
+ + return False
87
+ + 
88
+ + print(f"๐Ÿ“„ Found knowledge base: {kb_file.name}")
89
+ + 
90
+ + # Load and process
91
+ + with open(kb_file, 'r', encoding='utf-8') as f:
92
+ + kb_text = f.read()
93
+ + 
94
+ + print(f"โœ… Loaded {len(kb_text):,} characters")
95
+ + 
96
+ + # Initialize retrieval engine
97
+ + retrieval_engine = RetrievalEngine()
98
+ + 
99
+ + # Chunk text
100
+ + chunks = retrieval_engine._chunk_text(kb_text, chunk_size=800, chunk_overlap=100)
101
+ + print(f"โœ… Created {len(chunks)} chunks")
102
+ + 
103
+ + # Add to vector store
104
+ + print("๐Ÿ“ฅ Adding to vector store...")
105
+ + for i, chunk in enumerate(chunks):
106
+ + chunk_id = f"alu_comprehensive_kb_{i}"
107
+ + metadata = {
108
+ + "source": "ALU Comprehensive Knowledge Base 2024",
109
+ + "chunk_id": i,
110
+ + "type": "comprehensive_kb"
111
+ + }
112
+ + 
113
+ + try:
114
+ + retrieval_engine.collection.add(
115
+ + ids=[chunk_id],
116
+ + documents=[chunk],
117
+ + metadatas=[metadata]
118
+ + )
119
+ + except Exception as e:
120
+ + if i == 0: # Only print error for first chunk
121
+ + print(f"โš ๏ธ Note: {e}")
122
+ + 
123
+ + print(f"โœ… Comprehensive knowledge base loaded! ({len(chunks)} chunks)")
124
+ + return True
125
+ + 
126
+ except Exception as e:
127
+ - print(f"Error fetching ALU events: {e}")
128
+ - return {"events": [], "error": "Could not fetch events"}
129
+ + print(f"โš ๏ธ Error loading comprehensive KB: {e}")
130
+ + return False
131
+ +
132
+ +# Load knowledge base (commented out to prevent startup timeout)
133
+ +# Uncomment this line once the Space is stable:
134
+ +# load_comprehensive_knowledge_base()
135
+ +print("โš ๏ธ Comprehensive KB loading disabled to prevent timeout")
136
+ +print("๐Ÿ’ก The chatbot will use the existing ALU Brain knowledge base")
137
+ 
138
+ -@app.get("/api/analytics/dashboard")
139
+ -async def get_analytics_dashboard():
140
+ - """Get analytics dashboard data"""
141
+ +# Import your backend app (using minimal version to avoid model loading issues)
142
+ +print("\n๐Ÿ“ฆ Importing minimal backend application...")
143
+ +try:
144
+ + from minimal_app import app as backend_app
145
+ + print("โœ… Minimal backend application imported (no ML models required)")
146
+ +except ImportError:
147
+ + print("โš ๏ธ Minimal backend not found, trying lightweight...")
148
+ try:
149
+ - if not conversation_memory:
150
+ - return {"error": "Conversation memory not initialized"}
151
+ - 
152
+ - analytics = ConversationAnalytics(conversation_memory)
153
+ - dashboard_data = analytics.generate_dashboard_data()
154
+ - return dashboard_data
155
+ - except Exception as e:
156
+ - print(f"Error generating analytics dashboard: {e}")
157
+ - return {"error": f"Could not generate analytics: {str(e)}"}
158
+ -
159
+ -# This is needed for Hugging Face Spaces
160
+ -if __name__ == "__main__":
161
+ - import uvicorn
162
+ - port = int(os.environ.get("PORT", 7860)) # Hugging Face uses port 7860
163
+ - print(f"Starting server on port {port}")
164
+ - uvicorn.run(app, host="0.0.0.0", port=port)
165
+ 
166
+ + from main_lightweight import app as backend_app
167
+ + print("โœ… Lightweight backend application imported")
168
+ + except ImportError:
169
+ + print("โš ๏ธ Using main backend...")
170
+ + from main import app as backend_app
171
+ + print("โœ… Main backend application imported")
172
+ +
173
+ +app = FastAPI()
174
+ +
175
+ +# Configure CORS - copy settings from your backend
176
+ +allowed_origins = os.getenv("CORS_ALLOWED_ORIGINS", "http://localhost:3000,http://localhost:3001").split(",")
177
+ +app.add_middleware(
178
+ + CORSMiddleware,
179
+ + allow_origins=["*"], # Allow all origins when serving from same domain
180
+ + allow_credentials=True,
181
+ + allow_methods=["*"],
182
+ + allow_headers=["*"],
183
+ +)
184
+ +
185
+ +# Serve static files from React build
186
+ +app.mount("/static", StaticFiles(directory="build/static"), name="static")
187
+ +app.mount("/assets", StaticFiles(directory="build/assets", check_dir=False), name="assets")
188
+ +
189
+ +# Mount your backend API - all backend routes will be served under /api
190
+ +# IMPORTANT: Mount this AFTER static files but BEFORE catch-all route
191
+ +app.mount("/api", backend_app)
192
+ +
193
+ +# Root endpoint - return JSON instead of trying to serve files
194
+ +@app.get("/")
195
+ +async def root():
196
+ + return {
197
+ + "status": "running",
198
+ + "message": "ALU Student Companion API",
199
+ + "api_endpoints": {
200
+ + "health": "/health",
201
+ + "chat": "/api/chat",
202
+ + "docs": "/docs"
203
+ + }
204
+ + }
205
+ +
206
+ +# Health check endpoint
207
+ +@app.get("/health")
208
+ +async def health():
209
+ + return {"status": "healthy", "api": True, "backend": True}
210
+ +
211
+ +# Serve React app for specific paths only (not catch-all)
212
+ +@app.get("/static/{full_path:path}")
213
+ +async def serve_static(full_path: str):
214
+ + file_path = f"build/static/{full_path}"
215
+ + if os.path.exists(file_path):
216
+ + return FileResponse(file_path)
217
+ + return JSONResponse(
218
+ + content={"error": "File not found"},
219
+ + status_code=404
220
+ + )