From a33d6c02b220df51b56866e63f55062033ffdef9 Mon Sep 17 00:00:00 2001 From: Ayaz-Microsoft Date: Fri, 2 Jan 2026 11:34:24 +0530 Subject: [PATCH] fix: repeated citation --- .../src/components/Answer/AnswerParser.tsx | 56 +++++++++++++++---- extensions/teams/cards/cardBuilder.ts | 44 ++++++++++----- 2 files changed, 75 insertions(+), 25 deletions(-) diff --git a/code/frontend/src/components/Answer/AnswerParser.tsx b/code/frontend/src/components/Answer/AnswerParser.tsx index 44cbedf03..170174c32 100644 --- a/code/frontend/src/components/Answer/AnswerParser.tsx +++ b/code/frontend/src/components/Answer/AnswerParser.tsx @@ -22,22 +22,56 @@ export function parseAnswer(answer: AskResponse): ParsedAnswer { filteredCitations = [] as Citation[]; let citationReindex = 0; + + // Track the last citation to detect consecutive duplicates + let lastCitationKey: string | null = null; + citationLinks?.forEach(link => { - // Replacing the links/citations with number + // Extract citation index from [docN] let citationIndex = link.slice(lengthDocN, link.length - 1); let citation = cloneDeep(answer.citations[Number(citationIndex) - 1]) as Citation; - if (!isDuplicate(citation, citationIndex) && citation !== undefined) { - answerText = answerText.replaceAll(link, ` ^${++citationReindex}^ `); - citation.reindex_id = citationReindex.toString(); // reindex from 1 for display - filteredCitations.push(citation); - }else{ - // Replacing duplicate citation with original index - let matchingCitation = filteredCitations.find((ct) => citation.chunk_id === ct.chunk_id && citation.id === ct.id); - if (matchingCitation) { - answerText= answerText.replaceAll(link, ` ^${matchingCitation.reindex_id}^ `) + + if (citation === undefined) { + answerText = answerText.replace(link, ''); + return; + } + + // Create unique key for this citation + const citationKey = `${citation.chunk_id}_${citation.id}`; + + // Check if this is a consecutive duplicate + if (citationKey === lastCitationKey) { + // Remove consecutive duplicate + answerText = answerText.replace(link, ''); + } else { + // Not a duplicate or not consecutive - process it + if (!isDuplicate(citation, citationIndex)) { + // This is a new unique citation - add to list + citation.reindex_id = (++citationReindex).toString(); + filteredCitations.push(citation); + } else { + // This citation was seen before (but not consecutive) - find its reindex_id + const existingCitation = filteredCitations.find( + (c) => c.chunk_id === citation.chunk_id && c.id === citation.id + ); + if (existingCitation) { + citation.reindex_id = existingCitation.reindex_id; + } else { + // Fallback: should not happen, but handle it + citation.reindex_id = (++citationReindex).toString(); + filteredCitations.push(citation); + } + } + + // Replace with the citation number (use replace to only replace first occurrence) + if (citation.reindex_id) { + answerText = answerText.replace(link, ` ^${citation.reindex_id}^ `); } } - }) + + // Update last citation key + lastCitationKey = citationKey; + }); return { diff --git a/extensions/teams/cards/cardBuilder.ts b/extensions/teams/cards/cardBuilder.ts index c22085039..6bc41888b 100644 --- a/extensions/teams/cards/cardBuilder.ts +++ b/extensions/teams/cards/cardBuilder.ts @@ -92,29 +92,45 @@ export function cardBodyBuilder(citations: any[], assistantAnswer: string): any export function cwydResponseBuilder(citations: Citation[], assistantAnswer: string): Attachment { let citationActions: any[] = []; let docId = 1; - let deleteEnd = ""; - let deleteEndSpace = ""; let refCount = 1; let findPart = {}; let reIndex = 0; + + // Track the last citation to detect consecutive duplicates + let lastCitationKey: string | null = null; + citations.map((citation: Citation) => { - if (!(citation.chunk_id in findPart)) { - reIndex = docId; - citationActions.push(actionBuilder(citation, reIndex)); - findPart[citation.chunk_id] = reIndex; - docId++; + const citationKey = `${citation.chunk_id}_${citation.id}`; + const docMarker = `[doc${refCount}]`; + + // Check if this is a consecutive duplicate + if (citationKey === lastCitationKey) { + // Remove consecutive duplicate + assistantAnswer = assistantAnswer.replace(docMarker, ''); } else { - reIndex = findPart[citation.chunk_id]; - } + // Not consecutive - process it + if (!(citation.chunk_id in findPart)) { + // New unique citation + reIndex = docId; + citationActions.push(actionBuilder(citation, reIndex)); + findPart[citation.chunk_id] = reIndex; + docId++; + } else { + // Citation seen before (but not consecutive) + reIndex = findPart[citation.chunk_id]; + } - deleteEnd += `[${reIndex}]`; - deleteEndSpace += ` [${reIndex}]`; - assistantAnswer = assistantAnswer.replaceAll(`[doc${refCount}]`, `[${reIndex}]`); + // Replace with the reindexed number + if (reIndex) { + assistantAnswer = assistantAnswer.replace(docMarker, `[${reIndex}]`); + } + } + // Update last citation key + lastCitationKey = citationKey; refCount++; }); - assistantAnswer = assistantAnswer.replaceAll(deleteEnd, ""); - assistantAnswer = assistantAnswer.replaceAll(deleteEndSpace, ""); + let answerCard = CardFactory.adaptiveCard(cardBodyBuilder(citationActions, assistantAnswer)); return answerCard; }