File size: 2,584 Bytes
1904e4c
22b1735
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1904e4c
 
 
 
 
 
 
 
 
 
 
 
22b1735
 
 
 
 
 
 
 
 
 
 
 
 
 
1904e4c
 
22b1735
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1904e4c
22b1735
 
 
 
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

// src/components/ChatMessage.tsx
import React, { useState, useMemo } from 'react'
import ReactMarkdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import rehypeRaw from 'rehype-raw'
import { cn } from '@/lib/utils'
import { toast } from '../ui/sonner'

interface ChatMessageProps {
  content: string
  className?: string
}

export const ChatMessage: React.FC<ChatMessageProps> = ({
  content,
  className,
}) => {

  // Process thinking tags
  const processedContent = useMemo(() => {
    // Replace <think>...</think> tags with a special format
    const contentWithProcessedThinking = content.replace(
      /<think>([\s\S]*?)<\/think>/g,
      (_, thinkContent) => {
        return `<div class="think-block">${thinkContent}</div>`;
      }
    );

    // Continue processing source tags as before
    return contentWithProcessedThinking.replace(
      /<source\s+path=["'](.+?)["']\s*\/>/g,
      (_match, path) => {
        const filename = path
          .split('/')
          .pop()!
          .replace(/\.[^/.]+$/, '')
        // embed your ExternalLink SVG inline so you get the icon
        return `<a href="${path}" target="_blank" class="inline-flex items-center text-xs font-medium mx-0.5 rounded-sm px-1 bg-financial-accent/10 text-financial-accent border border-financial-accent/20 hover:bg-financial-accent/20 transition-colors">
            ${filename}
            <svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3 ml-1" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
              <path stroke-linecap="round" stroke-linejoin="round" d="M18 13v6a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6M15 3h6m0 0v6m0-6L10 14"/>
            </svg>
          </a>`
      }
    );
  }, [content]);

  return (
    <div
      className={cn(
        'group relative w-full rounded-md p-2 hover:bg-muted/30 transition-colors',
        className
      )}
    >
      <ReactMarkdown
        remarkPlugins={[remarkGfm]}
        rehypePlugins={[rehypeRaw]}
        components={{
          // style your normal links if you like
          a: ({ href, children, node, ...props }) =>
            href && href.endsWith('.md') ? (
              <a
                href={href}
                target="_blank"
                rel="noopener noreferrer"
                {...props}
              >
                {children}
              </a>
            ) : (
              <a href={href} {...props}>
                {children}
              </a>
            ),
        }}
      >
        {processedContent}
      </ReactMarkdown>
    </div>
  )
}