本文来源:支付宝体验科技公众号
ProChat 官网地址直达:https://pro-chat.antdigital.dev/
嗨~TechUI 的家人们,欢迎来到 TechUI 的冬季产品发布稿现场!今天我们将带给你们一点有趣又实用的东西 😎 —— ProChat 1.0。
正如预告所言,今年最火 🔥 的技术是什么?想必回答一定会是大模型。而我们所做的 ProChat 正是一款开箱即用的大模型对话前端解决方案,提供类 ProTable 的 request
接口和 useProChat
等方便的编程式操作控制,帮助你用 80 行代码 3 分钟 快速搭建 AI 对话产品。
当然,现在市面上已经有很多大模型的前端解决方案了,你可能会问,为什么我要使用 ProChat ,它有什么优势吗?而这个答案,也就在本文的标题中 —— 因为我们所关注的“亿”点点细节。我知道,“亿”这个字眼可能会让人觉得太过庞大和遥不可及,但在 ProChat 里,每一个“小细节”都值得被放大镜仔细端详。
让我们开始吧!
ProChat 体验细节
默认的流式输出支持
由 ChatGPT 率先实现的流式输出在用户体验上远超传统的 HTTP 请求,SSE(Server Send Event)这项技术也可以说正式登上了主流技术圈的视野中。ProChat 作为 AI 会话的前端解决方案,自然默认集成了这项流式输出的能力。
只需要在 request
中配置一个返回流式文本的 Response
(Web标准的 Response 对象),就可以轻松实现流式效果的集成。
import { ProChat } from '@ant-design/pro-chat'; import { MockResponse } from '../mocks/streamResponse'; export default () => { const theme = useTheme(); return ( <ProChat request={async (messages) => { const mockedData: string = `这是一段模拟的流式字符串数据。本次会话传入了${messages.length}条消息`; const mockResponse = new MockResponse(mockedData, 50); return mockResponse.getResponse(); }} /> ); };
效果如下:
而同样的,ProChat 的 request
api 也兼容传统的非流式请求:
/** * description: 消息将在等待 5s 后返回 */ import { ProChat } from '@ant-design/pro-chat'; const delay = (text: string) => new Promise<string>((resolve) => { setTimeout(() => { resolve(text); }, 5000); }); export default () => { return ( <ProChat request={async (messages) => { const text = await delay( `这是一条模拟非流式输出的消息的消息。本次会话传入了${messages.length}条消息`, ); return new Response(text); }} style={{ height: '100vh' }} /> ); };
完备的 Markdown、代码块展示
大模型可以通过 Markdown 的语法输出格式化的文本,因此 Markdown 的展示与渲染是一个AI会话组件必不可少的模块。ProChat 中已经完整支持基础的 Markdown 语法,并增强支持了代码块、LaTeX 数学公式等特性。完整效果一览如下:
其中我们特别优化了代码块的交互与体验。
其中:针对单行代码,我们使之更加贴近命令行执行风格,以符合常见的代码块使用习惯。
而针对多行代码块,我们则强化了代码块组件的交互能力,使之具有折叠展开、更换高亮语言等进阶功能,进而帮助你在日常使用 AI 大模型中更好地查看AI生成的代码。
当然,如果你希望在其他场景使用如此丰富与强大的 Markdown 与代码块组件,完全没有问题!ProChat 的 Markdown 语法高亮和代码块借助了 ProEditor 的 Markdown 组件 与 Highlight 组件 得以实现。而你也可以轻松地在你的项目中集成与使用。
会话消息的编辑与重新发送
如果经常使用 AI 大模型会话的同学,应该经常会感受到有时候大模型的输出存在一些瑕疵,导致体验极其不好。譬如上述的代码块场景。能够展示代码块的前提是 ai 标记输出了代码块的语法。但如果此时 AI 直接输出了纯文本,连代码块都没有呈现,请问阁下又该如何应对?
如果你在使用 ChatGPT ,那么你唯一能做的就只是让 AI 包含 Markdown 格式进行重新输出。这个体验并不理想。
而 ProChat 则给了用户一个新的选择:直接改它!
是的没错,在我们这大半年的实践中,我们发现可编辑的 AI 消息,对于用户操作的便捷性与易用度来说都非常有用,体验上更是能有一个巨大的体验。
与此同时,懂行的同学估计也知道,在 Chat 组件中实现可编辑消息的难度和复杂度,也比单纯的展示消息要高出很多。
而这正是 ProChat 的交互前瞻性与技术先进性的体现。
快速上手
好了,既然看了那么多 ProChat 的,那我们就看看如何快速上手使用吧!
安装 & 使用
直接使用 tnpm
进行安装,如果是非内部使用,也可以用 pnpm
、yarn
、bun
这类进行安装
tnpm install @ant-design/pro-chat --save tnpm install @ant-design/antd-style --save
依赖需求
peerDependencies: { "antd": "^5", "antd-style": "^3", "react": "^18" }
组件使用如下:最简单的情况下,你只需要一个 Request 的 Api 就可以了,详细使用和参考可以看下面的内容。
<ProChat request={async (messages) => { // request 发送,Mesaage 作为 参数传入 return Response; // 支持流式 & 非流式 }} />
80 行 3 分钟接入通义千问大模型
这是一个快速接入通义千问的例子,这里展示的是 NextJs 项目,如果是 umi 的话,需要一个服务端,目前通义千问还不支持客户端请求(OpenAI 是支持的)
import { ProChat } from '@ant-design/pro-chat'; export default () => { return ( <ProChat style={{ height: "100vh", width: "100vw", }} request={async (messages) => { const response = await fetch("/api/qwen", { method: "POST", body: JSON.stringify({ messages: messages }), }); const data = await response.json(); return new Response(data.output?.text); }} /> ); };
import { NextResponse } from "next/server"; export async function POST(request: Request) { const { messages = [] }: Partial<{ messages: Array<any> }> = await request.json(); try { const apiKey = "Your-Api-Key"; // 你的 API 密钥 const response = await fetch( "https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation", { method: "POST", headers: { Authorization: "Bearer " + apiKey, "Content-Type": "application/json", }, body: JSON.stringify({ model: "qwen-turbo", input: { messages: [ { role: "system", content: "You are a helpful assistant.", }, ...messages, ], }, parameters: {}, }), } ); const data = await response.json(); return NextResponse.json(data); } catch (error) { return NextResponse.error(); } }
因为我们担心使用个人 Key 给大家体验会有些奇怪的问题,我们结合 CodeFuse 的通义千问接口,给大家搭建了这样一个体验地址,后续会在 TechUI Studio 中持续完善,请关注我们。👇 戳我体验 ProChat + 通义千问
程序化控制
如果你需要使用程序化的方式控制,我们还提供了 chatRef
和 useProChat
两种方式,供你获取 proChat 实例,进而实现程序化控制:
import { ProChat, ProChatInstance } from '@ant-design/pro-chat'; import { useRef } from 'react'; import { Button } from 'antd'; import { MockResponse } from '@/ProChat/mocks/streamResponse'; import { example } from '../mocks/basic'; export default () => { const proChatRef = useRef<ProChatInstance>(); return ( <div> <Button type={'primary'} onClick={() => { if (!proChatRef.current) return; const messages = proChatRef.current.getChatMessages(); const { id, content } = messages[0] || {}; if (!id) return; proChatRef.current.setMessageContent(id, content + '👋'); }} > 修改首条消息,添加表情:👋 </Button> <ProChat initialChats={example.chats} chatRef={proChatRef} request={async (messages) => { const mockedData: string = `这是一段模拟的流式字符串数据。本次会话传入了${messages.length}条消息`; const mockResponse = new MockResponse(mockedData, 100); return mockResponse.getResponse(); }} /> </div> ); };
针对更加复杂的场景,使用 useProChat
hooks 来获取 proChat 实例对象,进而实现更加丰富的业务逻辑:
import { ProChat, ProChatProvider, useProChat } from '@ant-design/pro-chat'; const Control = () => { const proChat = useProChat(); return ( <Flex style={{ padding: 24 }} gap={8} justify={'space-between'}> <Flex gap={8}> <Button type={'primary'} onClick={() => { proChat.sendMessage('这是程序化发送的消息'); }} > 发送一条消息 </Button> <Button onClick={() => { const messages = proChat.getChatMessages(); const msg = messages.at(-1); if (msg) { message.info(msg.content); } else { message.warning('会话为空'); } }} > 获取最新会话消息 </Button> </Flex> <Button onClick={() => { const messages = proChat.getChatMessages(); const { id, content } = messages[0] || {}; if (!id) return; proChat.setMessageContent(id, content + '👋'); }} > 修改首条消息,添加表情:👋 </Button> <Flex gap={8}> <Button danger onClick={() => { const messages = proChat.getChatMessages(); proChat.deleteMessage(messages[0].id); message.success('已删除第一条消息'); }} > 删除第一条消息 </Button> <Button type={'primary'} danger onClick={() => { proChat.clearMessage(); }} > 清空消息 </Button> </Flex> </Flex> ); }; export default () => ( <ProChatProvider initialChats={example.chats}> <Control /> <Divider>🔼 程序化控制 | 🔽 用户控制</Divider> <Chat /> </ProChatProvider> );
注意:useProChat
hooks 必须在包裹 ProChatProvider 后方可使用。
开源地址 & 联系我们
- ProChat 官网:https://pro-chat.antdigital.dev
- Github:https://github.com/ant-design/pro-chat
接下去的一段时间,我们会继续根据用户反馈持续优化产品体验,修复和完善产品功能。