diff --git a/.gitignore b/.gitignore index e82cb08..ad1e690 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ backend/schedules schedules .env *.tar +**/venv/ ## Begin autogenerated .gradle diff --git a/backend/docs/README.md b/backend/docs/README.md index d997a2c..6c4b7f6 100644 --- a/backend/docs/README.md +++ b/backend/docs/README.md @@ -30,6 +30,10 @@ To install the latest stable version of Vite, run ```npm install -D vite```. A java JDK installation of version at least 21 is required to build and run this project. You can install one with ```winget install EclipseAdoptium.Temurin.21.JDK```. +### Python +A python version of 3.10 or higher is required to run this project. + + ## Running Currently, we do not have a prebuilt executable. You can run the project by executing the `run` gradle task. @@ -37,7 +41,12 @@ There are two ways to do this: 1. Change directories to the backend folder and run `./gradlew run` 2. Open the project in IntelliJ and execute the `application/run` gradle task from the right hand menu. -3. Navigate to `http://localhost:7070`. +3. From a terminal inside the python-backend folder, run `python -m venv venv` to create the virtual environment. +4. Activate the Venv by running `venv\Scripts\activate` if using Windows, or `source venv/bin/activate` for Mac/Linux. +5. Run `pip install -r requirements.txt` to download the python backend dependencies. +6. Run `uvicorn main:app --reload` to start the application. +7. Navigate to `http://localhost:7070`. + ## OCI Containers If you have Docker or Podman installed you can create an OCI container image .tar by running `./gradlew containerBuild` in the backend folder diff --git a/frontend/src/SearchPage.tsx b/frontend/src/SearchPage.tsx index da3394e..90a74fb 100644 --- a/frontend/src/SearchPage.tsx +++ b/frontend/src/SearchPage.tsx @@ -2,6 +2,7 @@ import { Toaster, toast } from "react-hot-toast"; import { useEffect, useState, useRef } from 'react'; + interface CourseTime { day: string; start_time: string; @@ -39,6 +40,10 @@ export default function SearchPage() { const [availableTimes, setAvailableTimes] = useState([]); const didMount = useRef(false); const isClearing = useRef(false); + const [text, setText] = useState(""); //for the chatbot query + const [result, setResult] = useState("Ask a question about your major's required classes!"); // the api call result + const [isOpen, setIsOpen] = useState(false); // for the modal + const [chatbotDept, setCbDept] = useState("Comp"); const getCourseId = (course: Course) => `${course.subject}${course.number}${course.section}${course.semester}`; // @@ -313,9 +318,46 @@ export default function SearchPage() { (_, i) => windowStart + i ); +//Chatbot query box +async function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + + if(text != ""){ + const response = await fetch("http://127.0.0.1:8000/query", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + text, + chatbotDept + }), + }); + + const data = await response.json(); + setResult(data.result); + } +} + +//modal styling +const modalStyle: React.CSSProperties = { + position: "fixed", + top: "0", + right: "0", + height: "100vh", + width: "350px", + background: "white", + padding: "20px", + boxShadow: "-2px 0 10px rgba(0,0,0,0.2)", + zIndex: 1000, + overflowY: "auto", +}; + + return (
+ {/* LEFT SIDEBAR */}

Filters

@@ -391,6 +433,7 @@ export default function SearchPage() { value={query} onChange={e => setQuery(e.target.value)} onKeyDown={e => e.key === 'Enter' && search()} + maxLength={1200} />
@@ -528,6 +571,65 @@ export default function SearchPage() { )}
+ {/*Floating Chatbot Button*/} + + {isOpen && ( +
+ + + {/* Close button */} + + + {/* Content layout */} +
+ + + + {/* Left: textbox */} +
+ setText(e.target.value)} + placeholder="Type..." + maxLength={1200} + /> + +
+ + + {/* scrollable content */} +
+

{result}

+
+ + + + +
+
+ + )} ); } diff --git a/python-backend/Comp.txt b/python-backend/Comp.txt new file mode 100644 index 0000000..368b3fb --- /dev/null +++ b/python-backend/Comp.txt @@ -0,0 +1,68 @@ +Computer Science B.S. suggested four year plan: +Freshman Year: +Fall: + {"department": "COMP", "number": "141", "name": "Computer Programming I", "credits": 3}, + {"department": "COMP", "number": "155", "name": "Introduction to Computer Science", "credits": 3}, + {"department": "MATH", "number": "161", "name": "Calculus I", "credits": 4}, + one science elective (each are four credits, either PHYS 101; PHYS 102; CHEM 105 or both CHEM 111 and 113; CHEM + 112 and 114; BIOL 101; or BIOL 102), + {"department": "HUMA", "number": "102", "name": "Civ and the Biblical Revelation", "credits": 3}, + +Spring: + {"department": "COMP", "number": "220", "name": "Computer Programming II", "credits": 3}, + {"department": "MATH", "number": "162", "name": "Calculus II", "credits": 4}, + one science elective (from previous list) + {"department": "WRIT", "number": "101", "name": "Foundations of Academic Discourse", "credits": 3}, + {"department": "PHYE", "number": "100", "name": "Healthful Living", "credits": 1}, + + +Sophomore year: +Fall: + {"department": "COMP", "number": "222", "name": "Introduction to Data Structures & Algorithms", "credits": 3}, + {"department": "COMP", "number": "244", "name": "Database Management", "credits": 3}, + {"department": "MATH", "number": "213", "name": "Discrete Mathematics for Comp. Science", "credits": 4}, + {"department": "HUMA", "number": "200", "name": "Western Civilization", "credits": 3}, + Foundations of social science course (3 credits, either ECON 120 Foundations of Economics, PSYC 101 Foundations of Psychology, HIST 120 Foundations of History, PSYC 200 Cross-Cultural Psychology, HIST 141 World Geography, SOCI 101 Foundations of Sociology, HIST 204 Hist/Phil Foundations of Education, SOCI 103 Found. of Cultural Anthr., POLS 101 Foundations of Political Science, or SOCW 101 Found. of Social Work) + one credit of a general elective (any non-CS class) + +Spring: + {"department": "COMP", "number": "205", "name": "Ethics, Faith, and the Conscious Mind", "credits": 3}, + {"department": "COMP", "number": "233", "name": "Parallel Computing", "credits": 3}, + {"department": "COMP", "number": "342", "name": "Data Communication & Networking", "credits": 3}, + {"department": "MATH", "number": "214", "name": "Applied Probability & Linear Algebra", "credits": 4}, + {"department": "HUMA", "number": "202", "name": "Civilization and Literature", "credits": 3}, + + + +Junior Year: +Fall: + {"department": "COMP", "number": "325", "name": "Computer Architecture & Organization", "credits": 3}, + {"department": "COMP", "number": "422", "name": "Introduction to Algorithms", "credits": 3}, + two three-credit computer science electives (from COMP 390 Topics in Computer Science, COMP 401 Principles of iOS Programming, COMP 402 + 3 Principles of Android Programming, COMP 435 Intro to Machine Learning, COMP 441 2D Game + Design/Development, COMP 442 Web Programming Technologies, COMP 445 Intro to Artificial Intelligence, COMP 446 3D Game Design/Development, COMP 447 Networked Game Design and Development, COMP 475 Advanced Security, DSCI 431 Intro to Big Data , DSCI 450 Applied + Modeling and Visualization, or ROBO 302 Mobile Robotics.) + {"department": "HUMA", "number": "301", "name": "Civilization and the Arts", "credits": 3}, + two general elective credits + +Spring: + {"department": "COMP", "number": "314", "name": "Automata Theory", "credits": 3}, + {"department": "COMP", "number": "340", "name": "Operating Systems", "credits": 3}, + {"department": "COMP", "number": "350", "name": "Software Engineering", "credits": 3}, + one three-credit computer science elective (from the list above) + four credits of general electives + + +Senior Year: +Fall: + {"department": "COMP", "number": "448", "name": "Computer Security", "credits": 3}, + {"department": "COMP", "number": "451", "name": "Senior Project I", "credits": 2}, + three credits of a computer science elective + {"department": "HUMA", "number": "303", "name": "Christianity and Civilization", "credits": 3} + four credits of general electives + +Spring: + {"department": "COMP", "number": "443", "name": "Programming Languages", "credits": 3}, + {"department": "COMP", "number": "452", "name": "Senior Project II", "credits": 3}, + one three-credit computer science elective + six credits of general electives diff --git a/python-backend/Engl.txt b/python-backend/Engl.txt new file mode 100644 index 0000000..2cbf9d7 --- /dev/null +++ b/python-backend/Engl.txt @@ -0,0 +1,75 @@ +English B.A. Suggested Four Year Plan + +Freshman Year: +Fall: +{"department": "ENGL", "number": "201", "name": "English Literature I", "credits": 3}, +ENGL Elective (3 credits, from list below), +{"department": "HUMA", "number": "102", "name": "Civ and the Biblical Revelation", "credits": 3}, +Foundations of Social Science course (3 credits, either ECON 120 Foundations of Economics, PSYC 101 Foundations of Psychology, HIST 120 Foundations of History, PSYC 200 Cross-Cultural Psychology, HIST 141 World Geography, SOCI 101 Foundations of Sociology, HIST 204 Hist/Phil Foundations of Education, SOCI 103 Found. of Cultural Anthr., POLS 101 Foundations of Political Science, or SOCW 101 Found. of Social Work), +Foreign Language or General Elective (3 credits) + +Spring: +{"department": "ENGL", "number": "202", "name": "English Literature II", "credits": 3}, +{"department": "WRIT", "number": "101", "name": "Foundations of Academic Discourse", "credits": 3}, +Quantitative/Logical Reasoning course (3 credits), +{"department": "PHYE", "number": "100", "name": "Healthful Living", "credits": 1}, +Foreign Language or General Elective (3 credits), +General Elective (3 credits) + +Sophomore Year: +Fall: +{"department": "ENGL", "number": "203", "name": "American Literature I", "credits": 3}, +ENGL 205, ENGL 250, or ENGL Elective (3 credits), +{"department": "HUMA", "number": "200", "name": "Western Civilization", "credits": 3}, +Natural Science with Lab (4 credits), +Foreign Language or General Elective (3 credits) + +Spring: +{"department": "ENGL", "number": "204", "name": "American Literature II", "credits": 3}, +ENGL Elective or {"department": "ENGL", "number": "206", "name": "Course option", "credits": 3}, +SSFT Course (2 credits), +Foreign Language or General Elective (3 credits), +General Elective (5 credits) + +Junior Year: +Fall: +{"department": "ENGL", "number": "351", "name": "Shakespeare", "credits": 3} or ENGL Elective, +{"department": "ENGL", "number": "302", "name": "Course option", "credits": 3} or ENGL Elective, +ENGL Elective (3 credits), +{"department": "HUMA", "number": "301", "name": "Civilization and the Arts", "credits": 3}, +Natural Science with Lab (4 credits) + +Spring: +ENGL Elective or {"department": "ENGL", "number": "352", "name": "Course option", "credits": 3}, +ENGL Elective or {"department": "ENGL", "number": "302", "name": "Course option", "credits": 3}, +{"department": "HUMA", "number": "303", "name": "Christianity and Civilization", "credits": 3}, +General Electives (8 credits) + +Senior Year: +Fall: +Quantitative/Logical Reasoning course (3 credits), +General Electives (13 credits) + +Spring: +{"department": "ENGL", "number": "485", "name": "Senior Capstone", "credits": 3}, +General Electives (13 credits) + + + +ENGL Electives List: + +ENGL 221 Science Fiction +ENGL 222 Fantasy Literature +ENGL 224 Arthurian Literature +ENGL 226 Gothic Literature +ENGL 242 19th Century English Novel +ENGL 243 20th Century English Novel +ENGL 245 19th Century American Novel +ENGL 246 20th Century American Novel +ENGL 252 Modern Drama +ENGL 254 Page to Stage (1 credit) +ENGL 261 Poetry +ENGL 262 Modern Poetry +ENGL 324 European Literature +ENGL 327 Christian Writers +ENGL 356 Literary Theory \ No newline at end of file diff --git a/python-backend/__pycache__/main.cpython-313.pyc b/python-backend/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000..3125541 Binary files /dev/null and b/python-backend/__pycache__/main.cpython-313.pyc differ diff --git a/python-backend/main.py b/python-backend/main.py new file mode 100644 index 0000000..1c7c7c8 --- /dev/null +++ b/python-backend/main.py @@ -0,0 +1,70 @@ +from fastapi import FastAPI +from pydantic import BaseModel +from fastapi.middleware.cors import CORSMiddleware +import os +from openai import OpenAI +import json +from dotenv import load_dotenv + +load_dotenv() + + + +app = FastAPI() +client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) + +class QueryRequest(BaseModel): + text: str + chatbotDept: str + + + +@app.post("/query") +def query(req: QueryRequest): + + if not req.text.strip(): + return {"result": "Please enter a question to begin."} + + prompt = """ + You are a helpful assistant that provides information or gives advice based on the required courses and suggested four-year plan for a certain major. + When given a question, you should provide an accurate and concise answer based on the information I provide, and be friendly and helpful. If you don't know the answer, say you don't know. Do not make up an answer. + Don't make anything bold in the answer you return. + If you're giving a response that includes a list of courses, please format the courses in a clear and organized way, such as using bullet points or numbering. Include newlines. This will make it easier for the user to read and understand the information. + Here is the course information and four-year plan taken from the major requirements:\n + + """ + + with open(req.chatbotDept + ".txt") as f: + context_data = f.read() + + context_str = json.dumps(context_data, indent=2) + prompt += context_str + + user_prompt = req.text + + + response = client.chat.completions.create( + model="gpt-5.4-nano", + messages=[ + {"role": "system", "content": prompt}, + {"role": "user", "content": user_prompt} + ] + ) + + result = response.choices[0].message.content + + + return {"result": result} + + +# browser permission rule that lets the React frontend talk to the Python +# backend during development. + +app.add_middleware( + CORSMiddleware, + allow_origins=["http://localhost:7070"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + diff --git a/python-backend/requirements.txt b/python-backend/requirements.txt new file mode 100644 index 0000000..93bfb43 Binary files /dev/null and b/python-backend/requirements.txt differ