Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
40 changes: 36 additions & 4 deletions app/frontend/src/components/Answer/AnswerParser.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,43 @@
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 dataPoint starts with possible citation
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;
}

const isValidCitation = dataPointsArray.some(dataPoint => dataPoint.startsWith(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();
// Trim any whitespace from the end of the answer after removing follow-up questions
let parsedAnswer = answer.message.content.trim();

// Omit a citation that is still being typed during streaming
if (isStreaming) {
Expand All @@ -34,6 +61,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