@lobehub/chat 0.92.0 → 0.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -0
- package/docs/Deploy-with-Azure-OpenAI.md +3 -3
- package/locales/en_US/chat.json +10 -10
- package/locales/en_US/setting.json +7 -0
- package/locales/ja_JP/setting.json +7 -0
- package/locales/ko_KR/setting.json +7 -0
- package/locales/ru_RU/common.json +2 -1
- package/locales/ru_RU/setting.json +7 -0
- package/locales/zh_CN/setting.json +7 -0
- package/locales/zh_TW/setting.json +7 -0
- package/package.json +5 -4
- package/scripts/i18nWorkflow/utils.ts +4 -1
- package/src/app/chat/features/Conversation/ChatList/Actions/customAction.ts +6 -4
- package/src/app/chat/features/Conversation/ChatList/index.tsx +21 -14
- package/src/app/chat/features/TopicListContent/SystemRole/index.tsx +4 -1
- package/src/app/chat/settings/(desktop)/{Header/Desktop.tsx → features/Header.tsx} +4 -3
- package/src/app/chat/settings/(desktop)/layout.desktop.tsx +1 -1
- package/src/app/chat/settings/{components/Header/Mobile.tsx → (mobile)/features/Header.tsx} +4 -3
- package/src/app/chat/settings/(mobile)/layout.mobile.tsx +1 -1
- package/src/app/chat/settings/{components/Header/index.tsx → features/HeaderContent.tsx} +11 -3
- package/src/app/chat/settings/features/SubmitAgentButton/Inner.tsx +86 -0
- package/src/app/chat/settings/features/SubmitAgentButton/index.tsx +37 -0
- package/src/app/chat/settings/features/SubmitAgentButton/style.ts +46 -0
- package/src/app/market/features/AgentSearchBar/index.tsx +6 -3
- package/src/chains/langDetect.ts +31 -0
- package/src/chains/pickEmoji.ts +31 -0
- package/src/chains/summaryAgentName.ts +30 -0
- package/src/chains/summaryDescription.ts +26 -0
- package/src/chains/summaryTags.ts +27 -0
- package/src/chains/summaryTitle.ts +32 -0
- package/src/chains/translate.ts +17 -0
- package/src/components/HotKeys/index.tsx +2 -2
- package/src/components/ResponsiveIndex/index.tsx +4 -2
- package/src/const/url.ts +1 -0
- package/src/features/AgentInfo/index.tsx +69 -0
- package/src/features/AgentSetting/AgentMeta/AutoGenerateSelect.tsx +48 -0
- package/src/features/AgentSetting/AgentMeta/index.tsx +16 -5
- package/src/features/AgentSetting/store/action.ts +66 -12
- package/src/locales/default/chat.ts +0 -1
- package/src/locales/default/setting.ts +8 -0
- package/src/locales/resources/index.ts +0 -1
- package/src/store/session/slices/chat/actions/topic.ts +1 -1
- package/src/store/session/slices/chat/actions/translate.ts +2 -1
- package/src/store/session/slices/session/reducers/session.ts +1 -1
- package/src/app/chat/settings/(desktop)/Header/index.tsx +0 -13
- package/src/app/chat/settings/(mobile)/Header.tsx +0 -12
- package/src/chains/agent.ts +0 -76
- package/src/chains/chat.ts +0 -77
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createStyles } from 'antd-style';
|
|
2
|
+
|
|
3
|
+
export const useStyles = createStyles(({ css, token, prefixCls }) => ({
|
|
4
|
+
author: css`
|
|
5
|
+
font-size: 12px;
|
|
6
|
+
`,
|
|
7
|
+
|
|
8
|
+
avatar: css`
|
|
9
|
+
flex: none;
|
|
10
|
+
`,
|
|
11
|
+
container: css`
|
|
12
|
+
position: relative;
|
|
13
|
+
padding: 16px 16px 24px;
|
|
14
|
+
border-bottom: 1px solid ${token.colorBorderSecondary};
|
|
15
|
+
`,
|
|
16
|
+
date: css`
|
|
17
|
+
font-size: 12px;
|
|
18
|
+
color: ${token.colorTextDescription};
|
|
19
|
+
`,
|
|
20
|
+
desc: css`
|
|
21
|
+
color: ${token.colorTextDescription};
|
|
22
|
+
text-align: center;
|
|
23
|
+
`,
|
|
24
|
+
loading: css`
|
|
25
|
+
.${prefixCls}-skeleton-content {
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
}
|
|
29
|
+
`,
|
|
30
|
+
nav: css`
|
|
31
|
+
padding-top: 4px;
|
|
32
|
+
|
|
33
|
+
.${prefixCls}-tabs-tab {
|
|
34
|
+
margin: 4px !important;
|
|
35
|
+
|
|
36
|
+
+ .${prefixCls}-tabs-tab {
|
|
37
|
+
margin: 4px !important;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
`,
|
|
41
|
+
title: css`
|
|
42
|
+
font-size: 20px;
|
|
43
|
+
font-weight: 600;
|
|
44
|
+
text-align: center;
|
|
45
|
+
`,
|
|
46
|
+
}));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SearchBar } from '@lobehub/ui';
|
|
2
2
|
import { useResponsive } from 'antd-style';
|
|
3
|
-
import { memo } from 'react';
|
|
3
|
+
import { memo, useState } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
6
|
import { useMarketStore } from '@/store/market';
|
|
@@ -8,17 +8,20 @@ import { useMarketStore } from '@/store/market';
|
|
|
8
8
|
const AgentSearchBar = memo(() => {
|
|
9
9
|
const { t } = useTranslation('market');
|
|
10
10
|
const keywords = useMarketStore((s) => s.searchKeywords);
|
|
11
|
+
const [value, setValue] = useState(keywords);
|
|
11
12
|
const { mobile } = useResponsive();
|
|
12
13
|
return (
|
|
13
14
|
<SearchBar
|
|
14
15
|
allowClear
|
|
15
16
|
enableShortKey={!mobile}
|
|
16
|
-
onChange={(e) =>
|
|
17
|
+
onChange={(e) => setValue(e.target.value)}
|
|
18
|
+
onPressEnter={() => useMarketStore.setState({ searchKeywords: value })}
|
|
19
|
+
onSubmit={() => useMarketStore.setState({ searchKeywords: value })}
|
|
17
20
|
placeholder={t('search.placeholder')}
|
|
18
21
|
shortKey={'k'}
|
|
19
22
|
spotlight={!mobile}
|
|
20
23
|
type={mobile ? 'block' : 'ghost'}
|
|
21
|
-
value={
|
|
24
|
+
value={value}
|
|
22
25
|
/>
|
|
23
26
|
);
|
|
24
27
|
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { OpenAIChatStreamPayload } from '@/types/openai/chat';
|
|
2
|
+
|
|
3
|
+
export const chainLangDetect = (content: string): Partial<OpenAIChatStreamPayload> => ({
|
|
4
|
+
messages: [
|
|
5
|
+
{
|
|
6
|
+
content:
|
|
7
|
+
'你是一名精通全世界语言的语言专家,你需要识别用户输入的内容,以国际标准 locale 进行输出',
|
|
8
|
+
role: 'system',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
content: '{你好}',
|
|
12
|
+
role: 'user',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
content: 'zh-CN',
|
|
16
|
+
role: 'assistant',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
content: '{hello}',
|
|
20
|
+
role: 'user',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
content: 'en-US',
|
|
24
|
+
role: 'assistant',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
content: `{${content}}`,
|
|
28
|
+
role: 'user',
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { OpenAIChatStreamPayload } from '@/types/openai/chat';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* pick emoji for user prompt
|
|
5
|
+
* @param content
|
|
6
|
+
*/
|
|
7
|
+
export const chainPickEmoji = (content: string): Partial<OpenAIChatStreamPayload> => ({
|
|
8
|
+
messages: [
|
|
9
|
+
{
|
|
10
|
+
content:
|
|
11
|
+
'你是一名擅长进行概念抽象的设计师与 Emoji 专家,你需要根据角色能力的描述抽象出一个表达物理实体的概念 Emoji 作为角色头像, 格式要求如下:\n输入: {文本作为JSON引用字符串}\n输出: {一个Emoji}',
|
|
12
|
+
role: 'system',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。}`,
|
|
16
|
+
role: 'user',
|
|
17
|
+
},
|
|
18
|
+
{ content: '✒️', role: 'assistant' },
|
|
19
|
+
{
|
|
20
|
+
content: `输入: {你是一名代码巫师,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`,
|
|
21
|
+
role: 'user',
|
|
22
|
+
},
|
|
23
|
+
{ content: '🧙♂️', role: 'assistant' },
|
|
24
|
+
{
|
|
25
|
+
content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。}`,
|
|
26
|
+
role: 'user',
|
|
27
|
+
},
|
|
28
|
+
{ content: '🚀', role: 'assistant' },
|
|
29
|
+
{ content: `输入: {${content}}`, role: 'user' },
|
|
30
|
+
],
|
|
31
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { OpenAIChatStreamPayload } from '@/types/openai/chat';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* summary agent name for user prompt
|
|
5
|
+
* @param content
|
|
6
|
+
*/
|
|
7
|
+
export const chainSummaryAgentName = (content: string): Partial<OpenAIChatStreamPayload> => ({
|
|
8
|
+
messages: [
|
|
9
|
+
{
|
|
10
|
+
content: `你是一名擅长起名的起名大师,名字需要有文学内涵,注重精炼和赋子意境,你需要将用户的描述总结为 20 个字以内的角色, 格式要求如下:\n输入: {文本作为JSON引用字符串}\n输出: {角色名}`,
|
|
11
|
+
role: 'system',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。}`,
|
|
15
|
+
role: 'user',
|
|
16
|
+
},
|
|
17
|
+
{ content: '创意命名师', role: 'assistant' },
|
|
18
|
+
{
|
|
19
|
+
content: `输入: {你是一名前端代码专家,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`,
|
|
20
|
+
role: 'user',
|
|
21
|
+
},
|
|
22
|
+
{ content: 'ts转换魔术师', role: 'assistant' },
|
|
23
|
+
{
|
|
24
|
+
content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。}`,
|
|
25
|
+
role: 'user',
|
|
26
|
+
},
|
|
27
|
+
{ content: '创业咨询专家', role: 'assistant' },
|
|
28
|
+
{ content: `输入: {${content}}`, role: 'user' },
|
|
29
|
+
],
|
|
30
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { OpenAIChatStreamPayload } from '@/types/openai/chat';
|
|
2
|
+
|
|
3
|
+
export const chainSummaryDescription = (content: string): Partial<OpenAIChatStreamPayload> => ({
|
|
4
|
+
messages: [
|
|
5
|
+
{
|
|
6
|
+
content: `你是一名擅长技能总结的助理,你需要将用户的输入的内容总结为一个角色技能简介,确保信息清晰、逻辑清晰,并有效地传达角色的技能和经验,不超过 20 个字, 格式要求如下:\n输入: {文本作为JSON引用字符串}\n输出: {角色技能简介}`,
|
|
7
|
+
role: 'system',
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。}`,
|
|
11
|
+
role: 'user',
|
|
12
|
+
},
|
|
13
|
+
{ content: '擅长文创艺术作品起名', role: 'assistant' },
|
|
14
|
+
{
|
|
15
|
+
content: `输入: {你是一名前端代码专家,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`,
|
|
16
|
+
role: 'user',
|
|
17
|
+
},
|
|
18
|
+
{ content: '擅长 ts 转换和补充类型声明', role: 'assistant' },
|
|
19
|
+
{
|
|
20
|
+
content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。}`,
|
|
21
|
+
role: 'user',
|
|
22
|
+
},
|
|
23
|
+
{ content: '擅长创业计划撰写与咨询', role: 'assistant' },
|
|
24
|
+
{ content: `输入: {${content}}`, role: 'user' },
|
|
25
|
+
],
|
|
26
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { OpenAIChatStreamPayload } from '@/types/openai/chat';
|
|
2
|
+
|
|
3
|
+
export const chainSummaryTags = (content: string): Partial<OpenAIChatStreamPayload> => ({
|
|
4
|
+
messages: [
|
|
5
|
+
{
|
|
6
|
+
content:
|
|
7
|
+
'你是一名擅长会话标签总结的助理,你需要将用户的输入的内容提炼出分类标签,使用`,`分隔,不超过 5 个标签, 格式要求如下:\n输入: {文本作为JSON引用字符串}\n输出: {角色名}',
|
|
8
|
+
role: 'system',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
content: `输入: {你是一名文案大师,帮我为一些设计 / 艺术作品起名,名字需要有文学内涵,注重精炼和赋子意境,表达作品的情景氛国,使名称既简洁又富有诗意。}`,
|
|
12
|
+
role: 'user',
|
|
13
|
+
},
|
|
14
|
+
{ content: '起名,写作,创意', role: 'assistant' },
|
|
15
|
+
{
|
|
16
|
+
content: `输入: {你是一名前端专家,请将下面的代码转成 ts,不要修改实现。如果原本 js 中没有定义的全局变量,需要补充 declare 的类型声明。}`,
|
|
17
|
+
role: 'user',
|
|
18
|
+
},
|
|
19
|
+
{ content: '代码,软件开发,效率', role: 'assistant' },
|
|
20
|
+
{
|
|
21
|
+
content: `输入: {你是一名创业计划撰写专家,可以提供包括创意名称、简短的标语、目标用户画像、用户痛点、主要价值主张、销售/营销渠道、收入流、成本结构等计划生成。}`,
|
|
22
|
+
role: 'user',
|
|
23
|
+
},
|
|
24
|
+
{ content: '创业,计划,咨询', role: 'assistant' },
|
|
25
|
+
{ content: `输入: {${content}}`, role: 'user' },
|
|
26
|
+
],
|
|
27
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { chatHelpers } from '@/store/session/slices/chat/helpers';
|
|
2
|
+
import { LanguageModel } from '@/types/llm';
|
|
3
|
+
import { OpenAIChatMessage, OpenAIChatStreamPayload } from '@/types/openai/chat';
|
|
4
|
+
|
|
5
|
+
export const chainSummaryTitle = async (
|
|
6
|
+
messages: OpenAIChatMessage[],
|
|
7
|
+
): Promise<Partial<OpenAIChatStreamPayload>> => {
|
|
8
|
+
const finalMessages: OpenAIChatMessage[] = [
|
|
9
|
+
{
|
|
10
|
+
content:
|
|
11
|
+
'你是一名擅长会话的助理,你需要将用户的会话总结为 10 个字以内的标题,不需要包含标点符号',
|
|
12
|
+
role: 'system',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
content: `${messages.map((message) => `${message.role}: ${message.content}`).join('\n')}
|
|
16
|
+
|
|
17
|
+
请总结上述对话为10个字以内的标题,不需要包含标点符号`,
|
|
18
|
+
role: 'user',
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
// 如果超过 4k,则使用 GPT3.5 16K 模型
|
|
22
|
+
const tokens = await chatHelpers.getMessagesTokenCount(finalMessages);
|
|
23
|
+
let model: LanguageModel | undefined = undefined;
|
|
24
|
+
if (tokens > 4000) {
|
|
25
|
+
model = LanguageModel.GPT3_5_16K;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
messages: finalMessages,
|
|
30
|
+
model,
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { OpenAIChatStreamPayload } from '@/types/openai/chat';
|
|
2
|
+
|
|
3
|
+
export const chainTranslate = (
|
|
4
|
+
content: string,
|
|
5
|
+
targetLang: string,
|
|
6
|
+
): Partial<OpenAIChatStreamPayload> => ({
|
|
7
|
+
messages: [
|
|
8
|
+
{
|
|
9
|
+
content: '你是一名擅长翻译的助理,你需要将输入的语言翻译为目标语言',
|
|
10
|
+
role: 'system',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
content: `请将以下内容 ${content},翻译为 ${targetLang} `,
|
|
14
|
+
role: 'user',
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
});
|
|
@@ -47,9 +47,9 @@ const HotKeys = memo<HotKeysProps>(({ keys, desc }) => {
|
|
|
47
47
|
|
|
48
48
|
if (!desc) return content;
|
|
49
49
|
return (
|
|
50
|
-
<Flexbox align={'center'}
|
|
51
|
-
{content}
|
|
50
|
+
<Flexbox align={'center'} style={{ textAlign: 'center' }}>
|
|
52
51
|
{desc}
|
|
52
|
+
{content}
|
|
53
53
|
</Flexbox>
|
|
54
54
|
);
|
|
55
55
|
});
|
|
@@ -14,10 +14,12 @@ const ResponsiveIndex = ({ children, Mobile }: ResponsiveIndexProps) => {
|
|
|
14
14
|
const { t } = useTranslation();
|
|
15
15
|
const mobile = useIsMobile();
|
|
16
16
|
|
|
17
|
-
return (
|
|
17
|
+
return mobile ? (
|
|
18
18
|
<Suspense fallback={<FullscreenLoading title={t('layoutInitializing', { ns: 'common' })} />}>
|
|
19
|
-
|
|
19
|
+
<Mobile />
|
|
20
20
|
</Suspense>
|
|
21
|
+
) : (
|
|
22
|
+
children
|
|
21
23
|
);
|
|
22
24
|
};
|
|
23
25
|
|
package/src/const/url.ts
CHANGED
|
@@ -43,6 +43,7 @@ export const getAgentJSON = (
|
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
export const AGENTS_INDEX_GITHUB = 'https://github.com/lobehub/lobe-chat-agents';
|
|
46
|
+
export const AGENTS_INDEX_GITHUB_ISSUE = urlJoin(AGENTS_INDEX_GITHUB, 'issues/new');
|
|
46
47
|
|
|
47
48
|
export const SESSION_CHAT_URL = (id: string = INBOX_SESSION_ID, mobile?: boolean) =>
|
|
48
49
|
mobile ? `/chat/mobile#session=${id}` : `/chat#session=${id}`;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Avatar, Markdown, Tag } from '@lobehub/ui';
|
|
2
|
+
import { Divider } from 'antd';
|
|
3
|
+
import { createStyles } from 'antd-style';
|
|
4
|
+
import { startCase } from 'lodash-es';
|
|
5
|
+
import { CSSProperties, memo } from 'react';
|
|
6
|
+
import { Center } from 'react-layout-kit';
|
|
7
|
+
|
|
8
|
+
import { MetaData } from '@/types/meta';
|
|
9
|
+
|
|
10
|
+
const useStyles = createStyles(({ css, token }) => ({
|
|
11
|
+
avatar: css`
|
|
12
|
+
flex: none;
|
|
13
|
+
`,
|
|
14
|
+
desc: css`
|
|
15
|
+
color: ${token.colorTextDescription};
|
|
16
|
+
text-align: center;
|
|
17
|
+
`,
|
|
18
|
+
|
|
19
|
+
title: css`
|
|
20
|
+
font-size: 20px;
|
|
21
|
+
font-weight: 600;
|
|
22
|
+
text-align: center;
|
|
23
|
+
`,
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
export interface AgentInfoProps {
|
|
27
|
+
meta?: MetaData;
|
|
28
|
+
style?: CSSProperties;
|
|
29
|
+
systemRole?: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const AgentInfo = memo<AgentInfoProps>(({ systemRole, style, meta }) => {
|
|
33
|
+
const { styles, theme } = useStyles();
|
|
34
|
+
|
|
35
|
+
if (!meta) return;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Center gap={16} style={style}>
|
|
39
|
+
{meta.avatar && (
|
|
40
|
+
<Avatar
|
|
41
|
+
animation
|
|
42
|
+
avatar={meta.avatar}
|
|
43
|
+
background={meta.backgroundColor || theme.colorFillTertiary}
|
|
44
|
+
className={styles.avatar}
|
|
45
|
+
size={100}
|
|
46
|
+
/>
|
|
47
|
+
)}
|
|
48
|
+
{meta.title && <div className={styles.title}>{meta.title}</div>}
|
|
49
|
+
{(meta?.tags as string[])?.length > 0 && (
|
|
50
|
+
<Center gap={6} horizontal style={{ flexWrap: 'wrap' }}>
|
|
51
|
+
{(meta.tags as string[]).map((tag: string, index) => (
|
|
52
|
+
<Tag key={index} style={{ margin: 0 }}>
|
|
53
|
+
{startCase(tag).trim()}
|
|
54
|
+
</Tag>
|
|
55
|
+
))}
|
|
56
|
+
</Center>
|
|
57
|
+
)}
|
|
58
|
+
{meta.description && <div className={styles.desc}>{meta.description}</div>}
|
|
59
|
+
{systemRole && (
|
|
60
|
+
<>
|
|
61
|
+
<Divider style={{ margin: '8px 0' }} />
|
|
62
|
+
<Markdown>{systemRole}</Markdown>
|
|
63
|
+
</>
|
|
64
|
+
)}
|
|
65
|
+
</Center>
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
export default AgentInfo;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { ActionIcon } from '@lobehub/ui';
|
|
2
|
+
import { Select, SelectProps } from 'antd';
|
|
3
|
+
import { useTheme } from 'antd-style';
|
|
4
|
+
import { isString } from 'lodash-es';
|
|
5
|
+
import { Wand2 } from 'lucide-react';
|
|
6
|
+
import { memo } from 'react';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
8
|
+
|
|
9
|
+
export interface AutoGenerateInputProps extends SelectProps {
|
|
10
|
+
loading?: boolean;
|
|
11
|
+
onGenerate?: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const AutoGenerateSelect = memo<AutoGenerateInputProps>(
|
|
15
|
+
({ loading, onGenerate, value, ...props }) => {
|
|
16
|
+
const { t } = useTranslation('common');
|
|
17
|
+
const theme = useTheme();
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<Select
|
|
21
|
+
mode="tags"
|
|
22
|
+
open={false}
|
|
23
|
+
style={{ width: '100%' }}
|
|
24
|
+
suffixIcon={
|
|
25
|
+
onGenerate && (
|
|
26
|
+
<ActionIcon
|
|
27
|
+
active
|
|
28
|
+
icon={Wand2}
|
|
29
|
+
loading={loading}
|
|
30
|
+
onClick={onGenerate}
|
|
31
|
+
size={'small'}
|
|
32
|
+
style={{
|
|
33
|
+
color: theme.colorInfo,
|
|
34
|
+
marginRight: -4,
|
|
35
|
+
}}
|
|
36
|
+
title={t('autoGenerate')}
|
|
37
|
+
/>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
tokenSeparators={[',', ',', ' ']}
|
|
41
|
+
value={isString(value) ? value.split(',') : value}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
},
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
export default AutoGenerateSelect;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Form, type FormItemProps, Icon, type ItemGroup, Tooltip } from '@lobehub/ui';
|
|
2
2
|
import { Button } from 'antd';
|
|
3
3
|
import isEqual from 'fast-deep-equal';
|
|
4
|
+
import { isString } from 'lodash-es';
|
|
4
5
|
import { UserCircle, Wand2 } from 'lucide-react';
|
|
5
6
|
import dynamic from 'next/dynamic';
|
|
6
7
|
import { memo, useMemo } from 'react';
|
|
@@ -11,6 +12,7 @@ import { FORM_STYLE } from '@/const/layoutTokens';
|
|
|
11
12
|
import { useStore } from '../store';
|
|
12
13
|
import { SessionLoadingState } from '../store/initialState';
|
|
13
14
|
import AutoGenerateInput from './AutoGenerateInput';
|
|
15
|
+
import AutoGenerateSelect from './AutoGenerateSelect';
|
|
14
16
|
import BackgroundSwatches from './BackgroundSwatches';
|
|
15
17
|
|
|
16
18
|
const EmojiPicker = dynamic(() => import('@/components/EmojiPicker'), { ssr: false });
|
|
@@ -28,26 +30,35 @@ const AgentMeta = memo(() => {
|
|
|
28
30
|
|
|
29
31
|
const basic = [
|
|
30
32
|
{
|
|
33
|
+
Render: AutoGenerateInput,
|
|
31
34
|
key: 'title',
|
|
32
35
|
label: t('settingAgent.name.title'),
|
|
36
|
+
onChange: (e: any) => updateMeta({ title: e.target.value }),
|
|
33
37
|
placeholder: t('settingAgent.name.placeholder'),
|
|
34
38
|
},
|
|
35
39
|
{
|
|
40
|
+
Render: AutoGenerateInput,
|
|
36
41
|
key: 'description',
|
|
37
42
|
label: t('settingAgent.description.title'),
|
|
43
|
+
onChange: (e: any) => updateMeta({ description: e.target.value }),
|
|
38
44
|
placeholder: t('settingAgent.description.placeholder'),
|
|
39
45
|
},
|
|
40
|
-
|
|
46
|
+
{
|
|
47
|
+
Render: AutoGenerateSelect,
|
|
48
|
+
key: 'tags',
|
|
49
|
+
label: t('settingAgent.tag.title'),
|
|
50
|
+
onChange: (e: any) => updateMeta({ tags: isString(e) ? e.split(',') : e }),
|
|
51
|
+
placeholder: t('settingAgent.tag.placeholder'),
|
|
52
|
+
},
|
|
41
53
|
];
|
|
42
54
|
|
|
43
55
|
const autocompleteItems: FormItemProps[] = basic.map((item) => {
|
|
56
|
+
const AutoGenerate = item.Render;
|
|
44
57
|
return {
|
|
45
58
|
children: (
|
|
46
|
-
<
|
|
59
|
+
<AutoGenerate
|
|
47
60
|
loading={loading[item.key as keyof SessionLoadingState]}
|
|
48
|
-
onChange={
|
|
49
|
-
updateMeta({ [item.key]: e.target.value });
|
|
50
|
-
}}
|
|
61
|
+
onChange={item.onChange}
|
|
51
62
|
onGenerate={() => {
|
|
52
63
|
autocompleteMeta(item.key as keyof typeof meta);
|
|
53
64
|
}}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { StateCreator } from 'zustand/vanilla';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { chainPickEmoji } from '@/chains/pickEmoji';
|
|
4
|
+
import { chainSummaryAgentName } from '@/chains/summaryAgentName';
|
|
5
|
+
import { chainSummaryDescription } from '@/chains/summaryDescription';
|
|
6
|
+
import { chainSummaryTags } from '@/chains/summaryTags';
|
|
4
7
|
import { MetaData } from '@/types/meta';
|
|
5
8
|
import { LobeAgentConfig } from '@/types/session';
|
|
6
9
|
import { fetchPresetTaskResult } from '@/utils/fetch';
|
|
@@ -26,6 +29,7 @@ export interface Action {
|
|
|
26
29
|
* @returns 一个 Promise,用于异步操作完成后的处理
|
|
27
30
|
*/
|
|
28
31
|
autocompleteAgentDescription: () => Promise<void>;
|
|
32
|
+
autocompleteAgentTags: () => Promise<void>;
|
|
29
33
|
/**
|
|
30
34
|
* 自动完成代理标题
|
|
31
35
|
* @param id - 代理的 ID
|
|
@@ -47,7 +51,8 @@ export interface Action {
|
|
|
47
51
|
setAgentConfig: (config: Partial<LobeAgentConfig>) => void;
|
|
48
52
|
|
|
49
53
|
setAgentMeta: (meta: Partial<MetaData>) => void;
|
|
50
|
-
|
|
54
|
+
streamUpdateMetaArray: (key: keyof MetaData) => any;
|
|
55
|
+
streamUpdateMetaString: (key: keyof MetaData) => any;
|
|
51
56
|
toggleAgentPlugin: (pluginId: string, state?: boolean) => void;
|
|
52
57
|
/**
|
|
53
58
|
* 更新加载状态
|
|
@@ -65,7 +70,7 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
|
|
|
65
70
|
...initialState,
|
|
66
71
|
|
|
67
72
|
autoPickEmoji: async () => {
|
|
68
|
-
const { config, dispatchMeta } = get();
|
|
73
|
+
const { config, meta, dispatchMeta } = get();
|
|
69
74
|
|
|
70
75
|
const systemRole = config.systemRole;
|
|
71
76
|
|
|
@@ -73,7 +78,7 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
|
|
|
73
78
|
onLoadingChange: (loading) => {
|
|
74
79
|
get().updateLoadingState('avatar', loading);
|
|
75
80
|
},
|
|
76
|
-
params:
|
|
81
|
+
params: chainPickEmoji([meta.title, meta.description, systemRole].filter(Boolean).join(',')),
|
|
77
82
|
});
|
|
78
83
|
|
|
79
84
|
if (emoji) {
|
|
@@ -81,7 +86,7 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
|
|
|
81
86
|
}
|
|
82
87
|
},
|
|
83
88
|
autocompleteAgentDescription: async () => {
|
|
84
|
-
const { dispatchMeta, config, meta, updateLoadingState,
|
|
89
|
+
const { dispatchMeta, config, meta, updateLoadingState, streamUpdateMetaString } = get();
|
|
85
90
|
|
|
86
91
|
const systemRole = config.systemRole;
|
|
87
92
|
|
|
@@ -99,12 +104,37 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
|
|
|
99
104
|
onLoadingChange: (loading) => {
|
|
100
105
|
updateLoadingState('description', loading);
|
|
101
106
|
},
|
|
102
|
-
onMessageHandle:
|
|
103
|
-
params:
|
|
107
|
+
onMessageHandle: streamUpdateMetaString('description'),
|
|
108
|
+
params: chainSummaryDescription(systemRole),
|
|
109
|
+
});
|
|
110
|
+
},
|
|
111
|
+
autocompleteAgentTags: async () => {
|
|
112
|
+
const { dispatchMeta, config, meta, updateLoadingState, streamUpdateMetaArray } = get();
|
|
113
|
+
|
|
114
|
+
const systemRole = config.systemRole;
|
|
115
|
+
|
|
116
|
+
if (!systemRole) return;
|
|
117
|
+
|
|
118
|
+
const preValue = meta.tags;
|
|
119
|
+
|
|
120
|
+
// 替换为 ...
|
|
121
|
+
dispatchMeta({ type: 'update', value: { tags: ['...'] } });
|
|
122
|
+
|
|
123
|
+
fetchPresetTaskResult({
|
|
124
|
+
onError: () => {
|
|
125
|
+
dispatchMeta({ type: 'update', value: { tags: preValue } });
|
|
126
|
+
},
|
|
127
|
+
onLoadingChange: (loading) => {
|
|
128
|
+
updateLoadingState('tags', loading);
|
|
129
|
+
},
|
|
130
|
+
onMessageHandle: streamUpdateMetaArray('tags'),
|
|
131
|
+
params: chainSummaryTags(
|
|
132
|
+
[meta.title, meta.description, systemRole].filter(Boolean).join(','),
|
|
133
|
+
),
|
|
104
134
|
});
|
|
105
135
|
},
|
|
106
136
|
autocompleteAgentTitle: async () => {
|
|
107
|
-
const { dispatchMeta, config, meta, updateLoadingState,
|
|
137
|
+
const { dispatchMeta, config, meta, updateLoadingState, streamUpdateMetaString } = get();
|
|
108
138
|
|
|
109
139
|
const systemRole = config.systemRole;
|
|
110
140
|
|
|
@@ -122,8 +152,8 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
|
|
|
122
152
|
onLoadingChange: (loading) => {
|
|
123
153
|
updateLoadingState('title', loading);
|
|
124
154
|
},
|
|
125
|
-
onMessageHandle:
|
|
126
|
-
params:
|
|
155
|
+
onMessageHandle: streamUpdateMetaString('title'),
|
|
156
|
+
params: chainSummaryAgentName([meta.description, systemRole].filter(Boolean).join(',')),
|
|
127
157
|
});
|
|
128
158
|
},
|
|
129
159
|
autocompleteAllMeta: (replace) => {
|
|
@@ -140,9 +170,18 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
|
|
|
140
170
|
if (!meta.avatar || replace) {
|
|
141
171
|
get().autoPickEmoji();
|
|
142
172
|
}
|
|
173
|
+
|
|
174
|
+
if (!meta.tags || replace) {
|
|
175
|
+
get().autocompleteAgentTags();
|
|
176
|
+
}
|
|
143
177
|
},
|
|
144
178
|
autocompleteMeta: (key) => {
|
|
145
|
-
const {
|
|
179
|
+
const {
|
|
180
|
+
autoPickEmoji,
|
|
181
|
+
autocompleteAgentTitle,
|
|
182
|
+
autocompleteAgentDescription,
|
|
183
|
+
autocompleteAgentTags,
|
|
184
|
+
} = get();
|
|
146
185
|
|
|
147
186
|
switch (key) {
|
|
148
187
|
case 'avatar': {
|
|
@@ -157,6 +196,12 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
|
|
|
157
196
|
|
|
158
197
|
case 'title': {
|
|
159
198
|
autocompleteAgentTitle();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
case 'tags': {
|
|
203
|
+
autocompleteAgentTags();
|
|
204
|
+
return;
|
|
160
205
|
}
|
|
161
206
|
}
|
|
162
207
|
},
|
|
@@ -187,10 +232,19 @@ export const store: StateCreator<Store, [['zustand/devtools', never]]> = (set, g
|
|
|
187
232
|
get().dispatchConfig({ config, type: 'update' });
|
|
188
233
|
},
|
|
189
234
|
setAgentMeta: (meta) => {
|
|
235
|
+
console.log(meta);
|
|
190
236
|
get().dispatchMeta({ type: 'update', value: meta });
|
|
191
237
|
},
|
|
192
238
|
|
|
193
|
-
|
|
239
|
+
streamUpdateMetaArray: (key: keyof MetaData) => {
|
|
240
|
+
let value = '';
|
|
241
|
+
return (text: string) => {
|
|
242
|
+
value += text;
|
|
243
|
+
get().dispatchMeta({ type: 'update', value: { [key]: value.split(',') } });
|
|
244
|
+
};
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
streamUpdateMetaString: (key: keyof MetaData) => {
|
|
194
248
|
let value = '';
|
|
195
249
|
return (text: string) => {
|
|
196
250
|
value += text;
|