Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions app/frontend/src/components/Answer/Answer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ export const Answer = ({
showSpeechOutputBrowser
}: Props) => {
const followupQuestions = answer.context?.followup_questions;
const messageContent = answer.message.content;
const parsedAnswer = useMemo(() => parseAnswerToHtml(messageContent, isStreaming, onCitationClicked), [answer]);
const parsedAnswer = useMemo(() => parseAnswerToHtml(answer, isStreaming, onCitationClicked), [answer]);
const { t } = useTranslation();
const sanitizedAnswerHtml = DOMPurify.sanitize(parsedAnswer.answerHtml);

Expand Down
39 changes: 36 additions & 3 deletions app/frontend/src/components/Answer/AnswerParser.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,44 @@
import { renderToStaticMarkup } from "react-dom/server";
import { getCitationFilePath } from "../../api";
import { ChatAppResponse, getCitationFilePath } from "../../api";

type HtmlParsedAnswer = {
answerHtml: string;
citations: string[];
};

export function parseAnswerToHtml(answer: string, isStreaming: boolean, onCitationClicked: (citationFilePath: string) => void): HtmlParsedAnswer {
// Function to validate citation format and check if it is a valid citation within the context
function isCitationValid(contextDataPoints: any, citationCandidate: string): boolean {
const regex = /^[^\s]+\.[a-zA-Z0-9]+/;
if (!regex.test(citationCandidate)) {
return false;
}

// Check if contextDataPoints is an object with a text property that is an array
let dataPointsArray: string[];
if (Array.isArray(contextDataPoints)) {
dataPointsArray = contextDataPoints;
} else if (contextDataPoints && Array.isArray(contextDataPoints.text)) {
dataPointsArray = contextDataPoints.text;
} else {
return false;
}

// Check if the citation is included in any of the strings within the text array
const isValidCitation = dataPointsArray.some(dataPoint => dataPoint.includes(citationCandidate));

if (!isValidCitation) {
return false;
}

return true;
}

export function parseAnswerToHtml(answer: ChatAppResponse, isStreaming: boolean, onCitationClicked: (citationFilePath: string) => void): HtmlParsedAnswer {
const contextDataPoints = answer.context.data_points;
const citations: string[] = [];

// trim any whitespace from the end of the answer after removing follow-up questions
let parsedAnswer = answer.trim();
let parsedAnswer = answer.message.content.trim();

// Omit a citation that is still being typed during streaming
if (isStreaming) {
Expand All @@ -34,6 +62,11 @@ export function parseAnswerToHtml(answer: string, isStreaming: boolean, onCitati
return part;
} else {
let citationIndex: number;

if (!isCitationValid(contextDataPoints, part)) {
return `[${part}]`;
}

if (citations.indexOf(part) !== -1) {
citationIndex = citations.indexOf(part) + 1;
} else {
Expand Down