@@ -478,45 +478,99 @@ def _merge_score_data(
478478 all_docs: List of all_retrieved_documents with score data
479479 log: Logger instance
480480 """
481- # Build a lookup map by content or filepath to match documents
482- doc_scores = {}
481+ # Build multiple lookup maps to maximize matching chances
482+ # all_retrieved_documents may have different keys than citations
483+ doc_scores_by_title = {}
484+ doc_scores_by_filepath = {}
485+ doc_scores_by_content = {}
486+ doc_scores_by_chunk_id = {}
487+
483488 for doc in all_docs :
484- # Try to match by chunk_id, filepath, or content hash
485- key = None
486- if doc .get ("chunk_id" ):
487- key = doc ["chunk_id" ]
488- elif doc .get ("filepath" ):
489- key = doc ["filepath" ]
490- elif doc .get ("content" ):
491- # Use first 100 chars of content as a key
492- key = doc ["content" ][:100 ] if len (doc .get ("content" , "" )) > 100 else doc .get ("content" )
493-
494- if key :
495- doc_scores [key ] = {
496- "original_search_score" : doc .get ("original_search_score" ),
497- "rerank_score" : doc .get ("rerank_score" ),
498- }
489+ scores = {
490+ "original_search_score" : doc .get ("original_search_score" ),
491+ "rerank_score" : doc .get ("rerank_score" ),
492+ }
493+
494+ # Only store if we have at least one score
495+ if scores ["original_search_score" ] is None and scores ["rerank_score" ] is None :
496+ continue
499497
500- # Match citations with score data
498+ # Index by title
499+ if doc .get ("title" ):
500+ doc_scores_by_title [doc ["title" ]] = scores
501+
502+ # Index by filepath
503+ if doc .get ("filepath" ):
504+ doc_scores_by_filepath [doc ["filepath" ]] = scores
505+
506+ # Index by chunk_id (may include title as prefix for uniqueness)
507+ if doc .get ("chunk_id" ) is not None :
508+ chunk_key = doc .get ("chunk_id" )
509+ # Also try with title prefix for uniqueness
510+ if doc .get ("title" ):
511+ chunk_key = f"{ doc ['title' ]} _{ doc ['chunk_id' ]} "
512+ doc_scores_by_chunk_id [str (doc ["chunk_id" ])] = scores
513+ doc_scores_by_chunk_id [chunk_key ] = scores
514+
515+ # Index by content prefix (first 100 chars)
516+ if doc .get ("content" ):
517+ content_key = doc ["content" ][:100 ] if len (doc .get ("content" , "" )) > 100 else doc .get ("content" )
518+ doc_scores_by_content [content_key ] = scores
519+
520+ log .debug (
521+ f"Built score lookup: by_title={ len (doc_scores_by_title )} , "
522+ f"by_filepath={ len (doc_scores_by_filepath )} , "
523+ f"by_chunk_id={ len (doc_scores_by_chunk_id )} , "
524+ f"by_content={ len (doc_scores_by_content )} "
525+ )
526+
527+ # Match citations with score data using multiple strategies
501528 matched = 0
502529 for citation in citations :
503- key = None
504- if citation .get ("chunk_id" ):
505- key = citation ["chunk_id" ]
506- elif citation .get ("filepath" ):
507- key = citation ["filepath" ]
508- elif citation .get ("content" ):
509- key = citation ["content" ][:100 ] if len (citation .get ("content" , "" )) > 100 else citation .get ("content" )
510-
511- if key and key in doc_scores :
512- scores = doc_scores [key ]
530+ scores = None
531+
532+ # Try matching by title first (most reliable)
533+ if not scores and citation .get ("title" ):
534+ scores = doc_scores_by_title .get (citation ["title" ])
535+ if scores :
536+ log .debug (f"Matched citation by title: { citation ['title' ]} " )
537+
538+ # Try matching by filepath
539+ if not scores and citation .get ("filepath" ):
540+ scores = doc_scores_by_filepath .get (citation ["filepath" ])
541+ if scores :
542+ log .debug (f"Matched citation by filepath: { citation ['filepath' ]} " )
543+
544+ # Try matching by chunk_id with title prefix
545+ if not scores and citation .get ("chunk_id" ) is not None :
546+ chunk_key = str (citation ["chunk_id" ])
547+ if citation .get ("title" ):
548+ chunk_key_with_title = f"{ citation ['title' ]} _{ citation ['chunk_id' ]} "
549+ scores = doc_scores_by_chunk_id .get (chunk_key_with_title )
550+ if not scores :
551+ scores = doc_scores_by_chunk_id .get (chunk_key )
552+ if scores :
553+ log .debug (f"Matched citation by chunk_id: { citation ['chunk_id' ]} " )
554+
555+ # Try matching by content prefix
556+ if not scores and citation .get ("content" ):
557+ content_key = citation ["content" ][:100 ] if len (citation .get ("content" , "" )) > 100 else citation .get ("content" )
558+ scores = doc_scores_by_content .get (content_key )
559+ if scores :
560+ log .debug (f"Matched citation by content prefix" )
561+
562+ if scores :
513563 if scores .get ("original_search_score" ) is not None :
514564 citation ["original_search_score" ] = scores ["original_search_score" ]
515565 if scores .get ("rerank_score" ) is not None :
516566 citation ["rerank_score" ] = scores ["rerank_score" ]
517567 matched += 1
568+ log .debug (
569+ f"Citation scores: original={ scores .get ('original_search_score' )} , "
570+ f"rerank={ scores .get ('rerank_score' )} "
571+ )
518572
519- log .debug (f"Merged score data for { matched } /{ len (citations )} citations" )
573+ log .info (f"Merged score data for { matched } /{ len (citations )} citations" )
520574
521575 def _normalize_citation_for_openwebui (
522576 self , citation : Dict [str , Any ], index : int
0 commit comments