Hello~ ProChat 1.0 : 会话组件中 的“亿” 点点细节

简介: Hello~ ProChat 1.0 : 会话组件中 的“亿” 点点细节

本文来源:支付宝体验科技公众号




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 则给了用户一个新的选择:直接改它!

image.png


是的没错,在我们这大半年的实践中,我们发现可编辑的 AI 消息,对于用户操作的便捷性与易用度来说都非常有用,体验上更是能有一个巨大的体验。


与此同时,懂行的同学估计也知道,在 Chat 组件中实现可编辑消息的难度和复杂度,也比单纯的展示消息要高出很多。


而这正是 ProChat 的交互前瞻性与技术先进性的体现。


  快速上手


好了,既然看了那么多 ProChat 的,那我们就看看如何快速上手使用吧!


安装 & 使用


直接使用 tnpm 进行安装,如果是非内部使用,也可以用 pnpmyarnbun 这类进行安装


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 + 通义千问


程序化控制


如果你需要使用程序化的方式控制,我们还提供了 chatRefuseProChat 两种方式,供你获取 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>
  );
};


image.png


针对更加复杂的场景,使用 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>
);


image.png 注意:useProChat hooks 必须在包裹 ProChatProvider 后方可使用。


  开源地址 & 联系我们



接下去的一段时间,我们会继续根据用户反馈持续优化产品体验,修复和完善产品功能。

相关文章
聊天框(番外篇)—如何实现@功能的整体删除
上一篇文章中,我们已经初步实现了聊天输入框,但其@功能是不完善的,例如无法整体删除、无法获取除用户名以外的数据(假设用户名不是唯一的)。有问题就要想办法解决,在网上百度了一圈后,倒是有一些收获。本文就着重解决@的整体删除以及获取额外数据。
1104 0
聊天框(番外篇)—如何实现@功能的整体删除
|
存储 小程序 前端开发
【易售小程序项目】小程序私聊页面完善(带尾巴聊天气泡组件封装、滑至顶端获取历史聊天数据逻辑优化)【后端基于若依管理系统开发】
【易售小程序项目】小程序私聊页面完善(带尾巴聊天气泡组件封装、滑至顶端获取历史聊天数据逻辑优化)【后端基于若依管理系统开发】
63 0
|
Java
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏20之enemy被攻击显示后退动画(block效果)
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏20之enemy被攻击显示后退动画(block效果)
164 0
|
存储 监控 安全
万字长文 | 微软“刷新”的背后,Satya未讲的另一半故事
2018年的最后一天,微软以7798亿美元市值,超过苹果的7491亿美元以及亚马逊的7344亿美元市值,而跃居全球最高市值公司,并以这个记录结束了整个2018年。就在2013年前任微软CEO Steve Ballmer宣布要退休的时候,业界认为微软已经在移动互联网和智能手机时代落后,对于微软的前景并不乐观。然而,就在2014年2月Satya Nadella上任新CEO后,微软出现了巨大变化,在云计算时代迎头赶上,并在短短4年里创造了新的辉煌。
301 0
万字长文 | 微软“刷新”的背后,Satya未讲的另一半故事
|
Web App开发
移动端基础事件和交互(未完待续)
移动端基础事件和交互
1286 0
|
存储 安全 搜索推荐
推给我的广告都跟我最近看的内容有关系,怎么做到的?
互联网的商业模式,商业化变现不外乎后向收费的广告模式,以及面向最终消费者的前向收费模式。广告尤其是重头。就连淘宝天猫的模式本质上也是赚的广告的钱。那么,大数据在广告中是如何起作用的?
|
数据库
【自然框架】之鼠标点功能现(一):单表的增删改查(即上次5月23日活动的一个主题)【Demo、源码下载】
简单的需求,点点鼠标就可以了,那么复杂的需求呢?还是要写代码,哈哈。 不要被我误导了哦,关于什么时候写代码的问题,请看这里:http://www.cnblogs.com/jyk/archive/2009/06/21/1507594.html    单表的增删改查         我有一个梦想,那就是不用敲代码,只需要点点鼠标,就可以实现客户的需求。
1125 0
|
数据库
【自然框架 免费视频】资源角色的思路介绍(整理了一下以前帖子的目录,请刷新)
  请大家不要忘记点推荐!    源码下载: 自然框架的源代码、Demo、数据库、配置信息管理程序下载     这里介绍一下资源权限的思路,我们来设计一个场景,这个场景大家比较常见的,也是我遇到过的。
1293 0
|
Android开发 Windows iOS开发
第二十五章:页面变化(六)
使用ItemTemplateTabbedPage还可用于呈现小数据集,每个数据集是由选项卡标识的单独页面。 您可以通过设置TabbedPage的ItemsSource属性并指定用于呈现每个页面的ItemTemplate来完成此操作。
558 0
|
JavaScript Android开发 iOS开发
第二十五章:页面变化(五)
TabbedPage TabbedPage派生自抽象类MultiPage 。它维护一个Page类型的子集合,其中只有一个一次完全可见。 TabbedPage通过页面顶部或底部的一系列选项卡标识每个子项。
497 0