Skip to content

Commit 5a8ae50

Browse files
authored
Merge branch 'develop' into ty/scrum-162-last-edited-refresh
2 parents be0a85f + 7393306 commit 5a8ae50

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1857
-387
lines changed

.github/workflows/autodeploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: CI/CD Pipeline
22

33
on:
44
push:
5-
branches: develop
5+
branches: main
66
jobs:
77
CI-PIPELINE:
88
runs-on: ubuntu-latest

.github/workflows/workflow.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Format the code
2+
3+
on:
4+
push:
5+
6+
jobs:
7+
format:
8+
runs-on: ubuntu-latest
9+
name: Format Files
10+
steps:
11+
- uses: actions/checkout@v3
12+
- uses: actions/setup-node@v3
13+
with:
14+
node-version: "20"
15+
- name: Prettier
16+
run: npx prettier --write **/*.{js,ts,tsx,json,md}
17+
env:
18+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19+
- uses: stefanzweifel/git-auto-commit-action@v4
20+
if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
21+
with:
22+
commit_message: "Auto-formatted the code using Prettier"

CICD/Dockerfile(backend)

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ COPY . .
1717
EXPOSE 8081
1818

1919
# Start the application
20-
CMD ["npm", "run", "dev"]
20+
CMD ["npm", "run", "prod"]

CICD/Dockerfile(frontend)

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ EXPOSE 8081
1818
EXPOSE 5173
1919

2020
# Start the application
21-
CMD ["npm", "run", "dev"]
21+
CMD ["npm", "run", "prod"]

CICD/ReadME.pdf

120 KB
Binary file not shown.

CICD/docker-compose.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ services:
1212
volumes:
1313
- ./backend:/app
1414
- /app/node_modules
15-
command: ["npm", "run", "dev"]
15+
command: ["npm", "run", "prod"]
1616
networks:
1717
- course-matrix-net
1818

@@ -27,7 +27,7 @@ services:
2727
volumes:
2828
- ./frontend:/app
2929
- /app/node_modules
30-
command: ["npm", "run", "dev"]
30+
command: ["npm", "run", "prod"]
3131
depends_on:
3232
- backend
3333
networks:

course-matrix/backend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"dev": "ts-node -r dotenv/config src/index.ts",
88
"test": "jest",
99
"test:watch": "jest --watch",
10-
"build": "vite build"
10+
"build": "vite build",
11+
"prod": "ts-node -r dotenv/config src/index.ts"
1112
},
1213
"keywords": [],
1314
"author": "",

course-matrix/backend/src/constants/availableFunctions.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ export type FunctionNames =
2828
| "updateTimetable"
2929
| "deleteTimetable"
3030
| "generateTimetable"
31-
| "getCourses";
31+
| "getCourses"
32+
| "getOfferings";
3233

3334
type AvailableFunctions = {
3435
[K in FunctionNames]: (args: any, req: Request) => Promise<any>;
@@ -484,7 +485,7 @@ ${offeringData.meeting_section} `;
484485
});
485486

486487
// Get all courses that have any of the provided courses as its prefix
487-
const { data, error } = await supabase
488+
const { data: courseData, error } = await supabase
488489
.schema("course")
489490
.from("courses")
490491
.select("*")
@@ -494,7 +495,42 @@ ${offeringData.meeting_section} `;
494495
return { status: 400, error: error.message };
495496
}
496497

497-
return { status: 200, data };
498+
return { status: 200, data: courseData };
499+
} catch (error) {
500+
const errorMessage =
501+
error instanceof Error ? error.message : "An unknown error occurred";
502+
return { status: 500, error: errorMessage };
503+
}
504+
},
505+
506+
getOfferings: async (args: any, req: Request) => {
507+
const { courses, semester } = args;
508+
try {
509+
const filterConditions = courses.map((prefix: string) => {
510+
return `code.ilike.${prefix}%`;
511+
});
512+
513+
// Get all offerings for any of the provided courses
514+
const { data: offeringsData, error: offeringsError } = await supabase
515+
.schema("course")
516+
.from("offerings")
517+
.select("*")
518+
.eq("offering", semester)
519+
.or(filterConditions.join(","));
520+
521+
if (offeringsError) {
522+
return { status: 400, error: offeringsError.message };
523+
}
524+
525+
// Return the courses that are offered in the semseter
526+
const coursesOffered = new Set();
527+
for (const offering of offeringsData) {
528+
if (!coursesOffered.has(offering.code)) {
529+
coursesOffered.add(offering.code);
530+
}
531+
}
532+
533+
return { status: 200, data: Array.from(coursesOffered) };
498534
} catch (error) {
499535
const errorMessage =
500536
error instanceof Error ? error.message : "An unknown error occurred";

course-matrix/backend/src/constants/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const TEST_DATE_NOW = new Date(2025, 4, 14, 8, 45, 1);
4646

4747
// Set minimum results wanted for a similarity search on the associated namespace.
4848
export const namespaceToMinResults = new Map();
49-
namespaceToMinResults.set("courses_v3", 10);
49+
namespaceToMinResults.set("courses_v3", 16);
5050
namespaceToMinResults.set("offerings", 16); // Typically, more offering info is wanted.
5151
namespaceToMinResults.set("prerequisites", 5);
5252
namespaceToMinResults.set("corequisites", 5);

course-matrix/backend/src/controllers/aiController.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export async function reformulateQuery(
138138
- DO replace pronouns and references with specific names and identifiers
139139
- DO include course codes, names and specific details for academic entities
140140
- If the query is not about university courses & offerings, return exactly a copy of the user's query.
141-
- Append "code: " before course codes For example: "CSCC01" -> "code: CSCC01"
141+
- Append "code: " before each course code For example: "CSCC01, BIOA01" -> "code: CSCC01, code: BIOA01"
142142
- If a course year level is written as "first year", "second year", etc. Then replace "first" with "1st" and "second" with "2nd" etc.
143143
144144
Examples:
@@ -265,8 +265,14 @@ export const chat = asyncHandler(async (req: Request, res: Response) => {
265265
process.env.CLIENT_APP_URL
266266
}/dashboard/timetable?edit=[[TIMETABLE_ID]] , where TIMETABLE_ID is the id of the respective timetable.
267267
- If the user provides a course code of length 6 like CSCA08, then assume they mean CSCA08H3 (H3 appended)
268-
- If the user wants to create a timetable, first call getCourses to get course information on the requested courses, then call generateTimetable.
268+
- If the user wants to create a timetable:
269+
1. First call getCourses to get course information on the requested courses,
270+
2. If the user provided a semester, then call getOfferings with the provided courses and semester to ensure the courses are actually offered in the semester.
271+
a) If a course is NOT returned by getOFferings, then list it under "Excluded courses" with "reason: not offered in [provided semester]"
272+
b) If no courses have offerings, then do not generate the timetable.
273+
3. Lastly, call generateTimetable with the provided information.
269274
- Do not make up fake courses or offerings.
275+
- If a user asks about a course that you do not know of, acknowledge this.
270276
- You can only edit title of the timetable, nothing else. If a user tries to edit something else, acknowledge this limitation.
271277
- For delete timetable requests, if the user asks to delete an ambiguous timetable name (i.e many with similar name exist) then ask them to clarify which one
272278
- For delete timetable requests, first check that the timetable the user is refering to exists
@@ -327,6 +333,19 @@ export const chat = asyncHandler(async (req: Request, res: Response) => {
327333
return await availableFunctions.getCourses(args, req);
328334
},
329335
}),
336+
getOfferings: tool({
337+
description:
338+
"Return courses offered in the provided semester out of all course codes provided",
339+
parameters: z.object({
340+
courses: z.array(z.string()).describe("List of course codes"),
341+
semester: z.string(),
342+
}),
343+
execute: async (args) => {
344+
const res = await availableFunctions.getOfferings(args, req);
345+
console.log("Result of getOfferings: ", res);
346+
return res;
347+
},
348+
}),
330349
},
331350
maxSteps: CHATBOT_TOOL_CALL_MAX_STEPS, // Controls how many back and forths
332351
// the model can take with user or
@@ -455,7 +474,9 @@ export const chat = asyncHandler(async (req: Request, res: Response) => {
455474
- If information is missing from the context but likely exists, try to use info from web to answer. If still not able to form a decent response, acknowledge the limitation
456475
- For unrelated questions, politely explain that you're specialized in UTSC academic information
457476
- If a user prompt appears like a task that requires timetable operations (like create, read, update, delete a user's timetable) BUT the user prompt doesn't start with prefix "/timetable" then remind user to use "/timetable" in front of their prompt to access these capabilities
458-
477+
- If the user prompt is a response to a task that requires timetable operations (eg "confirm", "proceed", "continue") then ask user to use "/timetable"
478+
- If a user asks about a course that you do not know of, acknowledge this.
479+
459480
## Available Knowledge
460481
${
461482
context === "[No context provided]"

0 commit comments

Comments
 (0)