File size: 3,885 Bytes
f098874
 
e4526cf
3717d81
 
727c614
f098874
 
e4526cf
f098874
98a4631
e4526cf
 
 
 
 
 
 
3717d81
727c614
f098874
 
90b8b3b
 
 
8e65602
 
90b8b3b
0918045
 
e4526cf
 
 
 
 
 
 
 
 
 
5a19572
90b8b3b
 
 
f098874
e4526cf
727c614
 
f098874
8e65602
4eeeb10
 
 
90b8b3b
4eeeb10
 
 
 
 
 
 
 
 
 
 
 
 
1ce4fbf
 
 
3717d81
1ce4fbf
a155b02
2c7dc70
5a19572
 
2c7dc70
0918045
 
 
 
1ce4fbf
0918045
1ce4fbf
 
 
f098874
727c614
 
 
4eeeb10
727c614
 
4eeeb10
 
 
727c614
 
 
 
 
 
 
4eeeb10
 
 
 
 
 
 
 
 
727c614
 
f098874
 
 
 
 
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import Text from "../Text/Text";
import styles from "./Message.module.css";
import React, { useState, useEffect } from "react";
import { marked } from "marked";
import DOMPurify from "dompurify";
import UploadedFileCard from "../UploadedFileCard/UploadedFileCard";

interface MessageProps {
  key: string;
  textContent: string;
  sender: "user" | "system";
  openFileViewer?: (
    fileUrl: string,
    fileName: string,
    page: number,
    lines: string,
    start: string,
  ) => void;
  isStreaming?: boolean;
  files?: { name: string; type: string; size: number }[];
}

const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;

function transformCitationsToLinks(text: string): string {
  const citationRegex =
    /\s*\[Source:\s*([^,]+?)\s*,\s*Page:\s*(\d+)\s*,\s*Lines:\s*(\d+\s*-\s*\d+)\s*,\s*Start:?\s*(\d+)\]/g;
  return text.replace(citationRegex, (match, path, page, lines, start) => {
    // const fileUrl = `https://the-ultimate-rag-hf-rag-integration-test.hf.space`+`\\viewer\\${path}`;
    const fileUrl = `https://PopovDanil-backend.hf.space`+`\\viewer\\${path}`;
    console.log(
      "File URL:",
      fileUrl,
      "Page:",
      page,
      "Lines:",
      lines,
      "Start:",
      start,
    );
    return ` <a id="${fileUrl}&${page}&${lines}&${start}" href="${fileUrl}" data-page="${page}" data-lines="${lines}" data-start="${start}">[Source]</a>`;
  });
}

function Message(props: Readonly<MessageProps>) {
  const { textContent, sender, openFileViewer, files } = props;
  const messageBubbleStyle: string = `${styles.messageBox} ${sender === "user" ? styles.userMessageBox : styles.systemMessageBox}`;
  const messageContainerStyle: string = `${styles.messageContainer} ${sender === "user" ? styles.userMessageContainer : styles.systemMessageContainer}`;

  const [sanitizedHtml, setSanitizedHtml] = useState("");

  useEffect(() => {
    const parseAndSanitize = async () => {
      const htmlResult = marked.parse(transformCitationsToLinks(textContent));
      let finalHtml: string;

      if (htmlResult instanceof Promise) {
        finalHtml = await htmlResult;
      } else {
        finalHtml = htmlResult;
      }
      setSanitizedHtml(DOMPurify.sanitize(finalHtml));
    };

    parseAndSanitize();
  }, [textContent]);

  const handleContentClick = (event: React.MouseEvent<HTMLDivElement>) => {
    const target = event.target as HTMLElement;
    if (target.tagName === "A" && target.hasAttribute("href")) {
      event.preventDefault();
      const fileUrl = target.getAttribute("href");
      const fileName = target.textContent ?? "";
      const page = target.getAttribute("data-page");
      const lines = target.getAttribute("data-lines");
      const start = target.getAttribute("data-start");
      console.log("File URL:", fileUrl, "Page:", page);

      if (openFileViewer) {
        openFileViewer(fileUrl ? fileUrl : '', fileName, parseInt(page ? page : "1"), lines ? lines : '1-1', start ? start : '');
        console.log('Opening file preview:', fileUrl)
      }

    }
  };

  return (
    <div className={messageContainerStyle}>
      {files && files.length > 0 && (
        <div className={styles.attachedFiles}>
          {files.map((file, idx) => (
            <UploadedFileCard
              key={idx}
              fileName={file.name}
              fileType={file.type}
              fileSize={file.size}
              onClose={() => {}}
            />
          ))}
        </div>
      )}

      <div className={messageBubbleStyle} onClick={handleContentClick}>
        <Text
          as="div"
          interactable={true}
          colorVariant={sender === "user" ? "button" : "primary"}
        >
          <span
            className={styles.markdownContent}
            dangerouslySetInnerHTML={{ __html: sanitizedHtml }}
          />
        </Text>
      </div>
    </div>
  );
}

export default Message;