一、Ant Design X 是什么?
Ant Design X,即@ant-design/x,是遵循 Ant Design 设计体系的 React UI 库 ,旨在构建 AI 驱动的界面,能一键接入智能对话组件与 API 服务。在人工智能技术蓬勃发展的当下,AI 驱动的应用越来越多,像智能客服、智能写作助手、智能图像生成工具等。开发这类应用时,构建一个高效、美观且用户体验良好的界面至关重要。Ant Design X 的出现,极大地简化了 AI 界面的开发流程。它就像是一个装满各种开发 "零件" 的工具箱,开发者无需从头开始打造每一个界面元素,直接使用 Ant Design X 提供的组件,就能快速搭建出功能丰富的 AI 交互界面,大大节省开发时间和精力。
二、搭建前的准备工作
(一)环境要求
在使用 Ant Design X 搭建 AI 交互界面之前,需要确保开发环境满足以下要求:
- Node.js:建议使用 Node.js 14.0.0 及以上版本 ,以获得更好的兼容性和性能。Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时,它允许开发者在服务器端运行 JavaScript 代码,为前端开发提供了强大的支持。
- React 和 React - DOM:React 17.0.0 及以上版本,React - DOM 也需要相应的版本,它们是构建用户界面的核心库,提供了创建和管理 UI 组件的能力。
- 包管理器:可以选择 npm(Node Package Manager)、yarn 或 pnpm。npm 是 Node.js 默认的包管理器,yarn 和 pnpm 则在性能和依赖管理方面有各自的优势,开发者可以根据项目需求和个人喜好进行选择。
(二)安装 Ant Design X
使用包管理器安装 Ant Design X 非常简单,以下是通过 npm、yarn、pnpm 安装的具体命令:
- npm:npm install @ant-design/x --save
- yarn:yarn add @ant-design/x
- pnpm:pnpm add @ant-design/x
安装完成后,Ant Design X 及其依赖项就会被下载到项目的node_modules目录中。
(三)引入组件和工具
在项目中引入 Ant Design X 的组件和钩子工具也很方便。以一个简单的 React 组件为例,假设我们要使用Bubble(消息气泡)、Sender(发送框)组件,以及useXAgent(模型调度钩子)、useXChat(数据管理钩子)工具,可以这样引入:
javascript
import React from'react';
import { Bubble, Sender, useXAgent, useXChat } from '@ant-design/x';
通过这样的方式,就可以在组件中使用这些功能强大的组件和工具,为搭建 AI 交互界面做好准备。
三、RICH 设计范式解析
Ant Design X 提出了独特的 RICH 设计范式,为 AI 交互界面的设计提供了清晰的指导思路,涵盖意图(Intention)、角色(Role)、会话(Conversation)和混合界面(Hybrid UI)四个核心要素。
(一)意图(Intention)
在 AI 交互中,明确用户意图至关重要。用户使用 AI 工具时,意图可能清晰,如让 AI 帮忙修改文档中的一段文字;也可能模糊,比如只是想了解某个领域的一些信息 。意图还可分为任务型,像完成一份项目策划;和咨询型,例如询问某个概念的含义。Ant Design X 通过提供引导性的提示和交互组件,帮助用户明确意图。比如在搜索框旁边设置一些热门搜索关键词或相关问题的示例,当用户不知道如何表达需求时,点击这些示例就能快速发起相关询问,让 AI 理解用户的大致方向,从而提供更准确的服务。
(二)角色(Role)
为 AI 设定不同角色能显著提升交互体验。在帮助中心,AI 可扮演亲和力强的客服角色,语言风格亲切、热情,使用诸如 "亲,有什么问题都可以问我哦" 这样的表述 ;在 BI 数据分析模块,AI 则扮演专业的数据分析师角色,使用专业术语,如 "根据这些数据的标准差和方差分析,我们可以得出......"。Ant Design X 提供了丰富的组件和配置选项来实现角色设计。可以通过设置 AI 的头像、语言风格、语气等方面来塑造角色形象。选择一个微笑的卡通形象作为帮助中心 AI 的头像,搭配温暖的语言,让用户感受到友好;而在专业分析场景中,使用简洁、严肃的界面风格和专业的图标,展现 AI 的专业性。
(三)会话(Conversation)
利用 Ant Design X 组件能有效管理对话流程和处理对话状态。在对话开始时,使用欢迎组件,如,向用户展示友好的问候和简单介绍,让用户快速了解 AI 的功能 。当用户提问后,AI 可能需要追问一些细节以更好地理解问题,此时可以通过特定的提示组件,如,给出追问的选项。在对话过程中,如果用户需要一些提示来继续对话,Ant Design X 的提示组件也能派上用场,提供相关的建议或引导。比如在用户与写作助手 AI 对话时,当用户思路中断,提示组件可以给出一些写作方向的建议,如 "可以从描述事件的起因开始"。
(四)混合界面(Hybrid UI)
Ant Design X 支持将多种交互模式融合,构建混合界面。在一个智能办公应用中,用户既可以通过传统的图形界面操作,如点击按钮、选择菜单来执行任务;也可以通过与 AI 对话的方式,让 AI 完成一些复杂的操作 。比如用户想要生成一份会议纪要,既可以在文档编辑界面手动输入内容,也可以直接对 AI 说 "帮我生成一份关于昨天会议的纪要,重点包括讨论的问题和决策结果"。Ant Design X 通过提供灵活的布局组件和交互组件,实现了这种混合界面的构建。开发者可以根据项目需求,将对话组件、操作按钮、信息展示区域等进行合理组合,为用户提供便捷、高效的交互体验。
四、核心组件实战
(一)消息气泡(Bubble)
消息气泡(Bubble)组件在 AI 交互界面中用于显示对话消息,就像我们日常使用的聊天软件中的聊天气泡一样,能让对话内容以直观、清晰的方式呈现。使用时,需先从@ant-design/x中引入Bubble组件:
javascript
import { Bubble } from '@ant-design/x';
在实际应用中,通常会将消息存储在一个数组中,每个消息对象包含content(消息内容)和role(角色,如user或ai)等属性。比如:
ini
const messages = [
{ content: '你好,今天天气如何?', role: 'user' },
{ content: '今天天气晴朗,适合外出活动。', role: 'ai' }
];
然后,通过Bubble.List组件来渲染这些消息:
ini
<Bubble.List items={messages}>
{({ item }) => (
<Bubble
key={item.id}
placement={item.role === 'user'? 'end' :'start'}
content={item.content}
avatar={item.role === 'user'? { icon: <UserOutlined /> } : { icon: <RobotOutlined /> }}
/>
)}
</Bubble.List>
在这段代码中,placement属性根据消息的角色设置气泡的位置,用户消息在右侧(end),AI 消息在左侧(start);avatar属性设置消息发送者的头像,使用UserOutlined图标表示用户,RobotOutlined图标表示 AI。通过这些设置,能让用户清晰地区分不同角色的消息,提升交互体验。
(二)输入框(Sender)
输入框(Sender)组件是用户与 AI 进行交互的重要入口,用户在此输入问题或指令,然后提交给 AI 进行处理。首先引入Sender组件:
javascript
import { Sender } from '@ant-design/x';
为了处理用户输入和提交请求,需要定义一些状态和函数。例如,使用 React 的useState钩子来管理输入框的值和提交状态:
javascript
import React, { useState } from'react';
const [inputValue, setInputValue] = useState('');
const [isLoading, setIsLoading] = useState(false);
const handleSubmit = (value) => {
setIsLoading(true);
// 模拟向AI发送请求
setTimeout(() => {
setIsLoading(false);
// 这里可以处理AI返回的结果
console.log('AI response:', value);
}, 2000);
setInputValue('');
};
在Sender组件中,通过value属性绑定输入框的值,onChange事件处理函数更新输入框的值,onSubmit事件处理函数在用户点击提交按钮或按下回车键时触发,将用户输入的值传递给handleSubmit函数进行处理,loading属性用于控制输入框是否显示加载状态:
ini
<Sender
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onSubmit={handleSubmit}
loading={isLoading}
/>
这样,用户在输入框中输入内容并提交后,就能与 AI 进行交互,输入框还会在请求处理过程中显示加载状态,让用户了解交互的进展。
(三)提示集(Prompts)
提示集(Prompts)组件提供了预定义问题或建议,能引导用户与 AI 进行交互,尤其适用于用户不知道如何提问或需要一些灵感的情况。引入Prompts组件:
javascript
import { Prompts } from '@ant-design/x';
定义提示集的内容,每个提示对象包含key(唯一标识)、label(显示的文本)和description(描述信息)等属性:
ini
const promptsItems = [
{
key: '1',
label: '热门电影推荐',
description: '请AI推荐近期热门电影'
},
{
key: '2',
label: '旅游景点推荐',
description: '让AI推荐国内热门旅游景点'
}
];
在组件中使用Prompts组件,并通过onItemClick事件处理函数处理用户点击提示的操作,比如将提示的描述信息作为用户输入发送给 AI:
ini
<Prompts
items={promptsItems}
onItemClick={(info) => {
// 处理用户点击提示的逻辑,这里可以将提示信息发送给AI
console.log('User clicked prompt:', info.data.description);
}}
/>
这样,用户在界面上可以看到这些预定义的提示,点击提示就能快速发起相关的询问,降低用户的输入门槛,提高交互效率。
(四)会话管理(Conversations)
会话管理(Conversations)组件用于管理多个会话,方便用户查看历史会话记录,在多轮对话或需要保存对话记录的场景中非常实用。引入Conversations组件:
javascript
import { Conversations } from '@ant-design/x';
定义会话列表的数据,每个会话对象包含key(唯一标识)和label(显示的名称)等属性:
ini
const conversationsItems = [
{
key: '1',
label: '与AI讨论工作安排'
},
{
key: '2',
label: '向AI咨询学习方法'
}
];
使用Conversations组件展示会话列表,并通过onActiveChange事件处理函数处理用户切换会话的操作,比如根据用户选择的会话加载相应的历史消息:
ini
<Conversations
items={conversationsItems}
onActiveChange={(key) => {
// 处理用户切换会话的逻辑,这里可以根据key加载相应的历史消息
console.log('User switched to conversation:', key);
}}
/>
通过这样的方式,用户可以在不同的会话之间进行切换,随时查看之前与 AI 的交流内容,方便回顾和继续之前的话题,提升了 AI 交互的连贯性和便捷性。
五、模型集成与数据流管理
(一)模型调度(useXAgent)
在 AI 交互界面开发中,模型调度是至关重要的环节,它负责管理和调度 AI 模型,确保模型能够高效、准确地处理用户请求。Ant Design X 提供的useXAgent钩子在模型调度方面发挥着关键作用。useXAgent钩子允许开发者通过一个Agent对象来管理和调度不同的 AI 模型,它提供了简洁的接口来处理模型请求和响应,使得集成和使用 AI 模型变得更加简单。
以对接 Qwen 模型为例,具体代码实现如下:
typescript
import React from'react';
import { useXAgent, Sender, XRequest } from '@ant-design/x';
const { create } = XRequest({
baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',// Qwen模型的请求地址
dangerouslyApiKey: process.env['DASHSCOPE_API_KEY'],// 阿里云DashScope平台的API密钥,从环境变量中获取
model: 'qwen-plus'// 使用的Qwen模型版本
});
const Component: React.FC = () => {
const [agent] = useXAgent({
request: async (info, callbacks) => {
const { messages, message } = info;
const { onUpdate } = callbacks;
let content: string = '';
try {
create({
messages: [
{
role: 'user',
content: message
}
],
stream: true
}, {
onSuccess: (chunks) => {
console.log('sse chunk list', chunks);
},
onError: (error) => {
console.log('error', error);
},
onUpdate: (chunk) => {
console.log('sse object', chunk);
const data = JSON.parse(chunk.data);
content += data?.choices[0].delta.content;
onUpdate(content);
}
});
} catch (error) {
// 处理错误
}
}
});
function onRequest(message: string) {
agent.request({ message }, {
onUpdate: () => { },
onSuccess: () => { },
onError: () => { }
});
}
return <Sender onSubmit={onRequest} />;
};
export default Component;
在这段代码中,首先通过XRequest创建了一个请求对象create,配置了 Qwen 模型的请求地址、API 密钥和模型版本。然后在useXAgent中定义了request函数,当接收到用户消息时,通过create函数向 Qwen 模型发起请求。模型返回的结果通过onUpdate回调函数进行处理,实时更新对话内容。最后,在Sender组件的onSubmit事件中调用onRequest函数,将用户输入的消息发送给模型进行处理。通过这样的方式,实现了使用useXAgent钩子对接 Qwen 模型,完成模型调度的功能。
(二)数据管理(useXChat)
数据管理在 AI 交互界面中同样不可或缺,它主要负责管理会话数据,并产出供页面渲染使用的数据,确保对话数据流的有序处理和展示。Ant Design X 的useXChat钩子极大地简化了这一过程,让开发者可以专注于构建用户界面,而不必过多担心底层的数据逻辑。useXChat钩子通过与useXAgent配合,实现了会话数据的高效管理。它可以处理对话的各种状态,如加载中、成功、失败等,并将处理后的数据传递给页面组件进行渲染。
以对接 OpenAI 服务为例,代码实现如下:
typescript
import React from'react';
import { useXAgent, useXChat, Sender, Bubble } from '@ant-design/x';
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: process.env['OPENAI_API_KEY'],
dangerouslyAllowBrowser: true
});
const Demo: React.FC = () => {
const [agent] = useXAgent({
request: async (info, callbacks) => {
const { messages, message } = info;
const { onSuccess, onUpdate, onError } = callbacks;
let content: string = '';
try {
const stream = await client.chat.completions.create({
model: 'gpt-4o',
messages: [
{
role: 'user',
content: message
}
],
stream: true
});
for await (const chunk of stream) {
content += chunk.choices[0]?.delta?.content || '';
onUpdate(content);
}
onSuccess(content);
} catch (error) {
// 处理错误
}
}
});
const { onRequest, messages } = useXChat({ agent });
const items = messages.map(({ message, id }) => ({
key: id,
content: message
}));
return (
<div>
<Bubble.List items={items} />
<Sender onSubmit={onRequest} />
</div>
);
};
export default Demo;
在这段代码中,首先创建了 OpenAI 客户端实例,配置了 API 密钥并允许在浏览器环境中使用。在useXAgent的request函数中,向 OpenAI 的gpt - 4o模型发起请求,处理模型返回的流式数据,并通过onUpdate和onSuccess回调函数更新和完成对话内容。useXChat钩子则通过agent对象获取对话数据,messages包含了所有的对话消息,将其映射为适合Bubble.List组件渲染的格式。最后,在页面中通过Bubble.List展示对话消息,Sender组件用于用户输入,实现了完整的数据管理和页面渲染流程。
(三)请求工具(XRequest)
XRequest是 Ant Design X 提供的一个强大的请求工具,专门用于向符合 OpenAI 标准的大语言模型(LLM,Large Language Models)发起请求。它封装了请求的细节,使得开发者可以轻松地与 AI 模型进行交互,无需过多关注底层的网络请求和参数配置。在实际应用中,XRequest简化了与模型通信的过程。开发者只需提供模型的请求地址、API 密钥和模型名称等基本信息,就可以使用XRequest创建请求对象,并通过该对象向模型发送请求。例如,在对接 Qwen 模型时,通过XRequest配置好请求地址、阿里云 DashScope 平台的 API 密钥以及qwen - plus模型名称后,就可以方便地向 Qwen 模型发起请求,获取模型的响应。
XRequest还支持对请求参数的灵活配置,如请求的消息内容、是否使用流式响应等。在与模型交互过程中,开发者可以根据实际需求调整这些参数,以获得更好的交互效果。它为开发者提供了一种便捷、高效的方式来与符合 OpenAI 标准的模型进行通信,大大提升了开发效率和体验。
六、实例实战
(一)源码
react
import {
Attachments,
Bubble,
Conversations,
Prompts,
Sender,
Welcome,
ThoughtChain,
useXAgent,
useXChat,
} from '@ant-design/x';
import { CheckCircleOutlined, CloudUploadOutlined, CommentOutlined, EllipsisOutlined, FireOutlined, HeartOutlined, MoreOutlined, PaperClipOutlined, PlusOutlined, ReadOutlined, ShareAltOutlined, SmileOutlined, UserOutlined } from '@ant-design/icons';
import { createStyles } from 'antd-style';
import { Card, Typography, Space, Button, Flex, type GetProp, Badge } from 'antd';
import React, { useEffect, useState } from 'react';
const { Paragraph, Text } = Typography;
const renderTitle = (icon: React.ReactElement, title: string) => (
<Space align="start">
{icon}
<span>{title}</span>
</Space>
);
const defaultConversationsItems = [
{
key: '0',
label: 'What is Ant Design X?',
},
];
const useStyle = createStyles(({ token, css }) => {
return {
layout: css`
width: 100%;
min-width: 1000px;
height: 100vh;
overflow-y: hidden;
border-radius: ${token.borderRadius}px;
display: flex;
background: ${token.colorBgContainer};
font-family: AlibabaPuHuiTi, ${token.fontFamily}, sans-serif;
.ant-prompts {
color: ${token.colorText};
}
`,
menu: css`
background: ${token.colorBgLayout}80;
width: 280px;
height: 100%;
display: flex;
flex-direction: column;
`,
thoughtChain: css`
background: ${token.colorBgLayout}80;
width: 300px;
height: 100%;
overflow-x: hidden;
overflow-y: scroll;
display: flex;
flex-direction: column;
`,
conversations: css`
padding: 0 12px;
flex: 1;
overflow-y: auto;
`,
chat: css`
height: 100%;
width: 100%;
margin: 0 auto;
box-sizing: border-box;
display: flex;
flex-direction: column;
padding: ${token.paddingLG}px;
gap: 16px;
`,
messages: css`
flex: 1;
`,
placeholder: css`
padding-top: 32px;
`,
sender: css`
box-shadow: ${token.boxShadow};
`,
logo: css`
display: flex;
height: 72px;
align-items: center;
justify-content: start;
padding: 0 24px;
box-sizing: border-box;
img {
width: 24px;
height: 24px;
display: inline-block;
}
span {
display: inline-block;
margin: 0 8px;
font-weight: bold;
color: ${token.colorText};
font-size: 16px;
}
`,
addBtn: css`
background: #1677ff0f;
border: 1px solid #1677ff34;
width: calc(100% - 24px);
margin: 0 12px 24px 12px;
`,
};
});
const placeholderPromptsItems: GetProp<typeof Prompts, 'items'> = [
{
key: '1',
label: renderTitle(<FireOutlined style={{ color: '#FF4D4F' }} />, 'Hot Topics'),
description: 'What are you interested in?',
children: [
{
key: '1-1',
description: `What's new in X?`,
},
{
key: '1-2',
description: `What's AGI?`,
},
{
key: '1-3',
description: `Where is the doc?`,
},
],
},
{
key: '2',
label: renderTitle(<ReadOutlined style={{ color: '#1890FF' }} />, 'Design Guide'),
description: 'How to design a good product?',
children: [
{
key: '2-1',
icon: <HeartOutlined />,
description: `Know the well`,
},
{
key: '2-2',
icon: <SmileOutlined />,
description: `Set the AI role`,
},
{
key: '2-3',
icon: <CommentOutlined />,
description: `Express the feeling`,
},
],
},
];
const senderPromptsItems: GetProp<typeof Prompts, 'items'> = [
{
key: '1',
description: 'Hot Topics',
icon: <FireOutlined style={{ color: '#FF4D4F' }} />,
},
{
key: '2',
description: 'Design Guide',
icon: <ReadOutlined style={{ color: '#1890FF' }} />,
},
];
const roles: GetProp<typeof Bubble.List, 'roles'> = {
ai: {
placement: 'start',
typing: true,
avatar: { icon: <UserOutlined />, style: { background: '#fde3cf' } },
},
suggestion: {
placement: 'start',
avatar: { icon: <UserOutlined />, style: { visibility: 'hidden' } },
variant: 'borderless',
messageRender: (content) => (
<Prompts
vertical
items={(content as any as string[]).map((text) => ({
key: text,
icon: <SmileOutlined style={{ color: '#FAAD14' }} />,
description: text,
}))}
/>
),
},
file: {
placement: 'start',
avatar: { icon: <UserOutlined />, style: { visibility: 'hidden' } },
variant: 'borderless',
messageRender: (items: any) => (
<Flex vertical gap="middle">
{(items as any[]).map((item) => (
<Attachments.FileCard key={item} item={{
uid: '9',
name: 'markdown-file.md',
size: 999999,
description: 'Custom description here',
}} />
))}
</Flex>
),
},
};
type AgentUserMessage = {
type: 'user';
content: string;
};
type AgentAIMessage = {
type: 'ai';
content?: string;
list?: (
| {
type: 'text';
content: string;
}
| {
type: 'suggestion';
content: string[];
}
)[];
};
type AgentMessage = AgentUserMessage | AgentAIMessage;
type BubbleMessage = {
role: string;
};
const Independent: React.FC = () => {
const { styles } = useStyle();
const [headerOpen, setHeaderOpen] = React.useState(false);
const [content, setContent] = React.useState('');
const [conversationsItems, setConversationsItems] = React.useState(defaultConversationsItems);
const [activeKey, setActiveKey] = React.useState(defaultConversationsItems[0].key);
const [attachedFiles, setAttachedFiles] = React.useState<GetProp<typeof Attachments, 'items'>>([]);
const [thoughtChainItems, setThoughtChainItems] = React.useState<GetProp<typeof ThoughtChain, 'items'>>([]);
const sleep = () => new Promise((resolve) => setTimeout(resolve, 1000));
const [agent] = useXAgent<AgentMessage>({
request: async ({ message }, { onSuccess }) => {
await sleep();
const { content } = message || {};
onSuccess({
type: 'ai',
list: [
{
type: 'text',
content: `Do you want?`,
},
{
type: 'suggestion',
content: [`Look at: ${content}`, `Search: ${content}`, `Try: ${content}`],
},
{
type: 'file',
content: [`Look at: ${content}`, `Search: ${content}`, `Try: ${content}`],
},
],
});
// 动态设置思维链
setThoughtChainItems((prevItems) => [
// ...prevItems,
{
title: 'User Input',
description: content,
icon: <CheckCircleOutlined />,
extra: <Button type="text" icon={<MoreOutlined />} />,
footer: <Button block>Thought Chain Item Footer</Button>,
content: (
<Typography>
<Paragraph>
User input: {content}
</Paragraph>
</Typography>
),
},
{
title: 'AI Response',
description: 'AI response description',
icon: <CheckCircleOutlined />,
extra: <Button type="text" icon={<MoreOutlined />} />,
footer: <Button block>Thought Chain Item Footer</Button>,
content: (
<Typography>
<Paragraph>
AI response: Do you want?
</Paragraph>
<Paragraph>
Suggestions: Look at: {content}, Search: {content}, Try: {content}
</Paragraph>
</Typography>
),
},
]);
},
});
const { onRequest, parsedMessages, setMessages } = useXChat<AgentMessage, BubbleMessage>({
agent,
defaultMessages: [
{
id: 'init',
message: {
type: 'ai',
content: 'Hello, what can I do for you?',
},
status: 'success',
},
],
requestPlaceholder: {
type: 'ai',
content: 'Waiting...',
},
parser: (agentMessages) => {
const list = agentMessages.content ? [agentMessages] : (agentMessages as AgentAIMessage).list;
return (list || []).map((msg) => ({
role: msg.type,
content: msg.content,
}));
},
});
useEffect(() => {
if (activeKey !== undefined) {
setMessages([]);
setThoughtChainItems([]);
}
}, [activeKey]);
const onSubmit = (nextContent: string) => {
if (!nextContent) return;
onRequest({
type: 'user',
content: nextContent,
});
setContent('');
};
const onPromptsItemClick: GetProp<typeof Prompts, 'onItemClick'> = (info) => {
onRequest(info.data.description as string);
};
const onAddConversation = () => {
setConversationsItems([
...conversationsItems,
{
key: `${conversationsItems.length}`,
label: `New Conversation ${conversationsItems.length}`,
},
]);
setActiveKey(`${conversationsItems.length}`);
};
const onConversationClick: GetProp<typeof Conversations, 'onActiveChange'> = (key) => {
setActiveKey(key);
};
const handleFileChange: GetProp<typeof Attachments, 'onChange'> = (info) =>
setAttachedFiles(info.fileList);
const placeholderNode = (
<Space direction="vertical" size={16} className={styles.placeholder}>
<Welcome
variant="borderless"
icon="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp"
title="Hello, I'm Ant Design X"
description="Base on Ant Design, AGI product interface solution, create a better intelligent vision~"
extra={
<Space>
<Button icon={<ShareAltOutlined />} />
<Button icon={<EllipsisOutlined />} />
</Space>
}
/>
<Prompts
title="Do you want?"
items={placeholderPromptsItems}
styles={{
list: {
width: '100%',
},
item: {
flex: 1,
},
}}
onItemClick={onPromptsItemClick}
/>
</Space>
);
const attachmentsNode = (
<Badge dot={attachedFiles.length > 0 && !headerOpen}>
<Button type="text" icon={<PaperClipOutlined />} onClick={() => setHeaderOpen(!headerOpen)} />
</Badge>
);
const senderHeader = (
<Sender.Header
title="Attachments"
open={headerOpen}
onOpenChange={setHeaderOpen}
styles={{
content: {
padding: 0,
},
}}
>
<Attachments
beforeUpload={() => false}
items={attachedFiles}
onChange={handleFileChange}
placeholder={(type) =>
type === 'drop'
? { title: 'Drop file here' }
: {
icon: <CloudUploadOutlined />,
title: 'Upload files',
description: 'Click or drag files to this area to upload',
}
}
/>
</Sender.Header>
);
const logoNode = (
<div className={styles.logo}>
<img
src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*eco6RrQhxbMAAAAAAAAAAAAADgCCAQ/original"
draggable={false}
alt="logo"
/>
<span>Ant Design X</span>
</div>
);
return (
<div className={styles.layout}>
<div className={styles.menu}>
{/* Logo */}
{logoNode}
{/* 会话区 */}
<Button
onClick={onAddConversation}
type="link"
className={styles.addBtn}
icon={<PlusOutlined />}
>
New Conversation
</Button>
{/* 对话列表 */}
<Conversations
items={conversationsItems}
className={styles.conversations}
activeKey={activeKey}
onActiveChange={onConversationClick}
/>
</div>
<div className={styles.chat}>
{/* 对话内容 */}
<Bubble.List
items={parsedMessages.map(({ id, message, status }) => ({
key: id,
loading: status === 'loading',
...message,
}))}
roles={roles}
className={styles.messages}
/>
{/* 提示 */}
<Prompts items={senderPromptsItems} onItemClick={onPromptsItemClick} />
{/* 发送框 */}
<Sender
value={content}
header={senderHeader}
onSubmit={onSubmit}
onChange={setContent}
prefix={attachmentsNode}
loading={agent.isRequesting()}
className={styles.sender}
/>
</div>
{
thoughtChainItems.length ? <div className={styles.thoughtChain}> {/* 思维链 */}
<ThoughtChain items={thoughtChainItems} />
</div> : ''
}
</div>
);
};
export default Independent;
效果
七、总结与展望
使用 Ant Design X 生成 AI 交互界面具有诸多显著优势。它提供的丰富组件和工具,极大地加速了开发进程,使开发者能够快速搭建出功能完备的界面。基于 RICH 设计范式,它为用户带来了更加流畅、智能的交互体验,有效提升了用户满意度。而且,Ant Design X 具备高度的灵活性和可定制性,能够满足各种不同项目的需求。