diff --git a/backend/.gitignore b/backend/.gitignore index 1370dcc89..282464865 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,5 +1,6 @@ .env __pycache__/ bluebook_env/ +bluebook_env_1/ .coverage htmlcov \ No newline at end of file diff --git a/backend/__pycache__/lib.cpython-312.pyc b/backend/__pycache__/lib.cpython-312.pyc index 5b6e153fc..62455bce6 100644 Binary files a/backend/__pycache__/lib.cpython-312.pyc and b/backend/__pycache__/lib.cpython-312.pyc differ diff --git a/backend/app.py b/backend/app.py index 16269d9b5..f66a27448 100644 --- a/backend/app.py +++ b/backend/app.py @@ -9,6 +9,7 @@ from pymongo.mongo_client import MongoClient import requests import xml.etree.ElementTree as ET +import datetime COURSE_QUERY_LIMIT = 5 SAFETY_CHECK_ENABLED = False @@ -31,7 +32,6 @@ def load_config(app, test_config=None): # Load configuration from environment variables app.config["MONGO_URI"] = os.getenv("MONGO_URI") - # Separate function to initialize database def init_database(app): if "MONGO_URI" in app.config: @@ -40,7 +40,6 @@ def init_database(app): app.config["collection"] = db["parsed_courses"] # else, set to None or Mock in case of testing - def create_app(test_config=None): app = Flask(__name__) CORS(app) @@ -101,7 +100,14 @@ def validate_cas_ticket(): @app.route("/api/chat", methods=["POST"]) def chat(): data = request.get_json() - user_messages = data["message"] + user_messages = data.get("message", None) + + filter_season_codes = data.get("season_codes", None) # assume it is an array of season code + filter_subject = data.get("subject", None) + filter_areas = data.get("areas", None) + + if not user_messages: + return jsonify({"error": "No message provided"}) # remove id before sending to OpenAI for message in user_messages: @@ -187,33 +193,50 @@ def chat(): collection = app.config["collection"] - database_response = collection.aggregate( - [ - { - "$vectorSearch": { - "index": "parsed_courses_title_description_index", - "path": "embedding", - # 'filter': { - # 'rating': { - # args['operator']: args['rating'] - # } - # }, - "queryVector": query_vector, - "numCandidates": 30, - "limit": COURSE_QUERY_LIMIT, - } + aggregate_pipeline = { + "$vectorSearch": { + "index": "parsed_courses_title_description_index", + "path": "embedding", + "queryVector": query_vector, + "numCandidates": 30, + "limit": COURSE_QUERY_LIMIT, + } + } + + if filter_season_codes: + aggregate_pipeline["$vectorSearch"]["filter"] = { + "season_code": { + "$in": filter_season_codes } - ] - ) + } + + if filter_subject: + aggregate_pipeline["$vectorSearch"]["filter"] = { + "subject": { + "$eq": filter_subject + } + } + + if filter_areas: + aggregate_pipeline["$vectorSearch"]["filter"] = { + "areas": { + "$in": filter_areas + } + } + database_response = collection.aggregate([aggregate_pipeline]) database_response = list(database_response) recommended_courses = [ { + "season_code": course["season_code"], "course_code": course["course_code"], "title": course["title"], "description": course["description"], "areas": course["areas"], + "sentiment_label": course["sentiment_info"]["final_label"], + "sentiment_score": course["sentiment_info"]["final_proportion"], + } for course in database_response ] diff --git a/backend/test_app.py b/backend/test_app.py index 0067b26b7..bad5cc314 100644 --- a/backend/test_app.py +++ b/backend/test_app.py @@ -13,8 +13,10 @@ def client(): "course_code": "CPSC 150", "description": "Introduction to the basic ideas of computer science (computability, algorithm, virtual machine, symbol processing system), and of several ongoing relationships between computer science and other fields, particularly philosophy of mind.", "season_code": "202303", - "sentiment_label": "NEGATIVE", - "sentiment_score": 0.9444444444444444, + "sentiment_info": { + "final_label": "NEGATIVE", + "final_proportion": 0.9444444444444444, + }, "title": "Computer Science and the Modern Intellectual Agenda", }, ]