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


是的没错,在我们这大半年的实践中,我们发现可编辑的 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>
  );
};


针对更加复杂的场景,使用 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 后方可使用。


  开源地址


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

相关文章
|
8月前
|
存储 小程序 前端开发
【易售小程序项目】小程序私聊页面完善(带尾巴聊天气泡组件封装、滑至顶端获取历史聊天数据逻辑优化)【后端基于若依管理系统开发】
【易售小程序项目】小程序私聊页面完善(带尾巴聊天气泡组件封装、滑至顶端获取历史聊天数据逻辑优化)【后端基于若依管理系统开发】
36 0
|
11月前
|
前端开发 NoSQL Redis
项目实战典型案例5——发送调查问卷流程图例子(将不必要的逻辑放入前端)
项目实战典型案例5——发送调查问卷流程图例子(将不必要的逻辑放入前端)
84 0
聊天框(番外篇)—如何实现@功能的整体删除
上一篇文章中,我们已经初步实现了聊天输入框,但其@功能是不完善的,例如无法整体删除、无法获取除用户名以外的数据(假设用户名不是唯一的)。有问题就要想办法解决,在网上百度了一圈后,倒是有一些收获。本文就着重解决@的整体删除以及获取额外数据。
979 0
聊天框(番外篇)—如何实现@功能的整体删除
|
前端开发
前端工作总结244-修改其他页面的时间逻辑
前端工作总结244-修改其他页面的时间逻辑
69 0
|
存储 安全 搜索推荐
推给我的广告都跟我最近看的内容有关系,怎么做到的?
互联网的商业模式,商业化变现不外乎后向收费的广告模式,以及面向最终消费者的前向收费模式。广告尤其是重头。就连淘宝天猫的模式本质上也是赚的广告的钱。那么,大数据在广告中是如何起作用的?
|
数据库
【自然框架】之鼠标点功能现(一):单表的增删改查(即上次5月23日活动的一个主题)【Demo、源码下载】
简单的需求,点点鼠标就可以了,那么复杂的需求呢?还是要写代码,哈哈。 不要被我误导了哦,关于什么时候写代码的问题,请看这里:http://www.cnblogs.com/jyk/archive/2009/06/21/1507594.html    单表的增删改查         我有一个梦想,那就是不用敲代码,只需要点点鼠标,就可以实现客户的需求。
1107 0
|
Android开发 Windows iOS开发
第二十五章:页面变化(六)
使用ItemTemplateTabbedPage还可用于呈现小数据集,每个数据集是由选项卡标识的单独页面。 您可以通过设置TabbedPage的ItemsSource属性并指定用于呈现每个页面的ItemTemplate来完成此操作。
538 0
|
JavaScript Android开发 iOS开发
第二十五章:页面变化(五)
TabbedPage TabbedPage派生自抽象类MultiPage 。它维护一个Page类型的子集合,其中只有一个一次完全可见。 TabbedPage通过页面顶部或底部的一系列选项卡标识每个子项。
480 0
|
JavaScript Android开发 iOS开发
第二十五章:页面变化(四)
您自己的用户界面如果您想提供自己的用户界面以在主视图和详细视图之间切换,您可能还希望禁用MasterDetailPage自动提供的界面。您可以通过两种方式执行此操作: 将IsGestureEnabled属性设置为false以禁用iOS和Android上的滑动手势支持。
578 0

热门文章

最新文章