React写ai聊天对话,如何实现聊天makedown输出转化

最近在写一个ai聊天对话的项目,在网上没有找到很好的资料,自己琢磨了半天,写点教程方便其他人使用。我的方法是是使用react-markdown再配上一些插件像remark-gfm,rehype-highlight,highlight.js,和一些css样式实现转换。

转化前后

代码的实现

创建一个组件ChatMessage.jsx,在compontents文件夹

安装依赖npm install react-markdown remark-gfm

需安装 react-markdown 与 remark-gfm 这两个库。react-markdown 能把 Markdown 文本转换为 React 组件,remark-gfm 可支持 GitHub Flavored Markdown(GFM),像表格、任务列表这类。

创建一个组件用来处理消息,传入两个参数,message传入的消息,role消息的产生者

jsx 复制代码
import React from 'react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';

const ChatMessage = ({ message, role }) => {
 return (
   role === 'assistant' ?
     <div className="chat-message">
       <ReactMarkdown remarkPlugins={[remarkGfm]}>
         {message}
       </ReactMarkdown>
     </div> :
     <div className="user-message">
       {message}
     </div>
 );
};

export default ChatMessage;

在ai聊天页面中使用这个组件

jsx 复制代码
import ChatMessage from '@/compontents/ChatMessage';

{/* 消息区域 - 添加固定高度和滚动 */}
<div className="flex-1 overflow-y-auto p-4 w-full max-w-4xl mx-auto">
        <div className="space-y-4 min-h-[calc(100vh-200px)]">
          {messages.map(message => (
            <div
              key={message.id}
              className={`flex flex-row ${message?.role === 'assistant' ? 'justify-start' : 'justify-end'} mb-4`}>
              <div className={`max-w-[80%] rounded-2xl px-4 py-3 ${message?.role === 'assistant' ?
                'bg-blue-100 rounded-bl-none' :
                'bg-indigo-100 rounded-br-none'}`}>
                <div className={`text-gray-800 ${message?.role === 'assistant' ? 'text-left' : 'text-right'}`}>
                  <ChatMessage message={message.content} role={message.role}/> 
                </div>
              </div>
            </div>
          ))}
          <div ref={endRef} className="h-8" />
        </div>
      </div>

处理后的makedown格式,代码块有点丑,并且代码段很丑,我们写一些css样式去美化我们的

美化makedown格式

创建一个markdownStyles.css的css文件,并引入到组件ChatMessage,觉得不太好看的话可以稍作修改。

css 复制代码
/* 消息容器 - 添加平滑过渡和更现代的阴影 */
.chat-message {
  margin: 12px 0;
  padding: 16px;
  transition: all 0.2s ease;
}

/* 标题 - 添加渐变颜色和更好的间距 */
.chat-message h1 {
  color: #1a1a1a;
  border-bottom: 1px solid #eaeaea;
  padding-bottom: 8px;
  margin-bottom: 16px;
}

.chat-message h2 {
  color: #1e40af;
  margin-top: 24px;
}

/* 段落 - 优化行高和字体 */
.chat-message p {
  color: #4b5563;
  line-height: 1.8;
  font-size: 16px;
  margin-bottom: 16px;
}

/* 列表 - 更精致的样式 */
.chat-message ul {
  list-style-type: '• ';
  padding-left: 24px;
}

.chat-message ol {
  padding-left: 24px;
}

/* 代码块 - 更专业的语法高亮样式 */
.chat-message pre {
  background-color: #1e293b;
  color: #f8fafc;
  border-radius: 8px;
  font-family: 'SF Mono', Menlo, monospace;
  font-size: 14px;
  line-height: 1.5;
  margin: 16px 0;
}

/* 内联代码 - 更突出的样式 */
.chat-message code:not(pre code) {
  background-color: #f3f4f6;
  color: #dc2626;
  border-radius: 4px;
  font-size: 90%;
}

/* 链接 - 更明显的交互效果 */
.chat-message a {
  color: #2563eb;
  text-decoration: none;
  font-weight: 500;
  transition: color 0.2s;
}

.chat-message a:hover {
  color: #1d4ed8;
  text-decoration: underline;
}

/* 表格样式 - 新增 */
.chat-message table {
  width: 100%;
  border-collapse: collapse;
  margin: 16px 0;
}

.chat-message th,
.chat-message td {
  padding: 12px;
  border: 1px solid #e5e7eb;
}

.chat-message th {
  background-color: #f3f4f6;
}

/* 引用样式 - 新增 */
.chat-message blockquote {
  border-left: 4px solid #2563eb;
  background-color: #f8fafc;
  padding: 12px 16px;
  margin: 16px 0;
  color: #4b5563;
}
jsx 复制代码
import React from 'react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import './markdownStyles.css';

const ChatMessage = ({ message, role }) => {
  return (
    role === 'assistant' ?
      <div className="chat-message">
        <ReactMarkdown remarkPlugins={[remarkGfm]}>
          {message}
        </ReactMarkdown>
      </div> :
      <div className="user-message">
        {message}
      </div>
  );
};

export default ChatMessage;

处理代码块

输入npm install highlight.js

输入npm install rehype-highlight

为了让代码在聊天界面中有不同颜色的高亮显示,你可以使用 rehype-highlight 插件,它可以帮助你实现代码块的语法高亮。

为了在代码块中实现更美观、更细致的代码高亮效果,我们可以使用 highlight.js 库。highlight.js 是一个流行的语法高亮库,支持多种编程语言。

rehype-highlighthighlight.js引入组件

jsx 复制代码
import React from 'react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import rehypeHighlight from 'rehype-highlight';
import hljs from 'highlight.js';
import './code.css';//引入代码段的css样式
import './markdownStyles.css';



const highlightCode = (node) => {//处理代码段的函数
  if (node.tagName === 'pre') {
    const codeNode = node.children[0];
    if (codeNode.tagName === 'code') {
      const language = codeNode.properties.className?.[0]?.replace('language-', '');
      if (language && hljs.getLanguage(language)) {
        const highlightedCode = hljs.highlight(codeNode.children[0].value, { language }).value;
        codeNode.children[0].value = highlightedCode;
      }
    }
  }
  return node;
};

const ChatMessage = ({ message, role }) => {
  return role === 'user' ? (
    <div>{message}</div>
  ) : (
    <div className="chat-message">
      <ReactMarkdown
        remarkPlugins={[remarkGfm]}
        rehypePlugins={[rehypeHighlight, () => highlightCode]}
      >
        {message}
      </ReactMarkdown>
    </div>
  );
};

export default ChatMessage;

这是样式code.css,来源于highlight.js/styles/atom-one-dark.css做出了一点修改,让代码块不是很突兀

css 复制代码
pre code.hljs {
  display: block;
  overflow-x: auto;
  border-radius: 1em;
  padding: 1em;
}

code.hljs {
  padding: 3px 5px
}

/*

Atom One Dark by Daniel Gamage
Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax

base:    #282c34
mono-1:  #abb2bf
mono-2:  #818896
mono-3:  #5c6370
hue-1:   #56b6c2
hue-2:   #61aeee
hue-3:   #c678dd
hue-4:   #98c379
hue-5:   #e06c75
hue-5-2: #be5046
hue-6:   #d19a66
hue-6-2: #e6c07b

*/
.hljs {
  color: #abb2bf;
  background: #282c34
}

.hljs-comment,
.hljs-quote {
  color: #5c6370;
  font-style: italic
}

.hljs-doctag,
.hljs-keyword,
.hljs-formula {
  color: #c678dd
}

.hljs-section,
.hljs-name,
.hljs-selector-tag,
.hljs-deletion,
.hljs-subst {
  color: #e06c75
}

.hljs-literal {
  color: #56b6c2
}

.hljs-string,
.hljs-regexp,
.hljs-addition,
.hljs-attribute,
.hljs-meta .hljs-string {
  color: #98c379
}

.hljs-attr,
.hljs-variable,
.hljs-template-variable,
.hljs-type,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-number {
  color: #d19a66
}

.hljs-symbol,
.hljs-bullet,
.hljs-link,
.hljs-meta,
.hljs-selector-id,
.hljs-title {
  color: #61aeee
}

.hljs-built_in,
.hljs-title.class_,
.hljs-class .hljs-title {
  color: #e6c07b
}

.hljs-emphasis {
  font-style: italic
}

.hljs-strong {
  font-weight: bold
}

.hljs-link {
  text-decoration: underline
}

在安装的highlight.js库中有许多代码块的样式,可以直接引用或者稍作修改后引入,我是稍微修改后放入code.css然后引入的 这是最后的成品

结语

如果有什么问题可以随时问我,我很高兴帮忙解决你的问题。

相关推荐
fanstuck1 小时前
从知识图谱到精准决策:基于MCP的招投标货物比对溯源系统实践
人工智能·知识图谱
@PHARAOH1 小时前
HOW - 在 Mac 上的 Chrome 浏览器中调试 Windows 场景下的前端页面
前端·chrome·macos
dqsh061 小时前
树莓派5+Ubuntu24.04 LTS串口通信 保姆级教程
人工智能·python·物联网·ubuntu·机器人
打小就很皮...2 小时前
编写大模型Prompt提示词方法
人工智能·语言模型·prompt
Aliano2172 小时前
Prompt(提示词)工程师,“跟AI聊天”
人工智能·prompt
weixin_445238122 小时前
第R8周:RNN实现阿尔兹海默病诊断(pytorch)
人工智能·pytorch·rnn
KingDol_MIni2 小时前
ResNet残差神经网络的模型结构定义(pytorch实现)
人工智能·pytorch·神经网络
月月大王3 小时前
easyexcel导出动态写入标题和数据
java·服务器·前端
新加坡内哥谈技术3 小时前
亚马逊推出新型仓储机器人 Vulcan:具备“触觉”但不会取代人类工人
人工智能
Alter12303 小时前
从一城一云到AI CITY,智慧城市进入新阶段
人工智能·智慧城市