import requests import json from sentence_transformers import SentenceTransformer import numpy as np from sklearn.metrics.pairwise import cosine_similarity from recommender import CourseRecommender class Chatbot: def __init__(self): self.qa_pairs = [] self.question_embeddings = [] self.model = SentenceTransformer('all-MiniLM-L6-v2') self.database_url = "https://database-46m3.onrender.com" self.recommender = CourseRecommender() self.load_qa_data() def load_qa_data(self): """Load Q&A pairs from the faqs table in the database""" try: # Connect to the faqs table endpoint faqs_url = f"{self.database_url}/faqs" response = requests.get(faqs_url) if response.status_code == 200: data = response.json() # Assuming the database returns a list of FAQ objects if isinstance(data, list): self.qa_pairs = data else: # If it's a single object, wrap it in a list self.qa_pairs = [data] # Generate embeddings for all questions questions = [item.get('question', '') for item in self.qa_pairs] self.question_embeddings = self.model.encode(questions) print(f"Loaded {len(self.qa_pairs)} FAQ pairs from database") else: print(f"Failed to load data from faqs table. Status code: {response.status_code}") self._load_fallback_data() except Exception as e: print(f"Error loading FAQ data: {str(e)}") self._load_fallback_data() def _load_fallback_data(self): """Load fallback data if database is unavailable""" self.qa_pairs = [ {"question": "What is artificial intelligence?", "answer": "Artificial Intelligence (AI) is a branch of computer science that aims to create machines capable of intelligent behavior."}, {"question": "How does machine learning work?", "answer": "Machine learning is a subset of AI that enables computers to learn and improve from experience without being explicitly programmed."}, {"question": "What is deep learning?", "answer": "Deep learning is a subset of machine learning that uses neural networks with multiple layers to model and understand complex patterns in data."}, {"question": "What is natural language processing?", "answer": "Natural Language Processing (NLP) is a field of AI that focuses on the interaction between computers and humans through natural language."}, {"question": "What is a neural network?", "answer": "A neural network is a computing system inspired by biological neural networks that constitute animal brains. It consists of interconnected nodes (neurons) that process information."} ] questions = [item['question'] for item in self.qa_pairs] self.question_embeddings = self.model.encode(questions) print("Loaded fallback Q&A data") def find_best_match(self, user_input, threshold=0.7): """Find the best matching question using semantic similarity""" if not self.qa_pairs: return None, 0 # Encode the user input user_embedding = self.model.encode([user_input]) # Calculate cosine similarity with all questions similarities = cosine_similarity(user_embedding, self.question_embeddings)[0] # Find the best match best_match_idx = np.argmax(similarities) best_similarity = similarities[best_match_idx] if best_similarity >= threshold: return self.qa_pairs[best_match_idx], best_similarity else: return None, best_similarity def get_response(self, user_input): """Get response for user input""" if not user_input.strip(): return "Please enter a message." best_match, similarity = self.find_best_match(user_input) if best_match: return { 'answer': best_match.get('answer', 'No answer found'), 'confidence': float(similarity), 'matched_question': best_match.get('question', ''), 'status': 'success' } else: return { 'answer': "I'm sorry, I couldn't find a relevant answer to your question. Could you please rephrase it or ask something else?", 'confidence': float(similarity), 'matched_question': '', 'status': 'no_match' } def get_qa_count(self): """Get the number of loaded Q&A pairs""" return len(self.qa_pairs) def get_course_recommendations(self, stanine, gwa, strand, hobbies): """Get course recommendations using the recommender system""" try: # Validate inputs stanine = int(stanine) if isinstance(stanine, str) else stanine gwa = float(gwa) if isinstance(gwa, str) else gwa if not (1 <= stanine <= 9): return "❌ Stanine score must be between 1 and 9" if not (75 <= gwa <= 100): return "❌ GWA must be between 75 and 100" if not strand: return "❌ Please select a strand" if not hobbies or not str(hobbies).strip(): return "❌ Please enter your hobbies/interests" # Get recommendations recommendations = self.recommender.recommend_courses( stanine=stanine, gwa=gwa, strand=strand, hobbies=str(hobbies) ) if not recommendations: return "No recommendations available at the moment." # Format response (without confidence scores) response = f"## 🎯 Course Recommendations for You\n\n" response += f"**Profile:** Stanine {stanine}, GWA {gwa}, {strand} Strand\n" response += f"**Interests:** {hobbies}\n\n" for i, rec in enumerate(recommendations, 1): response += f"### {i}. {rec['code']} - {rec['name']}\n\n" return response except Exception as e: return f"❌ Error getting recommendations: {str(e)}"