alu-chatbot / ersNgumDownloadsalu-chatbot
Ngum's picture
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
ababeb3
Raw
History Blame
11 kB
diff --git a/app.py b/app.py
index 58d2706..20c00eb 100644
--- a/app.py
+++ b/app.py
@@ -1,52 +1,173 @@
import os
import sys
+from pathlib import Path
+from fastapi import FastAPI, HTTPException
+from fastapi.staticfiles import StaticFiles
+from fastapi.responses import FileResponse, JSONResponse
+from fastapi.middleware.cors import CORSMiddleware

-# Set environment variables for Hugging Face
-os.environ["TRANSFORMERS_CACHE"] = "/tmp/model_cache"
-os.environ["HF_HOME"] = "/tmp/model_cache"
-os.environ["SENTENCE_TRANSFORMERS_HOME"] = "/tmp/model_cache"
-os.environ["PYTHONUNBUFFERED"] = "1"
-
-# Print startup diagnostic info
+print("=" * 60)
print("=== STARTUP: Beginning application initialization ===")
-print(f"=== STARTUP: PORT environment variable: {os.environ.get('PORT')} ===")
+print("=" * 60)

-# First import just the app from main
-from main import app
+# Add current directory to Python path so imports work
+current_path = os.path.dirname(__file__)
+if current_path not in sys.path:
+ sys.path.insert(0, current_path)

-# THEN import other components
-from main import conversation_memory
-from data_integration.alu_api_connector import ALUDataConnector
-from analytics.conversation_analytics import ConversationAnalytics
+# Ensure required directories exist
+os.makedirs("build/static", exist_ok=True)
+os.makedirs("build/assets", exist_ok=True)

-@app.get("/api/alu-events")
-async def get_alu_events(campus: str = "all", days: int = 7):
- """Get upcoming events at ALU"""
+# Load comprehensive knowledge base on startup
+def load_comprehensive_knowledge_base():
+ """Load the comprehensive ALU knowledge base into vector store"""
try:
- alu_connector = ALUDataConnector()
- events = alu_connector.get_upcoming_events(campus, days)
- return {"events": events}
+ print("\nπŸŽ“ Loading comprehensive ALU knowledge base...")
+ from retrieval_engine import RetrievalEngine
+ 
+ # Check for knowledge base files
+ kb_paths = [
+ Path("data/alu_knowledge"),
+ Path("backend/data/alu_knowledge"),
+ Path("/data/alu_knowledge")
+ ]
+ 
+ kb_dir = None
+ for path in kb_paths:
+ if path.exists():
+ kb_dir = path
+ break
+ 
+ if not kb_dir:
+ print("⚠️ Knowledge base directory not found. Using default ALU Brain.")
+ return False
+ 
+ # Find knowledge base file
+ kb_files = [
+ "alu_ultimate_knowledge_base.txt",
+ "alu_knowledge_base.txt"
+ ]
+ 
+ kb_file = None
+ for filename in kb_files:
+ file_path = kb_dir / filename
+ if file_path.exists():
+ kb_file = file_path
+ break
+ 
+ if not kb_file:
+ print("⚠️ Knowledge base file not found. Using default ALU Brain.")
+ return False
+ 
+ print(f"πŸ“„ Found knowledge base: {kb_file.name}")
+ 
+ # Load and process
+ with open(kb_file, 'r', encoding='utf-8') as f:
+ kb_text = f.read()
+ 
+ print(f"βœ… Loaded {len(kb_text):,} characters")
+ 
+ # Initialize retrieval engine
+ retrieval_engine = RetrievalEngine()
+ 
+ # Chunk text
+ chunks = retrieval_engine._chunk_text(kb_text, chunk_size=800, chunk_overlap=100)
+ print(f"βœ… Created {len(chunks)} chunks")
+ 
+ # Add to vector store
+ print("πŸ“₯ Adding to vector store...")
+ for i, chunk in enumerate(chunks):
+ chunk_id = f"alu_comprehensive_kb_{i}"
+ metadata = {
+ "source": "ALU Comprehensive Knowledge Base 2024",
+ "chunk_id": i,
+ "type": "comprehensive_kb"
+ }
+ 
+ try:
+ retrieval_engine.collection.add(
+ ids=[chunk_id],
+ documents=[chunk],
+ metadatas=[metadata]
+ )
+ except Exception as e:
+ if i == 0: # Only print error for first chunk
+ print(f"⚠️ Note: {e}")
+ 
+ print(f"βœ… Comprehensive knowledge base loaded! ({len(chunks)} chunks)")
+ return True
+ 
except Exception as e:
- print(f"Error fetching ALU events: {e}")
- return {"events": [], "error": "Could not fetch events"}
+ print(f"⚠️ Error loading comprehensive KB: {e}")
+ return False
+
+# Load knowledge base (commented out to prevent startup timeout)
+# Uncomment this line once the Space is stable:
+# load_comprehensive_knowledge_base()
+print("⚠️ Comprehensive KB loading disabled to prevent timeout")
+print("πŸ’‘ The chatbot will use the existing ALU Brain knowledge base")

-@app.get("/api/analytics/dashboard")
-async def get_analytics_dashboard():
- """Get analytics dashboard data"""
+# Import your backend app (using minimal version to avoid model loading issues)
+print("\nπŸ“¦ Importing minimal backend application...")
+try:
+ from minimal_app import app as backend_app
+ print("βœ… Minimal backend application imported (no ML models required)")
+except ImportError:
+ print("⚠️ Minimal backend not found, trying lightweight...")
try:
- if not conversation_memory:
- return {"error": "Conversation memory not initialized"}
- 
- analytics = ConversationAnalytics(conversation_memory)
- dashboard_data = analytics.generate_dashboard_data()
- return dashboard_data
- except Exception as e:
- print(f"Error generating analytics dashboard: {e}")
- return {"error": f"Could not generate analytics: {str(e)}"}
-
-# This is needed for Hugging Face Spaces
-if __name__ == "__main__":
- import uvicorn
- port = int(os.environ.get("PORT", 7860)) # Hugging Face uses port 7860
- print(f"Starting server on port {port}")
- uvicorn.run(app, host="0.0.0.0", port=port)
\ No newline at end of file
+ from main_lightweight import app as backend_app
+ print("βœ… Lightweight backend application imported")
+ except ImportError:
+ print("⚠️ Using main backend...")
+ from main import app as backend_app
+ print("βœ… Main backend application imported")
+
+app = FastAPI()
+
+# Configure CORS - copy settings from your backend
+allowed_origins = os.getenv("CORS_ALLOWED_ORIGINS", "http://localhost:3000,http://localhost:3001").split(",")
+app.add_middleware(
+ CORSMiddleware,
+ allow_origins=["*"], # Allow all origins when serving from same domain
+ allow_credentials=True,
+ allow_methods=["*"],
+ allow_headers=["*"],
+)
+
+# Serve static files from React build
+app.mount("/static", StaticFiles(directory="build/static"), name="static")
+app.mount("/assets", StaticFiles(directory="build/assets", check_dir=False), name="assets")
+
+# Mount your backend API - all backend routes will be served under /api
+# IMPORTANT: Mount this AFTER static files but BEFORE catch-all route
+app.mount("/api", backend_app)
+
+# Root endpoint - return JSON instead of trying to serve files
+@app.get("/")
+async def root():
+ return {
+ "status": "running",
+ "message": "ALU Student Companion API",
+ "api_endpoints": {
+ "health": "/health",
+ "chat": "/api/chat",
+ "docs": "/docs"
+ }
+ }
+
+# Health check endpoint
+@app.get("/health")
+async def health():
+ return {"status": "healthy", "api": True, "backend": True}
+
+# Serve React app for specific paths only (not catch-all)
+@app.get("/static/{full_path:path}")
+async def serve_static(full_path: str):
+ file_path = f"build/static/{full_path}"
+ if os.path.exists(file_path):
+ return FileResponse(file_path)
+ return JSONResponse(
+ content={"error": "File not found"},
+ status_code=404
+ )