Skip to content

Commit

Permalink
✨ feat: support autocompleteRequest and messageItemExtraRender (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
chenshuai2144 committed Oct 26, 2023
1 parent 4693573 commit 5305e56
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 10 deletions.
1 change: 1 addition & 0 deletions src/ChatList/Item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ const Item = memo<ChatListItemProps>((props) => {
if (renderMessagesExtra?.[item.role]) RenderFunction = renderMessagesExtra[item.role];
if (renderMessagesExtra?.['default']) RenderFunction = renderMessagesExtra['default'];
if (!RenderFunction && !RenderFunction) return;

return <RenderFunction {...data} />;
},
[renderMessagesExtra?.[item.role]],
Expand Down
11 changes: 8 additions & 3 deletions src/ProChat/components/ChatList/Extras/Assistant.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@ import { Flexbox } from 'react-layout-kit';

import { useStore } from '@/ProChat/store';

export const AssistantMessageExtra: RenderMessageExtra = memo(({ extra }) => {
const model = useStore((s) => s.config.model);
export const AssistantMessageExtra: RenderMessageExtra = memo(({ extra, ...rest }) => {
const [model, messageItemExtraRender] = useStore((s) => [
s.config.model,
s.messageItemExtraRender,
]);

const showModelTag = extra?.fromModel && model !== extra?.fromModel;
const hasTranslate = !!extra?.translate;

const showExtra = showModelTag || hasTranslate;

if (!showExtra) return;
const dom = messageItemExtraRender?.(rest, 'assistant');
if (!showExtra && !dom) return;

return (
<Flexbox gap={8} style={{ marginTop: 8 }}>
Expand All @@ -24,6 +28,7 @@ export const AssistantMessageExtra: RenderMessageExtra = memo(({ extra }) => {
<Tag>{extra?.fromModel as string}</Tag>
</div>
)}
{dom}
</Flexbox>
);
});
6 changes: 5 additions & 1 deletion src/ProChat/components/ChatList/Extras/User.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ import { Divider } from 'antd';
import { memo } from 'react';
import { Flexbox } from 'react-layout-kit';

export const UserMessageExtra: RenderMessageExtra = memo(({ extra }) => {
import { useStore } from '@/ProChat/store';

export const UserMessageExtra: RenderMessageExtra = memo(({ extra, ...rest }) => {
const hasTranslate = !!extra?.translate;

const [messageItemExtraRender] = useStore((s) => [s.messageItemExtraRender]);
return (
<Flexbox gap={8} style={{ marginTop: hasTranslate ? 8 : 0 }}>
{extra?.translate && (
<div>
<Divider style={{ margin: '12px 0' }} />
</div>
)}
{messageItemExtraRender?.(rest, 'user')}
</Flexbox>
);
});
31 changes: 31 additions & 0 deletions src/ProChat/components/InputArea/AutoCompleteTextArea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { AutoComplete, Input } from 'antd';
import { TextAreaProps } from 'antd/es/input';
import { useState } from 'react';
import { useStore } from '../../store';

export const AutoCompleteTextArea: React.FC<TextAreaProps> = (props) => {
const [autocompleteRequest] = useStore((s) => [s.autocompleteRequest]);

const [options, setOptions] = useState<{ value: string; label: string }[]>([]);

return (
<AutoComplete
className={props.className}
options={options}
size="large"
style={{
height: 'max-content',
}}
onSelect={(value) => {
props.onChange?.({ target: { value } } as any);
setOptions([]);
}}
onSearch={async (value) => {
const result = await autocompleteRequest?.(value);
setOptions((result as any[]) || []);
}}
>
<Input.TextArea {...props} />
</AutoComplete>
);
};
18 changes: 12 additions & 6 deletions src/ProChat/components/InputArea/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { SendOutlined } from '@ant-design/icons';
import { Button, ConfigProvider, Input } from 'antd';
import { Button, ConfigProvider } from 'antd';
import { createStyles, useResponsive } from 'antd-style';
import { memo, useRef, useState } from 'react';
import { Flexbox } from 'react-layout-kit';

import { useStore } from '../../store';

import ActionBar from './ActionBar';
import { AutoCompleteTextArea } from './AutoCompleteTextArea';

const useStyles = createStyles(({ css, responsive, token }) => ({
container: css`
Expand All @@ -30,13 +31,15 @@ const useStyles = createStyles(({ css, responsive, token }) => ({
`,
input: css`
width: 100%;
border: none;
outline: none;
border-radius: 8px;
`,
btn: css`
position: absolute;
z-index: 10;
right: 8px;
bottom: 8px;
bottom: 6px;
color: ${token.colorTextTertiary};
&:hover {
Expand All @@ -49,10 +52,13 @@ const useStyles = createStyles(({ css, responsive, token }) => ({
}));

export const InputArea = ({}) => {
const [sendMessage, isLoading] = useStore((s) => [s.sendMessage, !!s.chatLoadingId]);
const [sendMessage, isLoading, placeholder] = useStore((s) => [
s.sendMessage,
!!s.chatLoadingId,
s.placeholder,
]);
const [message, setMessage] = useState('');
const isChineseInput = useRef(false);

const { styles, theme } = useStyles();
const { mobile } = useResponsive();

Expand All @@ -76,10 +82,10 @@ export const InputArea = ({}) => {
<Flexbox gap={8} padding={16} className={styles.container}>
<ActionBar />
<Flexbox horizontal gap={8} align={'center'} className={styles.boxShadow}>
<Input.TextArea
<AutoCompleteTextArea
size={'large'}
value={message}
placeholder="请输入内容..."
placeholder={placeholder || '请输入内容...'}
onChange={(e) => {
setMessage(e.target.value);
}}
Expand Down
2 changes: 2 additions & 0 deletions src/ProChat/container/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const ProChat = memo<ProChatProps>(
onResetMessage,
style,
className,
autocompleteRequest,
...props
}) => {
return (
Expand All @@ -44,6 +45,7 @@ export const ProChat = memo<ProChatProps>(
assistantMeta={assistantMeta}
request={request}
onResetMessage={onResetMessage}
autocompleteRequest={autocompleteRequest}
{...props}
devtoolOptions={__PRO_CHAT_STORE_DEVTOOLS__}
>
Expand Down
11 changes: 11 additions & 0 deletions src/ProChat/demos/default.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ export default () => {
<ProChat
request={'/api/chat'}
config={example.config}
autocompleteRequest={async (value) => {
if (value === '/') {
return [{ value: '你可以帮助我列出问题吗?', label: '你可以帮助我列出问题吗?' }];
}
return [];
}}
messageItemExtraRender={(_, type) => {
if (type === 'user') return <span>🦐</span>;
return <span>👍</span>;
}}
placeholder="输入 / 查看推荐问题,或者直接输入你的问题"
onResetMessage={async () => {
console.log('数据清空');
}}
Expand Down
24 changes: 24 additions & 0 deletions src/ProChat/store/initialState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,30 @@ export interface ChatPropsState {
* @returns
*/
onResetMessage?: () => Promise<void>;

/**
* 获取自动完成列表的 request
* @param value
* @returns
*/
autocompleteRequest?: (value: string) => Promise<
{
value: string;
label?: string;
}[]
>;

/**
* 输入框的 placeholder
*/
placeholder?: string;

/**
* 信息框额外渲染
*/
messageItemExtraRender?: (message: ChatMessage, type: 'assistant' | 'user') => React.ReactNode;

/** */
// /**
// * 控制是否流式输出
// * @default true
Expand Down

0 comments on commit 5305e56

Please sign in to comment.