@@ -116,6 +116,7 @@ const updateWorkspaceAttributesSchema = schema.object({
116116
117117// Declare a variable outside the route handler to cache the model.
118118let semanticExtractor : any = null ;
119+ let answerer : any = null ;
119120
120121export function registerRoutes ( {
121122 client,
@@ -367,13 +368,19 @@ export function registerRoutes({
367368 try {
368369 const { query, links } = req . body ;
369370
370- // Filter links to ensure they have a description for the semantic search
371- let linksWithDescription = links . filter ( ( link ) => ! ! link . description ) ;
372- linksWithDescription = Array . from ( new Set ( linksWithDescription . map ( ( link ) => link . id ) ) ) . map (
373- ( id ) => linksWithDescription . find ( ( link ) => link . id === id ) !
374- ) ;
375-
376371 console . log ( '-------------Enter semanticSearch (Node.js)-------------' ) ;
372+ if ( ! answerer ) {
373+ const startTime = performance . now ( ) ;
374+ answerer = await pipeline (
375+ 'question-answering' ,
376+ 'Xenova/tiny-random-RoFormerForQuestionAnswering'
377+ ) ;
378+ const endTime = performance . now ( ) ;
379+ const loadingTimeMs = endTime - startTime ;
380+
381+ console . log ( 'Answer loaded and ready for inference.' ) ;
382+ console . log ( `Answer loading took: ${ loadingTimeMs . toFixed ( 2 ) } ms` ) ;
383+ }
377384
378385 // Load the model only once and reuse it later
379386 if ( ! semanticExtractor ) {
@@ -393,7 +400,7 @@ export function registerRoutes({
393400
394401 // Generate embeddings for links
395402 const linkEmbeddings = await Promise . all (
396- linksWithDescription . map ( async ( link ) => {
403+ links . map ( async ( link ) => {
397404 const titleOutput = await semanticExtractor ( link . title , {
398405 pooling : 'mean' ,
399406 normalize : true ,
@@ -409,13 +416,13 @@ export function registerRoutes({
409416 descriptionEmbedding = Array . from ( descOutput . data ) as number [ ] ;
410417 }
411418
412- const WEIGHT_TITLE = 0.7 ;
413- const WEIGHT_DESC = 0.3 ;
419+ const titleWeight = 0.7 ;
420+ const descWeight = 0.3 ;
414421
415422 let combinedEmbedding : number [ ] = [ ] ;
416423
417424 combinedEmbedding = titleEmbedding . map (
418- ( val , i ) => val * WEIGHT_TITLE + descriptionEmbedding ! [ i ] * WEIGHT_DESC
425+ ( val , i ) => val * titleWeight + descriptionEmbedding ! [ i ] * descWeight
419426 ) ;
420427
421428 return { ...link , embedding : combinedEmbedding } ;
@@ -430,18 +437,38 @@ export function registerRoutes({
430437 // Calculate scores and sort
431438 const scored = linkEmbeddings . map ( ( link ) => ( {
432439 ...link ,
433- // score: cosineSimilarity(queryEmbedding as number[], link.embedding as number[]),
434440 score : cos_sim ( queryEmbedding as number [ ] , link . embedding as number [ ] ) ,
435441 } ) ) ;
436442
437443 scored . sort ( ( a , b ) => b . score - a . score ) ;
438444
439445 const semanticSearchResult = scored
440- . slice ( 0 , 8 )
441- . filter ( ( item ) => item . score > 0.08 )
446+ . slice ( 0 , 5 )
447+ . filter ( ( item ) => item . score > 0.2 )
442448 . map ( ( { embedding, ...rest } ) => rest ) ;
443449 console . log ( 'semanticSearchResult: ' , semanticSearchResult ) ;
444450
451+ const qaResults = [ ] ;
452+
453+ for ( const link of links ) {
454+ const answer = await answerer ( query , link . description ) ;
455+ if ( answer && answer . answer ) {
456+ qaResults . push ( {
457+ linkId : link . id ,
458+ title : link . title ,
459+ description : link . description ,
460+ answer : answer . answer ,
461+ score : answer . score ,
462+ } ) ;
463+ }
464+ }
465+
466+ qaResults . sort ( ( a , b ) => b . score - a . score ) ;
467+
468+ const finalQaResults = qaResults . slice ( 0 , 5 ) . filter ( ( item ) => item . score > 0.1 ) ;
469+
470+ console . log ( 'Question Answering: ' , finalQaResults ) ;
471+
445472 return res . ok ( { body : semanticSearchResult } ) ;
446473 } catch ( error ) {
447474 console . error ( 'Error during semantic search:' , error ) ;
0 commit comments