aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/ChatBox/AnswerParser.ts
blob: 1162d46b0fe3ccf36239fc5fb7e6397000abcf8b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import { ASSISTANT_ROLE, AssistantMessage, Citation, getChunkType } from './types';
import { v4 as uuid } from 'uuid';

export class AnswerParser {
    static parse(xml: string): AssistantMessage {
        const answerRegex = /<answer>([\s\S]*?)<\/answer>/;
        const citationRegex = /<citation chunk_id="([^"]+)" type="([^"]+)">(.*?)<\/citation>/g;
        const followUpQuestionsRegex = /<follow_up_questions>([\s\S]*?)<\/follow_up_questions>/;
        const questionRegex = /<question>(.*?)<\/question>/g;

        const answerMatch = answerRegex.exec(xml);
        const followUpQuestionsMatch = followUpQuestionsRegex.exec(xml);

        if (!answerMatch) {
            throw new Error('Invalid XML: Missing <answer> tag.');
        }

        const rawTextContent = answerMatch[1].trim();
        const textContentWithCitations = rawTextContent.replace(citationRegex, '');
        const textContent = textContentWithCitations.replace(followUpQuestionsRegex, '').trim();

        let citations: Citation[] = [];
        let match: RegExpExecArray | null;

        let plainTextOffset = 0;
        let citationOffset = 0;

        while ((match = citationRegex.exec(rawTextContent)) !== null) {
            const [fullMatch, chunk_id, type, direct_text] = match;
            const citationStartIndex = match.index;
            const citationPlainStart = citationStartIndex - citationOffset;

            citations.push({
                direct_text: direct_text.trim(),
                type: getChunkType(type),
                chunk_id: chunk_id,
                text_location: citationPlainStart,
                citation_id: uuid(),
            });

            citationOffset += fullMatch.length;
        }

        let followUpQuestions: string[] = [];
        if (followUpQuestionsMatch) {
            const questionsText = followUpQuestionsMatch[1];
            let questionMatch: RegExpExecArray | null;

            while ((questionMatch = questionRegex.exec(questionsText)) !== null) {
                followUpQuestions.push(questionMatch[1].trim());
            }
        }
        const assistantResponse: AssistantMessage = {
            role: ASSISTANT_ROLE.ASSISTANT,
            text_content: textContent,
            follow_up_questions: followUpQuestions,
            citations: citations,
        };

        return assistantResponse;
    }
}