From 32c39e59e367acc3c4e3302368bd0e1409788050 Mon Sep 17 00:00:00 2001 From: alexj1701 Date: Mon, 19 Feb 2024 21:52:51 -0500 Subject: [PATCH 01/12] course subjects file --- backend/course_subjects.json | 202 +++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 backend/course_subjects.json diff --git a/backend/course_subjects.json b/backend/course_subjects.json new file mode 100644 index 000000000..70adbdf22 --- /dev/null +++ b/backend/course_subjects.json @@ -0,0 +1,202 @@ +{ + "ACCT": "Accounting", + "USAF": "Aerospace Studies", + "AFAM": "African American Studies", + "AFST": "African Studies", + "AKKD": "Akkadian", + "ASL": "American Sign Language", + "AMST": "American Studies", + "GREK": "Ancient Greek", + "ANTH": "Anthropology", + "AMTH": "Applied Mathematics", + "APHY": "Applied Physics", + "ARBC": "Arabic", + "ARCG": "Archaeological Studies", + "ARCH": "Architecture", + "ARMN": "Armenian", + "ART": "Art", + "ASTR": "Astronomy", + "BNGL": "Bengali", + "B&BS": "Biological & Biomedical Sci", + "BIOL": "Biology", + "BENG": "Biomedical Engineering", + "BIS": "Biostatistics", + "BRST": "British Studies", + "BURM": "Burmese", + "C&MP": "Cell & Molecular Physiology", + "CBIO": "Cell Biology", + "CENG": "Chemical Engineering", + "CHEM": "Chemistry", + "CHER": "Cherokee", + "CHLD": "Child Study", + "CHNS": "Chinese", + "CDE": "Chronic Disease Epidemiology", + "CLCV": "Classical Civilization", + "CLSS": "Classics", + "MEDR": "Clinical Clerkships", + "CGSC": "Cognitive Science", + "CSYC": "Coll Sem: Yale Coll", + "CSBF": "Coll Sem:Ben Franklin Coll", + "CSBK": "Coll Sem:Berkeley Coll", + "CSBR": "Coll Sem:Branford Coll", + "CSDC": "Coll Sem:Davenport Coll", + "CSES": "Coll Sem:Ezra Stiles Coll", + "CSGH": "Coll Sem:Grace Hopper Coll", + "CSJE": "Coll Sem:Jonathan Edwards Coll", + "CSMC": "Coll Sem:Morse Coll", + "CSMY": "Coll Sem:Pauli Murray Coll", + "CSPC": "Coll Sem:Pierson Coll", + "CSSY": "Coll Sem:Saybrook Coll", + "CSSM": "Coll Sem:Silliman Coll", + "CSTD": "Coll Sem:Timothy Dwight Coll", + "CSTC": "Coll Sem:Trumbull Coll", + "CB&B": "Comp Biol & Bioinfomatics", + "CPLT": "Comparative Literature", + "CPSC": "Computer Science", + "CSEC": "Computer Science and Economics", + "CPAR": "Computing and the Arts", + "MEDC": "Courses in School of Medicine", + "CZEC": "Czech", + "DEVN": "DeVane Lecture Course", + "DRST": "Directed Studies", + "DIR": "Directing", + "DISR": "Diss Research - in Residence", + "DRAM": "Drama", + "DRMA": "Drama Summer", + "DUTC": "Dutch", + "EMST": "Early Modern Studies", + "EPS": "Earth and Planetary Sciences", + "EALL": "East Asian Lang and Lit", + "EAST": "East Asian Studies", + "E&EB": "Ecology & Evolutionary Biology", + "ECON": "Economics", + "EDST": "Education Studies", + "EGYP": "Egyptology", + "EENG": "Electrical Engineering", + "ENRG": "Energy Studies", + "ENAS": "Engineering & Applied Science", + "ENGL": "English", + "ELP": "English Language Program", + "ENV": "Environment", + "ENVE": "Environmental Engineering", + "EHS": "Environmental Health Sciences", + "EVST": "Environmental Studies", + "EPH": "Epidemiology & Public Health", + "EMD": "Epidemiology Microbial Disease", + "EP&E": "Ethics, Politics, & Economics", + "ER&M": "Ethnicity, Race, & Migration", + "E&RS": "European & Russian Studies", + "EXCH": "Exchange Scholar Experience", + "EXPA": "Experimental Pathology", + "FILM": "Film & Media Studies", + "FNSH": "Finnish", + "F&ES": "Forestry & Environment Studies", + "FREN": "French", + "GENE": "Genetics", + "G&G": "Geology and Geophysics", + "GMAN": "German", + "GLBL": "Global Affairs", + "HPM": "Health Policy and Management", + "HLTH": "Health Studies", + "HEBR": "Hebrew", + "HNDI": "Hindi", + "HSHM": "Hist of Science, Hist of Med", + "HIST": "History", + "HSAR": "History of Art", + "HMRT": "Human Rights", + "HUMS": "Humanities", + "HGRN": "Hungarian", + "IBIO": "Immunobiology", + "IDRS": "Ind Res in Sciences", + "INDN": "Indonesian", + "INP": "Interdpt Neuroscience Pgm", + "IMED": "Investigative Medicine", + "ITAL": "Italian Studies", + "JAPN": "Japanese", + "JDST": "Jewish Studies", + "KHMR": "Khmer", + "SWAH": "Kiswahili", + "KREN": "Korean", + "LATN": "Latin", + "LAST": "Latin American Studies", + "LAW": "Law", + "LING": "Linguistics", + "LITR": "Literature", + "MGT": "Management", + "MGMT": "Management, PhD", + "MRES": "Master's Thesis Research", + "MHHR": "Material Hist of Human Record", + "MATH": "Mathematics", + "MENG": "Mechanical Engineering", + "MDVL": "Medieval Studies", + "MESO": "Mesopotamia", + "MBIO": "Microbiology", + "MGRK": "Modern Greek", + "MMES": "Modern Middle East Studies", + "MTBT": "Modern Tibetan", + "MB&B": "Molecular Biophysics & Biochem", + "MCDB": "Molecular, Cellular & Dev Biol", + "MUSI": "Music Department", + "NAVY": "Naval Science", + "NELC": "Near Eastern Langs & Civs", + "NPLI": "Nepali", + "NSCI": "Neuroscience", + "NURS": "Nursing", + "OTTM": "Ottoman", + "PATH": "Pathology", + "PERS": "Persian", + "PHAR": "Pharmacology", + "PHIL": "Philosophy", + "OLPA": "Physician Assistant Online Pgm", + "PA": "Physician Associate Program", + "PHYS": "Physics", + "PLSH": "Polish", + "PLSC": "Political Science", + "PORT": "Portuguese", + "PRAC": "Practicum Analysis", + "CAND": "Prep for Adv to Candidacy", + "QUAL": "Preparing for Qualifying Exams", + "PSYC": "Psychology", + "PHUM": "Public Humanities", + "PNJB": "Punjabi", + "REL": "Religion", + "RLST": "Religious Studies", + "RNST": "Renaissance Studies", + "ROMN": "Romanian", + "RUSS": "Russian", + "RSEE": "Russian & East Europe Studies", + "SKRT": "Sanskrit", + "MD": "School of Medicine", + "MUS": "School of Music", + "SCIE": "Science", + "SMTC": "Semitic", + "SBCR": "Serbian & Croatian", + "SNHL": "Sinhala", + "SLAV": "Slavic", + "SBS": "Social and Behavioral Sciences", + "SOCY": "Sociology", + "SAST": "South Asian Studies", + "SPAN": "Spanish", + "SPEC": "Special Divisional Major", + "STRT": "Start Program - Medical School", + "S&DS": "Statistics and Data Sciences", + "STEV": "Studies in the Environment", + "STCY": "Study of the City", + "SUMR": "Summer Term", + "SWED": "Swedish", + "TAML": "Tamil", + "THST": "Theater and Performance Studies", + "TBTN": "Tibetan", + "PTB": "Translational Biomedicine", + "TKSH": "Turkish", + "TWI": "Twi", + "UKRN": "Ukrainian", + "URBN": "Urban Studies", + "VIET": "Vietnamese", + "VAIR": "Visiting Assistant in Research", + "WLOF": "Wolof", + "WGSS": "Women's, Gender & Sexuality Studies", + "YDSH": "Yiddish", + "YORU": "Yoruba", + "ZULU": "Zulu" +} \ No newline at end of file From a67ad8253389ad13cd982dbfda9f1f8ef8e23c4d Mon Sep 17 00:00:00 2001 From: alexj1701 Date: Mon, 19 Feb 2024 21:56:00 -0500 Subject: [PATCH 02/12] Function calling demo --- backend/functions.ipynb | 255 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 backend/functions.ipynb diff --git a/backend/functions.ipynb b/backend/functions.ipynb new file mode 100644 index 000000000..3169e42bc --- /dev/null +++ b/backend/functions.ipynb @@ -0,0 +1,255 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%pip install openai\n", + "%pip install python-dotenv\n", + "%pip install scipy\n", + "%pip install tenacity\n", + "%pip install tiktoken\n", + "%pip install termcolor " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import openai\n", + "import json\n", + "from dotenv import load_dotenv\n", + "load_dotenv()\n", + "from openai import OpenAI\n", + "openai.api_key = os.getenv(\"OPENAI_API_KEY\")\n", + "import json\n", + "from tenacity import retry, wait_random_exponential, stop_after_attempt\n", + "from termcolor import colored \n", + "from enum import Enum\n", + "\n", + "GPT_MODEL = \"gpt-3.5-turbo-0613\"\n", + "client = OpenAI()" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "@retry(wait=wait_random_exponential(multiplier=1, max=40), stop=stop_after_attempt(3))\n", + "def chat_completion_request(messages, tools=None, tool_choice=None, model=GPT_MODEL):\n", + " try:\n", + " response = client.chat.completions.create(\n", + " model=model,\n", + " messages=messages,\n", + " tools=tools,\n", + " tool_choice=tool_choice,\n", + " )\n", + " return response\n", + " except Exception as e:\n", + " print(\"Unable to generate ChatCompletion response\")\n", + " print(f\"Exception: {e}\")\n", + " return e\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "def pretty_print_conversation(messages):\n", + " role_to_color = {\n", + " \"system\": \"red\",\n", + " \"user\": \"green\",\n", + " \"assistant\": \"blue\",\n", + " \"function\": \"magenta\",\n", + " }\n", + " \n", + " for message in messages:\n", + " if message[\"role\"] == \"system\":\n", + " print(colored(f\"system: {message['content']}\\n\", role_to_color[message[\"role\"]]))\n", + " elif message[\"role\"] == \"user\":\n", + " print(colored(f\"user: {message['content']}\\n\", role_to_color[message[\"role\"]]))\n", + " elif message[\"role\"] == \"assistant\" and message.get(\"function_call\"):\n", + " print(colored(f\"assistant: {message['function_call']}\\n\", role_to_color[message[\"role\"]]))\n", + " elif message[\"role\"] == \"assistant\" and not message.get(\"function_call\"):\n", + " print(colored(f\"assistant: {message['content']}\\n\", role_to_color[message[\"role\"]]))\n", + " elif message[\"role\"] == \"function\":\n", + " print(colored(f\"function ({message['name']}): {message['content']}\\n\", role_to_color[message[\"role\"]]))" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "# --------------------------------------------------------------\n", + "# Use OpenAIโ€™s Function Calling Feature\n", + "# --------------------------------------------------------------\n", + "\n", + "# Open the JSON file\n", + "with open('course_subjects.json', 'r') as file:\n", + " # Load the JSON data into a Python list\n", + " subjects = json.load(file)\n", + " \n", + "tools = [\n", + " # {\n", + " # \"type\": \"function\",\n", + " # \"function\": {\n", + " # \"name\": \"filter_by_rating\",\n", + " # \"description\": \"Get a class by its rating (0 - 5). If a number is not provided, interpret their opinion to fit the range (0-5).\", \n", + " # \"parameters\": {\n", + " # \"type\": \"object\",\n", + " # \"properties\": {\n", + " # \"comparison_operator\": {\n", + " # \"type\": \"string\",\n", + " # \"enum\": [\"$lt\", \"$gt\", \"$gte\", \"$lte\"],\n", + " # \"description\": \"A comparison operator\",\n", + " # },\n", + " # \"rating\": {\n", + " # \"type\": \"number\",\n", + " # \"description\": \"The rating (a number) for the class\",\n", + " # },\n", + " # },\n", + " # \"required\": [\"comparison_operator\", \"rating\"],\n", + " # },\n", + " # }\n", + " # },\n", + " \n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"CourseFilter\",\n", + " \"description\": \"Provide filters for a course based on conditions.\", \n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"subject_code\": {\n", + " \"type\": \"string\",\n", + " \"enum\": [str(key) for key in subjects.keys()],\n", + " \"description\": \"A code for the subject of instruction\",\n", + " },\n", + " \"rating\": {\n", + " \"type\": \"number\",\n", + " \"description\": \"The rating (a number with one significant digit) for the class (0 - 4). If a number is not provided, interpret the given opinion to fit the range. A good, or average, class should be 3.5\",\n", + " },\n", + " \"comparison_operator_rating\": {\n", + " \"type\": \"string\",\n", + " \"enum\": [\"$lt\", \"$gt\", \"$gte\", \"$lte\"],\n", + " \"description\": \"A comparison operator for the class rating\",\n", + " },\n", + " \"workload\": {\n", + " \"type\": \"number\",\n", + " \"description\": \"The workload (a number with one significant digit) for the class (0 - 4). If a number is not provided, interpret the given opinion to fit the range.\",\n", + " },\n", + " \"comparison_operator_workload\": {\n", + " \"type\": \"string\",\n", + " \"enum\": [\"$lt\", \"$gt\", \"$gte\", \"$lte\"],\n", + " \"description\": \"A comparison operator for the class workload\",\n", + " },\n", + " \"comparison_operator_workload\": {\n", + " \"type\": \"string\",\n", + " \"enum\": [\"$lt\", \"$gt\", \"$gte\", \"$lte\"],\n", + " \"description\": \"A comparison operator for the class workload\",\n", + " },\n", + " \n", + " },\n", + " \"required\": [\"comparison_operator\", \"rating\"],\n", + " },\n", + " }\n", + " }\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Unable to generate ChatCompletion response\n", + "Exception: Error code: 400 - {'error': {'message': \"Invalid schema for function 'CourseFilter': 'ACCT,USAF,AFAM,AFST,AKKD,ASL,AMST,GREK,ANTH,AMTH,APHY,ARBC,ARCG,ARCH,ARMN,ART,ASTR,BNGL,B&BS,BIOL,BENG,BIS,BRST,BURM,C&MP,CBIO,CENG,CHEM,CHER,CHLD,CHNS,CDE,CLCV,CLSS,MEDR,CGSC,CSYC,CSBF,CSBK,CSBR,CSDC,CSES,CSGH,CSJE,CSMC,CSMY,CSPC,CSSY,CSSM,CSTD,CSTC,CB&B,CPLT,CPSC,CSEC,CPAR,MEDC,CZEC,DEVN,DRST,DIR,DISR,DRAM,DRMA,DUTC,EMST,EPS,EALL,EAST,E&EB,ECON,EDST,EGYP,EENG,ENRG,ENAS,ENGL,ELP,ENV,ENVE,EHS,EVST,EPH,EMD,EP&E,ER&M,E&RS,EXCH,EXPA,FILM,FNSH,F&ES,FREN,GENE,G&G,GMAN,GLBL,HPM,HLTH,HEBR,HNDI,HSHM,HIST,HSAR,HMRT,HUMS,HGRN,IBIO,IDRS,INDN,INP,IMED,ITAL,JAPN,JDST,KHMR,SWAH,KREN,LATN,LAST,LAW,LING,LITR,MGT,MGMT,MRES,MHHR,MATH,MENG,MDVL,MESO,MBIO,MGRK,MMES,MTBT,MB&B,MCDB,MUSI,NAVY,NELC,NPLI,NSCI,NURS,OTTM,PATH,PERS,PHAR,PHIL,OLPA,PA,PHYS,PLSH,PLSC,PORT,PRAC,CAND,QUAL,PSYC,PHUM,PNJB,REL,RLST,RNST,ROMN,RUSS,RSEE,SKRT,MD,MUS,SCIE,SMTC,SBCR,SNHL,SLAV,SBS,SOCY,SAST,SPAN,SPEC,STRT,S&DS,STEV,STCY,SUMR,SWED,TAML,THST,TBTN,PTB,TKSH,TWI,UKRN,URBN,VIET,VAIR,WLOF,WGSS,YDSH,YORU,ZULU' is not of type 'array'\", 'type': 'invalid_request_error', 'param': None, 'code': None}}\n" + ] + }, + { + "ename": "AttributeError", + "evalue": "'BadRequestError' object has no attribute 'choices'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[42], line 7\u001b[0m\n\u001b[1;32m 3\u001b[0m messages\u001b[39m.\u001b[39mappend({\u001b[39m\"\u001b[39m\u001b[39mrole\u001b[39m\u001b[39m\"\u001b[39m: \u001b[39m\"\u001b[39m\u001b[39muser\u001b[39m\u001b[39m\"\u001b[39m, \u001b[39m\"\u001b[39m\u001b[39mcontent\u001b[39m\u001b[39m\"\u001b[39m: \u001b[39m\"\u001b[39m\u001b[39mGive me a good and easy CS class\u001b[39m\u001b[39m\"\u001b[39m})\n\u001b[1;32m 4\u001b[0m chat_response \u001b[39m=\u001b[39m chat_completion_request(\n\u001b[1;32m 5\u001b[0m messages, tools\u001b[39m=\u001b[39mtools\n\u001b[1;32m 6\u001b[0m )\n\u001b[0;32m----> 7\u001b[0m assistant_message \u001b[39m=\u001b[39m chat_response\u001b[39m.\u001b[39;49mchoices[\u001b[39m0\u001b[39m]\u001b[39m.\u001b[39mmessage\n\u001b[1;32m 8\u001b[0m messages\u001b[39m.\u001b[39mappend(assistant_message)\n\u001b[1;32m 9\u001b[0m assistant_message\u001b[39m.\u001b[39mtool_calls[\u001b[39m0\u001b[39m]\u001b[39m.\u001b[39mfunction\u001b[39m.\u001b[39marguments\n", + "\u001b[0;31mAttributeError\u001b[0m: 'BadRequestError' object has no attribute 'choices'" + ] + } + ], + "source": [ + "messages = []\n", + "messages.append({\"role\": \"system\", \"content\": \"Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous.\"})\n", + "messages.append({\"role\": \"user\", \"content\": \"Give me a good and easy CS class\"})\n", + "chat_response = chat_completion_request(\n", + " messages, tools=tools\n", + ")\n", + "assistant_message = chat_response.choices[0].message\n", + "messages.append(assistant_message)\n", + "assistant_message.tool_calls[0].function.arguments\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"subject_code\": \"CPSC\",\n", + " \"rating\": 4,\n", + " \"comparison_operator_rating\": \"$gte\",\n", + " \"workload\": 2,\n", + " \"comparison_operator_workload\": \"$lte\"\n", + "}\n" + ] + } + ], + "source": [ + "print(assistant_message.tool_calls[0].function.arguments)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.2" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} From de5cb9bfb3bd5d9f0cd0fe91bf236a09e0f2d3fa Mon Sep 17 00:00:00 2001 From: Alex Johnson <71511357+alexj1701@users.noreply.github.com> Date: Mon, 19 Feb 2024 22:09:02 -0500 Subject: [PATCH 03/12] Delete backend/functions.ipynb --- backend/functions.ipynb | 255 ---------------------------------------- 1 file changed, 255 deletions(-) delete mode 100644 backend/functions.ipynb diff --git a/backend/functions.ipynb b/backend/functions.ipynb deleted file mode 100644 index 3169e42bc..000000000 --- a/backend/functions.ipynb +++ /dev/null @@ -1,255 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%pip install openai\n", - "%pip install python-dotenv\n", - "%pip install scipy\n", - "%pip install tenacity\n", - "%pip install tiktoken\n", - "%pip install termcolor " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "import openai\n", - "import json\n", - "from dotenv import load_dotenv\n", - "load_dotenv()\n", - "from openai import OpenAI\n", - "openai.api_key = os.getenv(\"OPENAI_API_KEY\")\n", - "import json\n", - "from tenacity import retry, wait_random_exponential, stop_after_attempt\n", - "from termcolor import colored \n", - "from enum import Enum\n", - "\n", - "GPT_MODEL = \"gpt-3.5-turbo-0613\"\n", - "client = OpenAI()" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "@retry(wait=wait_random_exponential(multiplier=1, max=40), stop=stop_after_attempt(3))\n", - "def chat_completion_request(messages, tools=None, tool_choice=None, model=GPT_MODEL):\n", - " try:\n", - " response = client.chat.completions.create(\n", - " model=model,\n", - " messages=messages,\n", - " tools=tools,\n", - " tool_choice=tool_choice,\n", - " )\n", - " return response\n", - " except Exception as e:\n", - " print(\"Unable to generate ChatCompletion response\")\n", - " print(f\"Exception: {e}\")\n", - " return e\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "def pretty_print_conversation(messages):\n", - " role_to_color = {\n", - " \"system\": \"red\",\n", - " \"user\": \"green\",\n", - " \"assistant\": \"blue\",\n", - " \"function\": \"magenta\",\n", - " }\n", - " \n", - " for message in messages:\n", - " if message[\"role\"] == \"system\":\n", - " print(colored(f\"system: {message['content']}\\n\", role_to_color[message[\"role\"]]))\n", - " elif message[\"role\"] == \"user\":\n", - " print(colored(f\"user: {message['content']}\\n\", role_to_color[message[\"role\"]]))\n", - " elif message[\"role\"] == \"assistant\" and message.get(\"function_call\"):\n", - " print(colored(f\"assistant: {message['function_call']}\\n\", role_to_color[message[\"role\"]]))\n", - " elif message[\"role\"] == \"assistant\" and not message.get(\"function_call\"):\n", - " print(colored(f\"assistant: {message['content']}\\n\", role_to_color[message[\"role\"]]))\n", - " elif message[\"role\"] == \"function\":\n", - " print(colored(f\"function ({message['name']}): {message['content']}\\n\", role_to_color[message[\"role\"]]))" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [], - "source": [ - "# --------------------------------------------------------------\n", - "# Use OpenAIโ€™s Function Calling Feature\n", - "# --------------------------------------------------------------\n", - "\n", - "# Open the JSON file\n", - "with open('course_subjects.json', 'r') as file:\n", - " # Load the JSON data into a Python list\n", - " subjects = json.load(file)\n", - " \n", - "tools = [\n", - " # {\n", - " # \"type\": \"function\",\n", - " # \"function\": {\n", - " # \"name\": \"filter_by_rating\",\n", - " # \"description\": \"Get a class by its rating (0 - 5). If a number is not provided, interpret their opinion to fit the range (0-5).\", \n", - " # \"parameters\": {\n", - " # \"type\": \"object\",\n", - " # \"properties\": {\n", - " # \"comparison_operator\": {\n", - " # \"type\": \"string\",\n", - " # \"enum\": [\"$lt\", \"$gt\", \"$gte\", \"$lte\"],\n", - " # \"description\": \"A comparison operator\",\n", - " # },\n", - " # \"rating\": {\n", - " # \"type\": \"number\",\n", - " # \"description\": \"The rating (a number) for the class\",\n", - " # },\n", - " # },\n", - " # \"required\": [\"comparison_operator\", \"rating\"],\n", - " # },\n", - " # }\n", - " # },\n", - " \n", - " {\n", - " \"type\": \"function\",\n", - " \"function\": {\n", - " \"name\": \"CourseFilter\",\n", - " \"description\": \"Provide filters for a course based on conditions.\", \n", - " \"parameters\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"subject_code\": {\n", - " \"type\": \"string\",\n", - " \"enum\": [str(key) for key in subjects.keys()],\n", - " \"description\": \"A code for the subject of instruction\",\n", - " },\n", - " \"rating\": {\n", - " \"type\": \"number\",\n", - " \"description\": \"The rating (a number with one significant digit) for the class (0 - 4). If a number is not provided, interpret the given opinion to fit the range. A good, or average, class should be 3.5\",\n", - " },\n", - " \"comparison_operator_rating\": {\n", - " \"type\": \"string\",\n", - " \"enum\": [\"$lt\", \"$gt\", \"$gte\", \"$lte\"],\n", - " \"description\": \"A comparison operator for the class rating\",\n", - " },\n", - " \"workload\": {\n", - " \"type\": \"number\",\n", - " \"description\": \"The workload (a number with one significant digit) for the class (0 - 4). If a number is not provided, interpret the given opinion to fit the range.\",\n", - " },\n", - " \"comparison_operator_workload\": {\n", - " \"type\": \"string\",\n", - " \"enum\": [\"$lt\", \"$gt\", \"$gte\", \"$lte\"],\n", - " \"description\": \"A comparison operator for the class workload\",\n", - " },\n", - " \"comparison_operator_workload\": {\n", - " \"type\": \"string\",\n", - " \"enum\": [\"$lt\", \"$gt\", \"$gte\", \"$lte\"],\n", - " \"description\": \"A comparison operator for the class workload\",\n", - " },\n", - " \n", - " },\n", - " \"required\": [\"comparison_operator\", \"rating\"],\n", - " },\n", - " }\n", - " }\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Unable to generate ChatCompletion response\n", - "Exception: Error code: 400 - {'error': {'message': \"Invalid schema for function 'CourseFilter': 'ACCT,USAF,AFAM,AFST,AKKD,ASL,AMST,GREK,ANTH,AMTH,APHY,ARBC,ARCG,ARCH,ARMN,ART,ASTR,BNGL,B&BS,BIOL,BENG,BIS,BRST,BURM,C&MP,CBIO,CENG,CHEM,CHER,CHLD,CHNS,CDE,CLCV,CLSS,MEDR,CGSC,CSYC,CSBF,CSBK,CSBR,CSDC,CSES,CSGH,CSJE,CSMC,CSMY,CSPC,CSSY,CSSM,CSTD,CSTC,CB&B,CPLT,CPSC,CSEC,CPAR,MEDC,CZEC,DEVN,DRST,DIR,DISR,DRAM,DRMA,DUTC,EMST,EPS,EALL,EAST,E&EB,ECON,EDST,EGYP,EENG,ENRG,ENAS,ENGL,ELP,ENV,ENVE,EHS,EVST,EPH,EMD,EP&E,ER&M,E&RS,EXCH,EXPA,FILM,FNSH,F&ES,FREN,GENE,G&G,GMAN,GLBL,HPM,HLTH,HEBR,HNDI,HSHM,HIST,HSAR,HMRT,HUMS,HGRN,IBIO,IDRS,INDN,INP,IMED,ITAL,JAPN,JDST,KHMR,SWAH,KREN,LATN,LAST,LAW,LING,LITR,MGT,MGMT,MRES,MHHR,MATH,MENG,MDVL,MESO,MBIO,MGRK,MMES,MTBT,MB&B,MCDB,MUSI,NAVY,NELC,NPLI,NSCI,NURS,OTTM,PATH,PERS,PHAR,PHIL,OLPA,PA,PHYS,PLSH,PLSC,PORT,PRAC,CAND,QUAL,PSYC,PHUM,PNJB,REL,RLST,RNST,ROMN,RUSS,RSEE,SKRT,MD,MUS,SCIE,SMTC,SBCR,SNHL,SLAV,SBS,SOCY,SAST,SPAN,SPEC,STRT,S&DS,STEV,STCY,SUMR,SWED,TAML,THST,TBTN,PTB,TKSH,TWI,UKRN,URBN,VIET,VAIR,WLOF,WGSS,YDSH,YORU,ZULU' is not of type 'array'\", 'type': 'invalid_request_error', 'param': None, 'code': None}}\n" - ] - }, - { - "ename": "AttributeError", - "evalue": "'BadRequestError' object has no attribute 'choices'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[42], line 7\u001b[0m\n\u001b[1;32m 3\u001b[0m messages\u001b[39m.\u001b[39mappend({\u001b[39m\"\u001b[39m\u001b[39mrole\u001b[39m\u001b[39m\"\u001b[39m: \u001b[39m\"\u001b[39m\u001b[39muser\u001b[39m\u001b[39m\"\u001b[39m, \u001b[39m\"\u001b[39m\u001b[39mcontent\u001b[39m\u001b[39m\"\u001b[39m: \u001b[39m\"\u001b[39m\u001b[39mGive me a good and easy CS class\u001b[39m\u001b[39m\"\u001b[39m})\n\u001b[1;32m 4\u001b[0m chat_response \u001b[39m=\u001b[39m chat_completion_request(\n\u001b[1;32m 5\u001b[0m messages, tools\u001b[39m=\u001b[39mtools\n\u001b[1;32m 6\u001b[0m )\n\u001b[0;32m----> 7\u001b[0m assistant_message \u001b[39m=\u001b[39m chat_response\u001b[39m.\u001b[39;49mchoices[\u001b[39m0\u001b[39m]\u001b[39m.\u001b[39mmessage\n\u001b[1;32m 8\u001b[0m messages\u001b[39m.\u001b[39mappend(assistant_message)\n\u001b[1;32m 9\u001b[0m assistant_message\u001b[39m.\u001b[39mtool_calls[\u001b[39m0\u001b[39m]\u001b[39m.\u001b[39mfunction\u001b[39m.\u001b[39marguments\n", - "\u001b[0;31mAttributeError\u001b[0m: 'BadRequestError' object has no attribute 'choices'" - ] - } - ], - "source": [ - "messages = []\n", - "messages.append({\"role\": \"system\", \"content\": \"Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous.\"})\n", - "messages.append({\"role\": \"user\", \"content\": \"Give me a good and easy CS class\"})\n", - "chat_response = chat_completion_request(\n", - " messages, tools=tools\n", - ")\n", - "assistant_message = chat_response.choices[0].message\n", - "messages.append(assistant_message)\n", - "assistant_message.tool_calls[0].function.arguments\n" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"subject_code\": \"CPSC\",\n", - " \"rating\": 4,\n", - " \"comparison_operator_rating\": \"$gte\",\n", - " \"workload\": 2,\n", - " \"comparison_operator_workload\": \"$lte\"\n", - "}\n" - ] - } - ], - "source": [ - "print(assistant_message.tool_calls[0].function.arguments)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.2" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} From 86a754b71f36ac8cfa410492c19b2ee6e5cf55a6 Mon Sep 17 00:00:00 2001 From: plin <116143761+plin349@users.noreply.github.com> Date: Mon, 19 Feb 2024 22:11:57 -0500 Subject: [PATCH 04/12] flask backend --- backend/app.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 backend/app.py diff --git a/backend/app.py b/backend/app.py new file mode 100644 index 000000000..c53a4268b --- /dev/null +++ b/backend/app.py @@ -0,0 +1,46 @@ +from flask import Flask, request, jsonify +import os +from dotenv import load_dotenv +from lib import chat_completion_request + +from pymongo.mongo_client import MongoClient + +uri = "mongodb+srv://dbUser:@cluster0.blvdnja.mongodb.net/?retryWrites=true&w=majority" + +# connect to the MongoDB cluster +client = MongoClient(uri) +try: + client.admin.command('ping') + print("Pinged your deployment. You successfully connected to MongoDB!") +except Exception as e: + print(e) + +app = Flask(__name__) + +load_dotenv() + +@app.route('/chat', methods=['POST']) +def chat(): + data = request.get_json() + if 'message' not in data: + return jsonify({"error": "Missing 'messages' in request body"}), 400 + user_messages = data['message'] + response = chat_completion_request(messages=user_messages) + message = response.choices[0].message + if message.tool_calls is not None: + json_response = message.tool_calls[0].function.arguments + + + # ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_Ub07GeA6kaC2OZ8b8KlVmtZz', function=Function(arguments='{\n "subject_code": "CPSC",\n "rating": 3.5,\n "comparison_operator_rating": "$gte",\n "workload": 1,\n "comparison_operator_workload": "$lte"\n}', name='CourseFilter'), type='function')]) + + json_response = { + 'message': [{ + 'role': response.choices[0].message.role, + 'content': response.choices[0].message.content, + }] + } + + return jsonify(json_response) + +if __name__ == '__main__': + app.run(debug=True) From 3eef5351f9af60ba23f7e1b7913680342624d773 Mon Sep 17 00:00:00 2001 From: plin <116143761+plin349@users.noreply.github.com> Date: Mon, 19 Feb 2024 22:13:13 -0500 Subject: [PATCH 05/12] Create lib.py --- backend/lib.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 backend/lib.py diff --git a/backend/lib.py b/backend/lib.py new file mode 100644 index 000000000..337034810 --- /dev/null +++ b/backend/lib.py @@ -0,0 +1,45 @@ +from tenacity import retry, wait_random_exponential, stop_after_attempt +import os +from openai import OpenAI + +tools = [ + { + "type": "function", + "function": { + "name": "filter_classes_by_rating", + "description": "", + "parameters": { + "type": "object", + "properties": { + "operator": { + "type": "string", + "enum": ["$gt", "$lt", '$gte', '$lte', '$eq'], + "description": "The operator to use for the filter", + }, + "rating": { + "type": "number", + "description": "The rating to filter by", + }, + }, + "required": ["operator", "rating"], + }, + } + }, +] + +client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) + +@retry(wait=wait_random_exponential(multiplier=1, max=40), stop=stop_after_attempt(3)) +def chat_completion_request(messages, tools=tools, tool_choice=None, model='gpt-3.5-turbo'): + try: + response = client.chat.completions.create( + model=model, + messages=messages, + tools=tools, + tool_choice=tool_choice, + ) + return response + except Exception as e: + print("Unable to generate ChatCompletion response") + print(f"Exception: {e}") + return e From 2e6ba27f83af88684e66045931b76038e682d75a Mon Sep 17 00:00:00 2001 From: alexj1701 Date: Mon, 19 Feb 2024 22:20:22 -0500 Subject: [PATCH 06/12] "everything bagel" function with json retreival --- backend/lib.py | 58 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/backend/lib.py b/backend/lib.py index 337034810..f9d5d4eea 100644 --- a/backend/lib.py +++ b/backend/lib.py @@ -1,30 +1,56 @@ from tenacity import retry, wait_random_exponential, stop_after_attempt import os from openai import OpenAI +import json + +# Open the JSON file +with open('course_subjects.json', 'r') as file: + # Load the JSON data into a Python list + subjects = json.load(file) tools = [ { "type": "function", "function": { - "name": "filter_classes_by_rating", - "description": "", - "parameters": { - "type": "object", - "properties": { - "operator": { - "type": "string", - "enum": ["$gt", "$lt", '$gte', '$lte', '$eq'], - "description": "The operator to use for the filter", - }, - "rating": { - "type": "number", - "description": "The rating to filter by", - }, + "name": "CourseFilter", + "description": "Provide filters for a course based on conditions.", + "parameters": { + "type": "object", + "properties": { + "subject_code": { + "type": "string", + "enum": [str(key) for key in subjects.keys()], + "description": "A code for the subject of instruction", + }, + "rating": { + "type": "number", + "description": "The rating (a number with one significant digit) for the class (0 - 4). If a number is not provided, interpret the given opinion to fit the range. A good, or average, class should be 3.5", + }, + "comparison_operator_rating": { + "type": "string", + "enum": ["$lt", "$gt", "$gte", "$lte"], + "description": "A comparison operator for the class rating", + }, + "workload": { + "type": "number", + "description": "The workload (a number with one significant digit) for the class (0 - 4). If a number is not provided, interpret the given opinion to fit the range.", + }, + "comparison_operator_workload": { + "type": "string", + "enum": ["$lt", "$gt", "$gte", "$lte"], + "description": "A comparison operator for the class workload", + }, + "comparison_operator_workload": { + "type": "string", + "enum": ["$lt", "$gt", "$gte", "$lte"], + "description": "A comparison operator for the class workload", }, - "required": ["operator", "rating"], + }, + "required": ["comparison_operator_rating", "rating"], + }, } - }, + } ] client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) From 0ce0bc1a7e79edd104d90504f759d756aaaa5264 Mon Sep 17 00:00:00 2001 From: plin <116143761+plin349@users.noreply.github.com> Date: Mon, 19 Feb 2024 23:54:37 -0500 Subject: [PATCH 07/12] mongo db vector search --- backend/app.py | 72 +++++++++++++++++++++++++++++++++++++++------ backend/lib.py | 79 ++++++++++++++++++++++---------------------------- 2 files changed, 97 insertions(+), 54 deletions(-) diff --git a/backend/app.py b/backend/app.py index c53a4268b..4625fafa6 100644 --- a/backend/app.py +++ b/backend/app.py @@ -1,14 +1,18 @@ from flask import Flask, request, jsonify import os from dotenv import load_dotenv -from lib import chat_completion_request +from lib import chat_completion_request, create_embedding +import json from pymongo.mongo_client import MongoClient -uri = "mongodb+srv://dbUser:@cluster0.blvdnja.mongodb.net/?retryWrites=true&w=majority" +uri = "mongodb+srv://dbUser:@cluster0.blvdnja.mongodb.net/?retryWrites=true&w=majority" # connect to the MongoDB cluster client = MongoClient(uri) +db = client['bluebookai'] +collection = db['course-info'] + try: client.admin.command('ping') print("Pinged your deployment. You successfully connected to MongoDB!") @@ -24,20 +28,70 @@ def chat(): data = request.get_json() if 'message' not in data: return jsonify({"error": "Missing 'messages' in request body"}), 400 + user_messages = data['message'] response = chat_completion_request(messages=user_messages) message = response.choices[0].message - if message.tool_calls is not None: - json_response = message.tool_calls[0].function.arguments - + print(message) + # if message.tool_calls is None: + # return 'success' + # args = json.loads(message.tool_calls[0].function.arguments) + # query_vector = create_embedding(user_messages[-1]['content']) + # database_response = collection.aggregate([ + # { + # '$vectorSearch': { + # 'index': 'course-rating-index', + # 'path': 'embedding', + # 'filter': { + # 'rating': { + # args['operator']: args['rating'] + # } + # }, + # 'queryVector': query_vector, + # 'numCandidates': 5, + # 'limit': 5 + # } + # } + # ]) + # # print(database_response) + + # top_class = list(database_response)[0] + # json_response = { + # 'title': top_class['title'], + # 'rating': top_class['rating'], + # } + # return jsonify(json_response) + + # "{\"operator\":\"$gt\",\"rating\":4}" # ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_Ub07GeA6kaC2OZ8b8KlVmtZz', function=Function(arguments='{\n "subject_code": "CPSC",\n "rating": 3.5,\n "comparison_operator_rating": "$gte",\n "workload": 1,\n "comparison_operator_workload": "$lte"\n}', name='CourseFilter'), type='function')]) + query_vector = create_embedding(user_messages[-1]['content']) + + print(user_messages[-1]) + database_response = collection.aggregate([ + { + '$vectorSearch': { + 'index': 'course-rating-index', + 'path': 'embedding', + 'queryVector': query_vector, + 'numCandidates': 5, + 'limit': 5 + } + } + ]) + + classes = list(database_response) + # top_class = classes[0] + print([c['title'] for c in classes]) + top_class = classes[0] json_response = { - 'message': [{ - 'role': response.choices[0].message.role, - 'content': response.choices[0].message.content, - }] + # 'message': [{ + # 'role': response.choices[0].message.role, + # 'content': response.choices[0].message.content, + # }] + 'title': top_class['title'], + # 'rating': top_class['rating'], } return jsonify(json_response) diff --git a/backend/lib.py b/backend/lib.py index f9d5d4eea..b6b5bf344 100644 --- a/backend/lib.py +++ b/backend/lib.py @@ -1,62 +1,50 @@ from tenacity import retry, wait_random_exponential, stop_after_attempt import os from openai import OpenAI -import json -# Open the JSON file -with open('course_subjects.json', 'r') as file: - # Load the JSON data into a Python list - subjects = json.load(file) - -tools = [ +_tools = [ { "type": "function", "function": { - "name": "CourseFilter", - "description": "Provide filters for a course based on conditions.", - "parameters": { - "type": "object", - "properties": { - "subject_code": { - "type": "string", - "enum": [str(key) for key in subjects.keys()], - "description": "A code for the subject of instruction", - }, - "rating": { - "type": "number", - "description": "The rating (a number with one significant digit) for the class (0 - 4). If a number is not provided, interpret the given opinion to fit the range. A good, or average, class should be 3.5", - }, - "comparison_operator_rating": { - "type": "string", - "enum": ["$lt", "$gt", "$gte", "$lte"], - "description": "A comparison operator for the class rating", - }, - "workload": { - "type": "number", - "description": "The workload (a number with one significant digit) for the class (0 - 4). If a number is not provided, interpret the given opinion to fit the range.", + "name": "filter_classes_by_rating", + "description": "", + "parameters": { + "type": "object", + "properties": { + "operator": { + "type": "string", + "enum": ["$gt", "$lt", '$gte', '$lte', '$eq'], + "description": "The operator to use for the filter", + }, + "rating": { + "type": "number", + "description": "The rating to filter by", + }, }, - "comparison_operator_workload": { - "type": "string", - "enum": ["$lt", "$gt", "$gte", "$lte"], - "description": "A comparison operator for the class workload", - }, - "comparison_operator_workload": { - "type": "string", - "enum": ["$lt", "$gt", "$gte", "$lte"], - "description": "A comparison operator for the class workload", - }, - + "required": ["operator", "rating"], }, - "required": ["comparison_operator_rating", "rating"], - }, } - } + }, ] -client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) +# client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) +client = OpenAI(api_key="") + +@retry(wait=wait_random_exponential(multiplier=1, max=40), stop=stop_after_attempt(3)) +def create_embedding(text, model='text-embedding-3-small'): + try: + response = client.embeddings.create( + input=text, + model="text-embedding-3-small" + ) + return response.data[0].embedding + except Exception as e: + print("Unable to generate embedding") + print(f"Exception: {e}") + return e @retry(wait=wait_random_exponential(multiplier=1, max=40), stop=stop_after_attempt(3)) -def chat_completion_request(messages, tools=tools, tool_choice=None, model='gpt-3.5-turbo'): +def chat_completion_request(messages, tools=None, tool_choice=None, model='gpt-3.5-turbo'): try: response = client.chat.completions.create( model=model, @@ -69,3 +57,4 @@ def chat_completion_request(messages, tools=tools, tool_choice=None, model='gpt- print("Unable to generate ChatCompletion response") print(f"Exception: {e}") return e + From f7b991577e346e08ede0d8a2accbaaa6a4b440ad Mon Sep 17 00:00:00 2001 From: Buwei Chen <59496117+BuweiChen@users.noreply.github.com> Date: Sun, 25 Feb 2024 16:24:20 -0500 Subject: [PATCH 08/12] Add testing demo --- .github/workflows/github-actions-demo.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/github-actions-demo.yml diff --git a/.github/workflows/github-actions-demo.yml b/.github/workflows/github-actions-demo.yml new file mode 100644 index 000000000..e5bb16153 --- /dev/null +++ b/.github/workflows/github-actions-demo.yml @@ -0,0 +1,18 @@ +name: GitHub Actions Demo +run-name: ${{ github.actor }} is testing out GitHub Actions ๐Ÿš€ +on: [push] +jobs: + Explore-GitHub-Actions: + runs-on: ubuntu-latest + steps: + - run: echo "๐ŸŽ‰ The job was automatically triggered by a ${{ github.event_name }} event." + - run: echo "๐Ÿง This job is now running on a ${{ runner.os }} server hosted by GitHub!" + - run: echo "๐Ÿ”Ž The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}." + - name: Check out repository code + uses: actions/checkout@v4 + - run: echo "๐Ÿ’ก The ${{ github.repository }} repository has been cloned to the runner." + - run: echo "๐Ÿ–ฅ๏ธ The workflow is now ready to test your code on the runner." + - name: List files in the repository + run: | + ls ${{ github.workspace }} + - run: echo "๐Ÿ This job's status is ${{ job.status }}." \ No newline at end of file From 656db7e3e7a77be04562c14b0060cab8e991c951 Mon Sep 17 00:00:00 2001 From: Buwei Chen <59496117+BuweiChen@users.noreply.github.com> Date: Sun, 25 Feb 2024 16:49:05 -0500 Subject: [PATCH 09/12] Update MongoDB key [internal: see notion page] --- backend/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/app.py b/backend/app.py index 4625fafa6..0f1548ed9 100644 --- a/backend/app.py +++ b/backend/app.py @@ -6,7 +6,7 @@ from pymongo.mongo_client import MongoClient -uri = "mongodb+srv://dbUser:@cluster0.blvdnja.mongodb.net/?retryWrites=true&w=majority" +uri = "mongodb+srv://bluebookairoot:@bluebookcluster.0hf4pzi.mongodb.net/?retryWrites=true&w=majority&appName=BluebookCluster" # connect to the MongoDB cluster client = MongoClient(uri) From 036b10faef4d0a19aa567ea1387f79f835c62b4f Mon Sep 17 00:00:00 2001 From: alexj1701 Date: Wed, 28 Feb 2024 18:27:46 -0500 Subject: [PATCH 10/12] restored newest function --- backend/lib.py | 54 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/backend/lib.py b/backend/lib.py index b6b5bf344..cf76b6fbd 100644 --- a/backend/lib.py +++ b/backend/lib.py @@ -2,29 +2,49 @@ import os from openai import OpenAI -_tools = [ +tools = [ { "type": "function", "function": { - "name": "filter_classes_by_rating", - "description": "", - "parameters": { - "type": "object", - "properties": { - "operator": { - "type": "string", - "enum": ["$gt", "$lt", '$gte', '$lte', '$eq'], - "description": "The operator to use for the filter", - }, - "rating": { - "type": "number", - "description": "The rating to filter by", - }, + "name": "CourseFilter", + "description": "Provide filters for a course based on conditions.", + "parameters": { + "type": "object", + "properties": { + "subject_code": { + ~ "type": "string", + "enum": [str(key) for key in subjects.keys()], + "description": "A code for the subject of instruction", }, - "required": ["operator", "rating"], + "rating": { + "type": "number", + "description": "The rating (a number with one significant digit) for the class (0 - 4). If a number is not provided, interpret the given opinion to fit the range. A good, or average, class should be 3.5", + }, + "comparison_operator_rating": { + "type": "string", + "enum": ["$lt", "$gt", "$gte", "$lte"], + "description": "A comparison operator for the class rating", + }, + "workload": { + "type": "number", + "description": "The workload (a number with one significant digit) for the class (0 - 4). If a number is not provided, interpret the given opinion to fit the range.", + }, + "comparison_operator_workload": { + "type": "string", + "enum": ["$lt", "$gt", "$gte", "$lte"], + "description": "A comparison operator for the class workload", + }, + "comparison_operator_workload": { + "type": "string", + "enum": ["$lt", "$gt", "$gte", "$lte"], + "description": "A comparison operator for the class workload", + }, + }, + "required": ["comparison_operator_rating", "rating"], + }, } - }, + } ] # client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) From a2e3f57b78e3360bf3a3750a98d1764e7e721963 Mon Sep 17 00:00:00 2001 From: alexj1701 Date: Wed, 28 Feb 2024 18:29:55 -0500 Subject: [PATCH 11/12] added support for course json file --- backend/lib.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/lib.py b/backend/lib.py index cf76b6fbd..04fe1cbc8 100644 --- a/backend/lib.py +++ b/backend/lib.py @@ -1,6 +1,12 @@ from tenacity import retry, wait_random_exponential, stop_after_attempt import os from openai import OpenAI +import json + +# Open the JSON file +with open('course_subjects.json', 'r') as file: + # Load the JSON data into a Python list + subjects = json.load(file) tools = [ { From 7cd8c0de2b1abe1cdde8d75cd6037602bd88ee88 Mon Sep 17 00:00:00 2001 From: alexj1701 Date: Wed, 28 Feb 2024 18:32:08 -0500 Subject: [PATCH 12/12] removed duplicate code --- backend/lib.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/backend/lib.py b/backend/lib.py index 04fe1cbc8..7aa98e8d5 100644 --- a/backend/lib.py +++ b/backend/lib.py @@ -39,13 +39,7 @@ "type": "string", "enum": ["$lt", "$gt", "$gte", "$lte"], "description": "A comparison operator for the class workload", - }, - "comparison_operator_workload": { - "type": "string", - "enum": ["$lt", "$gt", "$gte", "$lte"], - "description": "A comparison operator for the class workload", - }, - + }, }, "required": ["comparison_operator_rating", "rating"], },