- {name &&
{name}
}
+
+ {showTitle ? avatar.title || 'untitled' : null}
+ {time && (
+
+ {formatTime(time)}
+
+ )}
+
{alert ? (
) : (
diff --git a/src/ChatItem/style.ts b/src/ChatItem/style.ts
index 71b54f3d..6d546c58 100644
--- a/src/ChatItem/style.ts
+++ b/src/ChatItem/style.ts
@@ -2,18 +2,20 @@ import { createStyles } from 'antd-style';
export const useStyles = createStyles(
(
- { cx, css, token },
+ { cx, css, token, stylish },
{
placement,
type,
- name,
+ title,
primary,
avatarSize,
+ showTitle,
}: {
avatarSize: number;
- name?: string;
placement?: 'left' | 'right';
primary?: boolean;
+ showTitle?: boolean;
+ title?: string;
type?: 'block' | 'pure';
},
) => {
@@ -29,7 +31,7 @@ export const useStyles = createStyles(
`;
const pureStylish = css`
- padding-top: ${name ? 0 : '6px'};
+ padding-top: ${title ? 0 : '6px'};
`;
const pureContainerStylish = css`
@@ -61,6 +63,16 @@ export const useStyles = createStyles(
width: 100%;
padding: 12px;
+
+ .chat-item-time {
+ display: none;
+ }
+
+ &:hover {
+ .chat-item-time {
+ display: inline-block;
+ }
+ }
`,
),
loading: css`
@@ -96,6 +108,15 @@ export const useStyles = createStyles(
}
`,
name: css`
+ position: ${showTitle ? 'relative' : 'absolute'};
+ top: ${showTitle ? 'unset' : '-16px'};
+ right: ${placement === 'right' ? '0' : 'unset'};
+ left: ${placement === 'left' ? '0' : 'unset'};
+
+ display: flex;
+ flex-direction: ${placement === 'left' ? 'row' : 'row-reverse'};
+ gap: 4px;
+
margin-bottom: 6px;
font-size: 12px;
@@ -103,6 +124,21 @@ export const useStyles = createStyles(
color: ${token.colorTextDescription};
text-align: ${placement === 'left' ? 'left' : 'right'};
`,
+ time: cx(
+ stylish.blur,
+ css`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ padding: 4px 6px;
+
+ line-height: 1;
+
+ background: ${token.colorFillQuaternary};
+ border-radius: ${token.borderRadius}px;
+ `,
+ ),
message: cx(
typeStylish,
css`
diff --git a/src/ChatList/demos/data.ts b/src/ChatList/demos/data.ts
index d07173cd..49f96ba1 100644
--- a/src/ChatList/demos/data.ts
+++ b/src/ChatList/demos/data.ts
@@ -1,13 +1,28 @@
-import { ChatMessage } from '@/Chat';
+import { ChatMessage } from '@/types/chatMessage';
export const data: ChatMessage[] = [
{
+ id: '1',
+ meta: {
+ avatar: 'https://avatars.githubusercontent.com/u/17870709?v=4',
+ title: 'CanisMinor',
+ },
role: 'user',
content: 'dayjs 如何使用 fromNow',
+ createAt: 1686437950084,
+ updateAt: 1686437950084,
},
{
+ id: '2',
+ meta: {
+ avatar: '😎',
+ title: 'Advertiser',
+ backgroundColor: '#E8DA5A',
+ },
role: 'assistant',
content:
'要使用 dayjs 的 fromNow 函数,需要先安装 dayjs 库并在代码中引入它。然后,可以使用以下语法来获取当前时间与给定时间之间的相对时间:\n\n```javascript\ndayjs().fromNow(); // 获取当前时间的相对时间\ndayjs(\'2021-05-01\').fromNow(); // 获取给定时间的相对时间\n```\n\n第一个示例将返回类似于 "几秒前"、"一分钟前"、"2 天前" 的相对时间字符串,表示当前时间与调用 fromNow 方法时的时间差。第二个示例将返回给定时间与当前时间的相对时间字符串。',
+ createAt: 1686538950084,
+ updateAt: 1686538950084,
},
];
diff --git a/src/ChatList/demos/index.tsx b/src/ChatList/demos/index.tsx
index fcbee0b7..77678d44 100644
--- a/src/ChatList/demos/index.tsx
+++ b/src/ChatList/demos/index.tsx
@@ -10,6 +10,7 @@ export default () => {
value: 'chat',
options: ['doc', 'chat'],
},
+ showTitle: false,
},
{ store },
);
diff --git a/src/ChatList/index.tsx b/src/ChatList/index.tsx
index 75b6f6bf..55a6daa5 100644
--- a/src/ChatList/index.tsx
+++ b/src/ChatList/index.tsx
@@ -1,8 +1,8 @@
import { memo } from 'react';
-import { ChatMessage } from '@/Chat';
-import { ChatItem } from '@/index';
+import { ChatItem, ChatItemProps } from '@/index';
import type { DivProps } from '@/types';
+import { ChatMessage } from '@/types/chatMessage';
import { useStyles } from './style';
@@ -11,6 +11,11 @@ export interface ChatListProps extends DivProps {
* @description Data of chat messages to be displayed
*/
data: ChatMessage[];
+ /**
+ * @description Whether to show name of the chat item
+ * @default false
+ */
+ showTitle?: ChatItemProps['showTitle'];
/**
* @description Type of chat list
* @default 'chat'
@@ -18,18 +23,21 @@ export interface ChatListProps extends DivProps {
type?: 'docs' | 'chat';
}
-const ChatList = memo
(({ className, data, type = 'chat', ...props }) => {
+const ChatList = memo(({ className, data, type = 'chat', showTitle, ...props }) => {
const { cx, styles } = useStyles();
return (
- {data.map((item, index) => (
+ {data.map((item) => (
))}
diff --git a/src/types/chatMessage.ts b/src/types/chatMessage.ts
new file mode 100644
index 00000000..f21c034e
--- /dev/null
+++ b/src/types/chatMessage.ts
@@ -0,0 +1,41 @@
+import { LLMRoleType } from './llm';
+import { BaseDataModel } from './meta';
+
+/**
+ * 聊天消息错误对象
+ */
+export interface ChatMessageError {
+ /**
+ * 错误信息
+ */
+ message: string;
+ status: number;
+ type: 'general' | 'llm';
+}
+
+export interface ChatMessage extends BaseDataModel {
+ /**
+ * @title 内容
+ * @description 消息内容
+ */
+ content: string;
+
+ // 扩展字段
+ extra?: {
+ // 翻译
+ translate: {
+ target: string;
+ to: string;
+ };
+ // 语音
+ } & Record;
+
+ parentId?: string;
+ // 引用
+ quotaId?: string;
+ /**
+ * 角色
+ * @description 消息发送者的角色
+ */
+ role: LLMRoleType;
+}
diff --git a/src/types/llm.ts b/src/types/llm.ts
new file mode 100644
index 00000000..af643a77
--- /dev/null
+++ b/src/types/llm.ts
@@ -0,0 +1,47 @@
+/**
+ * LLM 模型
+ */
+export enum LanguageModel {
+ /**
+ * GPT 3.5 Turbo
+ */
+ GPT3_5 = 'gpt-3.5-turbo',
+ /**
+ * GPT 4
+ */
+ GPT4 = 'gpt-4',
+}
+
+// 语言模型的设置参数
+export interface LLMParams {
+ /**
+ * 控制生成文本中的惩罚系数,用于减少重复性
+ */
+ frequency_penalty?: number;
+ /**
+ * 生成文本的最大长度
+ */
+ max_tokens?: number;
+ /**
+ * 控制生成文本中的惩罚系数,用于减少主题的变化
+ */
+ presence_penalty?: number;
+ /**
+ * 生成文本的随机度量,用于控制文本的创造性和多样性
+ * @default 0.8
+ */
+ temperature: number;
+ /**
+ * 控制生成文本中最高概率的单个 token
+ */
+ top_p?: number;
+}
+
+export type LLMRoleType = 'user' | 'system' | 'assistant';
+
+export interface LLMMessage {
+ content: string;
+ role: LLMRoleType;
+}
+
+export type LLMExample = LLMMessage[];
diff --git a/src/types/meta.ts b/src/types/meta.ts
new file mode 100644
index 00000000..4d1e33d9
--- /dev/null
+++ b/src/types/meta.ts
@@ -0,0 +1,26 @@
+export interface MetaData {
+ /**
+ * 角色头像
+ * @description 可选参数,如果不传则使用默认头像
+ */
+ avatar?: string;
+ /**
+ * 背景色
+ * @description 可选参数,如果不传则使用默认背景色
+ */
+ backgroundColor?: string;
+ description?: string;
+ tag?: string[];
+ /**
+ * 名称
+ * @description 可选参数,如果不传则使用默认名称
+ */
+ title?: string;
+}
+
+export interface BaseDataModel {
+ createAt?: number;
+ id: string;
+ meta: MetaData;
+ updateAt?: number;
+}
diff --git a/src/utils/formatTime.ts b/src/utils/formatTime.ts
new file mode 100644
index 00000000..3e09bfa9
--- /dev/null
+++ b/src/utils/formatTime.ts
@@ -0,0 +1,14 @@
+import dayjs from 'dayjs';
+
+export const formatTime = (time: number): string => {
+ const now = dayjs();
+ const target = dayjs(time);
+
+ if (target.isSame(now, 'day')) {
+ return target.format('HH:mm');
+ } else if (target.isSame(now, 'year')) {
+ return target.format('MM-DD HH:mm');
+ } else {
+ return target.format('YYYY-MM-DD HH:mm');
+ }
+};