import os from flask import request, jsonify from sentence_transformers import SentenceTransformer, util # Define a writable directory for the model cache. # This now respects the HF_HOME environment variable set in the Dockerfile. cache_dir = os.environ.get("HF_HOME", "/tmp/huggingface") os.makedirs(cache_dir, exist_ok=True) print("Loading SentenceTransformer model (paraphrase-MiniLM-L6-v2)...") matcher_model = SentenceTransformer('sentence-transformers/paraphrase-MiniLM-L6-v2', cache_folder=cache_dir) print("SentenceTransformer model loaded.") # Define a threshold for a "good" match SIMILARITY_THRESHOLD = 0.6 def handle_match_question(): data = request.get_json() if not data or 'user_question' not in data or 'documents' not in data: return jsonify({'error': 'Invalid request. "user_question" and "documents" are required.'}), 400 user_question = data['user_question'] documents = data['documents'] if not documents: return jsonify({'answer': "There are no notes to search."}) # Flatten the list of questions from all documents all_questions = [] # Map each question to the original note text question_to_note_map = {} for doc in documents: note_text = doc.get('note_text', '') for q in doc.get('questions', []): all_questions.append(q) question_to_note_map[q] = note_text if not all_questions: return jsonify({'answer': "No questions have been generated for your notes yet."}) try: # Encode the user's question and all stored questions user_embedding = matcher_model.encode(user_question, convert_to_tensor=True) stored_embeddings = matcher_model.encode(all_questions, convert_to_tensor=True) # Compute cosine similarity cosine_scores = util.pytorch_cos_sim(user_embedding, stored_embeddings) # Find the best match best_match_idx = cosine_scores.argmax() best_score = float(cosine_scores[0][best_match_idx]) best_question = all_questions[best_match_idx] print(f"User Question: '{user_question}'") print(f"Best matched stored question: '{best_question}' with score: {best_score:.4f}") # Check if the match is good enough if best_score > SIMILARITY_THRESHOLD: # Return the note associated with the best-matched question answer = question_to_note_map[best_question] else: answer = "Sorry, I couldn't find a relevant note to answer your question." return jsonify({'answer': answer}) except Exception as e: print(f"Error during question matching: {e}") return jsonify({'error': str(e)}), 500