@@ -12,14 +12,10 @@ import {
1212 DEPARTMENT_CODES ,
1313 ASSISTANT_TERMS ,
1414 USEFUL_INFO ,
15- BREADTH_REQUIREMENT_KEYWORDS ,
16- YEAR_LEVEL_KEYWORDS ,
1715} from "../constants/promptKeywords" ;
1816import { CHATBOT_MEMORY_THRESHOLD , codeToYear } from "../constants/constants" ;
1917import { namespaceToMinResults } from "../constants/constants" ;
2018import OpenAI from "openai" ;
21- import { convertBreadthRequirement } from "../utils/convert-breadth-requirement" ;
22- import { convertYearLevel } from "../utils/convert-year-level" ;
2319
2420const openai = createOpenAI ( {
2521 baseURL : process . env . OPENAI_BASE_URL ,
@@ -35,7 +31,7 @@ const pinecone = new Pinecone({
3531} ) ;
3632
3733const index : Index < RecordMetadata > = pinecone . Index (
38- process . env . PINECONE_INDEX_NAME ! ,
34+ process . env . PINECONE_INDEX_NAME !
3935) ;
4036
4137console . log ( "Connected to OpenAI API" ) ;
@@ -62,8 +58,8 @@ function analyzeQuery(query: string): {
6258
6359 // If a course code is detected, add tehse namespaces
6460 if ( containsCourseCode ) {
65- if ( ! relevantNamespaces . includes ( "courses_v3 " ) )
66- relevantNamespaces . push ( "courses_v3 " ) ;
61+ if ( ! relevantNamespaces . includes ( "courses_v2 " ) )
62+ relevantNamespaces . push ( "courses_v2 " ) ;
6763 if ( ! relevantNamespaces . includes ( "offerings" ) )
6864 relevantNamespaces . push ( "offerings" ) ;
6965 if ( ! relevantNamespaces . includes ( "prerequisites" ) )
@@ -74,8 +70,8 @@ function analyzeQuery(query: string): {
7470 if ( DEPARTMENT_CODES . some ( ( code ) => lowerQuery . includes ( code ) ) ) {
7571 if ( ! relevantNamespaces . includes ( "departments" ) )
7672 relevantNamespaces . push ( "departments" ) ;
77- if ( ! relevantNamespaces . includes ( "courses_v3 " ) )
78- relevantNamespaces . push ( "courses_v3 " ) ;
73+ if ( ! relevantNamespaces . includes ( "courses_v2 " ) )
74+ relevantNamespaces . push ( "courses_v2 " ) ;
7975 }
8076
8177 // If search is required at all
@@ -87,12 +83,12 @@ function analyzeQuery(query: string): {
8783 // If no specific namespaces identified & search required, then search all
8884 if ( requiresSearch && relevantNamespaces . length === 0 ) {
8985 relevantNamespaces . push (
90- "courses_v3 " ,
86+ "courses_v2 " ,
9187 "offerings" ,
9288 "prerequisites" ,
9389 "corequisites" ,
9490 "departments" ,
95- "programs" ,
91+ "programs"
9692 ) ;
9793 }
9894
@@ -109,8 +105,7 @@ function analyzeQuery(query: string): {
109105async function searchSelectedNamespaces (
110106 query : string ,
111107 k : number ,
112- namespaces : string [ ] ,
113- filters ?: Object ,
108+ namespaces : string [ ]
114109) : Promise < Document [ ] > {
115110 let allResults : Document [ ] = [ ] ;
116111
@@ -131,8 +126,7 @@ async function searchSelectedNamespaces(
131126 // Search results count given by the min result count for a given namespace (or k if k is greater)
132127 const results = await namespaceStore . similaritySearch (
133128 query ,
134- Math . max ( k , namespaceToMinResults . get ( namespace ) ) ,
135- namespace === "courses_v3" ? filters : undefined ,
129+ Math . max ( k , namespaceToMinResults . get ( namespace ) )
136130 ) ;
137131 console . log ( `Found ${ results . length } results in namespace: ${ namespace } ` ) ;
138132 allResults = [ ...allResults , ...results ] ;
@@ -153,7 +147,7 @@ async function searchSelectedNamespaces(
153147// Reformulate user query to make more concise query to database, taking into consideration context
154148async function reformulateQuery (
155149 latestQuery : string ,
156- conversationHistory : any [ ] ,
150+ conversationHistory : any [ ]
157151) : Promise < string > {
158152 try {
159153 const openai = new OpenAI ( {
@@ -233,69 +227,6 @@ async function reformulateQuery(
233227 }
234228}
235229
236- // Determines whether to apply metadata filtering based on user query.
237- function includeFilters ( query : string ) {
238- const lowerQuery = query . toLocaleLowerCase ( ) ;
239- const relaventBreadthRequirements : string [ ] = [ ] ;
240- const relaventYearLevels : string [ ] = [ ] ;
241-
242- Object . entries ( BREADTH_REQUIREMENT_KEYWORDS ) . forEach (
243- ( [ namespace , keywords ] ) => {
244- if ( keywords . some ( ( keyword ) => lowerQuery . includes ( keyword ) ) ) {
245- relaventBreadthRequirements . push ( convertBreadthRequirement ( namespace ) ) ;
246- }
247- } ,
248- ) ;
249-
250- Object . entries ( YEAR_LEVEL_KEYWORDS ) . forEach ( ( [ namespace , keywords ] ) => {
251- if ( keywords . some ( ( keyword ) => lowerQuery . includes ( keyword ) ) ) {
252- relaventYearLevels . push ( convertYearLevel ( namespace ) ) ;
253- }
254- } ) ;
255-
256- let filter = { } ;
257- if ( relaventBreadthRequirements . length > 0 && relaventYearLevels . length > 0 ) {
258- filter = {
259- $and : [
260- {
261- $or : relaventBreadthRequirements . map ( ( req ) => ( {
262- breadth_requirement : { $eq : req } ,
263- } ) ) ,
264- } ,
265- {
266- $or : relaventYearLevels . map ( ( yl ) => ( { year_level : { $eq : yl } } ) ) ,
267- } ,
268- ] ,
269- } ;
270- } else if ( relaventBreadthRequirements . length > 0 ) {
271- filter = {
272- $or : relaventBreadthRequirements . map ( ( req ) => ( {
273- breadth_requirement : { $eq : req } ,
274- } ) ) ,
275- } ;
276- } else if ( relaventYearLevels . length > 0 ) {
277- filter = {
278- $or : relaventYearLevels . map ( ( yl ) => ( { year_level : { $eq : yl } } ) ) ,
279- } ;
280- }
281- return filter ;
282- }
283-
284- /**
285- * @description Handles user queries and generates responses using GPT-4o, with optional knowledge retrieval.
286- *
287- * @param {Request } req - The Express request object, containing:
288- * @param {Object[] } req.body.messages - Array of message objects representing the conversation history.
289- * @param {string } req.body.messages[].role - The role of the message sender (e.g., "user", "assistant").
290- * @param {Object[] } req.body.messages[].content - An array containing message content objects.
291- * @param {string } req.body.messages[].content[].text - The actual text of the message.
292- *
293- * @param {Response } res - The Express response object used to stream the generated response.
294- *
295- * @returns {void } Responds with a streamed text response of the AI output
296- *
297- * @throws {Error } If query reformulation or knowledge retrieval fails.
298- */
299230export const chat = asyncHandler ( async ( req : Request , res : Response ) => {
300231 const { messages } = req . body ;
301232 const latestMessage = messages [ messages . length - 1 ] . content [ 0 ] . text ;
@@ -309,7 +240,7 @@ export const chat = asyncHandler(async (req: Request, res: Response) => {
309240 // Use GPT-4o to reformulate the query based on conversation history
310241 const reformulatedQuery = await reformulateQuery (
311242 latestMessage ,
312- conversationHistory . slice ( - CHATBOT_MEMORY_THRESHOLD ) , // last K messages
243+ conversationHistory . slice ( - CHATBOT_MEMORY_THRESHOLD ) // last K messages
313244 ) ;
314245 console . log ( ">>>> Original query:" , latestMessage ) ;
315246 console . log ( ">>>> Reformulated query:" , reformulatedQuery ) ;
@@ -323,19 +254,15 @@ export const chat = asyncHandler(async (req: Request, res: Response) => {
323254 if ( requiresSearch ) {
324255 console . log (
325256 `Query requires knowledge retrieval, searching namespaces: ${ relevantNamespaces . join (
326- ", " ,
327- ) } `,
257+ ", "
258+ ) } `
328259 ) ;
329260
330- const filters = includeFilters ( reformulatedQuery ) ;
331- // console.log("Filters: ", JSON.stringify(filters))
332-
333261 // Search only relevant namespaces
334262 const searchResults = await searchSelectedNamespaces (
335263 reformulatedQuery ,
336264 3 ,
337- relevantNamespaces ,
338- Object . keys ( filters ) . length === 0 ? undefined : filters ,
265+ relevantNamespaces
339266 ) ;
340267 // console.log("Search Results: ", searchResults);
341268
@@ -403,15 +330,15 @@ export const testSimilaritySearch = asyncHandler(
403330 if ( requiresSearch ) {
404331 console . log (
405332 `Query requires knowledge retrieval, searching namespaces: ${ relevantNamespaces . join (
406- ", " ,
407- ) } `,
333+ ", "
334+ ) } `
408335 ) ;
409336
410337 // Search only the relevant namespaces
411338 const searchResults = await searchSelectedNamespaces (
412339 message ,
413340 3 ,
414- relevantNamespaces ,
341+ relevantNamespaces
415342 ) ;
416343 console . log ( "Search Results: " , searchResults ) ;
417344
@@ -421,11 +348,11 @@ export const testSimilaritySearch = asyncHandler(
421348 }
422349 } else {
423350 console . log (
424- "Query does not require knowledge retrieval, skipping search" ,
351+ "Query does not require knowledge retrieval, skipping search"
425352 ) ;
426353 }
427354
428355 console . log ( "CONTEXT: " , context ) ;
429356 res . status ( 200 ) . send ( context ) ;
430- } ,
357+ }
431358) ;
0 commit comments