@lobehub/chat 0.101.7 → 0.102.1

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.
Files changed (87) hide show
  1. package/.i18nrc.js +1 -1
  2. package/CHANGELOG.md +50 -0
  3. package/README.md +38 -4
  4. package/README.zh-CN.md +41 -9
  5. package/__mocks__/zustand/traditional.ts +4 -4
  6. package/locales/en_US/chat.json +11 -1
  7. package/locales/en_US/error.json +6 -0
  8. package/locales/en_US/setting.json +40 -1
  9. package/locales/ja_JP/chat.json +11 -1
  10. package/locales/ja_JP/error.json +6 -0
  11. package/locales/ja_JP/setting.json +40 -1
  12. package/locales/ko_KR/chat.json +11 -1
  13. package/locales/ko_KR/error.json +6 -0
  14. package/locales/ko_KR/setting.json +40 -1
  15. package/locales/ru_RU/chat.json +11 -1
  16. package/locales/ru_RU/error.json +6 -0
  17. package/locales/ru_RU/setting.json +40 -1
  18. package/locales/zh_CN/chat.json +10 -1
  19. package/locales/zh_CN/error.json +6 -0
  20. package/locales/zh_CN/setting.json +36 -1
  21. package/locales/zh_TW/chat.json +11 -1
  22. package/locales/zh_TW/error.json +6 -0
  23. package/locales/zh_TW/setting.json +40 -1
  24. package/next.config.mjs +2 -20
  25. package/package.json +4 -3
  26. package/src/app/api/openai/chat/route.ts +5 -41
  27. package/src/app/api/openai/{createAzureOpenai.ts → createBizOpenAI/createAzureOpenai.ts} +1 -1
  28. package/src/app/api/openai/{createOpenai.ts → createBizOpenAI/createOpenai.ts} +1 -1
  29. package/src/app/api/openai/createBizOpenAI/index.ts +46 -0
  30. package/src/app/api/openai/models/route.ts +1 -1
  31. package/src/app/api/openai/stt/route.ts +29 -0
  32. package/src/app/api/openai/tts/route.ts +17 -0
  33. package/src/app/api/tts/edge-speech/route.ts +9 -0
  34. package/src/app/api/tts/microsoft-speech/route.ts +9 -0
  35. package/src/app/chat/(desktop)/features/ChatHeader.tsx +3 -2
  36. package/src/app/chat/(desktop)/features/ChatInput/index.tsx +0 -1
  37. package/src/app/chat/(desktop)/features/SessionHeader.tsx +2 -2
  38. package/src/app/chat/(mobile)/features/ChatHeader.tsx +29 -11
  39. package/src/app/chat/(mobile)/features/ChatInput/Mobile.tsx +20 -4
  40. package/src/app/chat/features/ChatHeader/ShareButton/index.tsx +23 -15
  41. package/src/app/chat/features/ChatInput/ActionBar/config.ts +16 -6
  42. package/src/app/chat/features/ChatInput/ActionBar/index.tsx +40 -16
  43. package/src/app/chat/features/ChatInput/STT/index.tsx +146 -0
  44. package/src/app/chat/features/ChatInput/Topic/index.tsx +1 -3
  45. package/src/app/chat/features/Conversation/ChatList/Actions/Assistant.tsx +2 -2
  46. package/src/app/chat/features/Conversation/ChatList/Actions/User.tsx +2 -2
  47. package/src/app/chat/features/Conversation/ChatList/Actions/customAction.ts +9 -2
  48. package/src/app/chat/features/Conversation/ChatList/Actions/index.ts +8 -1
  49. package/src/app/chat/features/Conversation/ChatList/Extras/Assistant.tsx +33 -27
  50. package/src/app/chat/features/Conversation/ChatList/Extras/AudioPlayer.tsx +139 -0
  51. package/src/app/chat/features/Conversation/ChatList/Extras/ExtraContainer.tsx +13 -0
  52. package/src/app/chat/features/Conversation/ChatList/Extras/TTS.tsx +122 -0
  53. package/src/app/chat/features/Conversation/ChatList/Extras/User.tsx +18 -11
  54. package/src/app/chat/settings/features/HeaderContent.tsx +6 -4
  55. package/src/app/chat/settings/features/SubmitAgentButton/index.tsx +2 -3
  56. package/src/app/settings/features/SideBar/List.tsx +2 -1
  57. package/src/app/settings/features/SideBar/index.tsx +1 -1
  58. package/src/app/settings/features/UpgradeAlert.tsx +1 -1
  59. package/src/app/settings/tts/TTS/index.tsx +73 -0
  60. package/src/app/settings/tts/TTS/options.ts +30 -0
  61. package/src/app/settings/tts/index.tsx +21 -0
  62. package/src/app/settings/tts/layout.tsx +1 -0
  63. package/src/app/settings/tts/page.tsx +3 -0
  64. package/src/components/HotKeys/index.tsx +4 -7
  65. package/src/const/layoutTokens.ts +3 -0
  66. package/src/const/settings.ts +22 -1
  67. package/src/features/AgentSetting/AgentTTS/SelectWithTTSPreview.tsx +119 -0
  68. package/src/features/AgentSetting/AgentTTS/index.tsx +115 -0
  69. package/src/features/AgentSetting/AgentTTS/options.ts +16 -0
  70. package/src/features/AgentSetting/index.tsx +2 -1
  71. package/src/hooks/useSTT.ts +61 -0
  72. package/src/hooks/useTTS.ts +87 -0
  73. package/src/locales/default/chat.ts +10 -1
  74. package/src/locales/default/error.ts +6 -0
  75. package/src/locales/default/setting.ts +35 -1
  76. package/src/services/_url.ts +7 -0
  77. package/src/store/global/initialState.ts +1 -0
  78. package/src/store/global/selectors/settings.test.ts +32 -0
  79. package/src/store/global/selectors/settings.ts +9 -1
  80. package/src/store/session/slices/agentConfig/selectors.ts +9 -0
  81. package/src/store/session/slices/chat/actions/translate.ts +24 -1
  82. package/src/store/session/slices/chat/selectors/utils.test.ts +16 -0
  83. package/src/store/session/slices/session/reducers/session.test.ts +24 -0
  84. package/src/types/chatMessage.ts +6 -0
  85. package/src/types/session.ts +17 -0
  86. package/src/types/settings.ts +13 -2
  87. package/src/app/chat/(mobile)/features/ChatInput/style.mobile.ts +0 -19
@@ -0,0 +1,115 @@
1
+ import { VoiceList } from '@lobehub/tts';
2
+ import { Form, ItemGroup } from '@lobehub/ui';
3
+ import { Form as AFrom, Select, Switch } from 'antd';
4
+ import isEqual from 'fast-deep-equal';
5
+ import { debounce } from 'lodash-es';
6
+ import { Mic } from 'lucide-react';
7
+ import { memo, useEffect } from 'react';
8
+ import { useTranslation } from 'react-i18next';
9
+
10
+ import { FORM_STYLE } from '@/const/layoutTokens';
11
+ import SelectWithTTSPreview from '@/features/AgentSetting/AgentTTS/SelectWithTTSPreview';
12
+ import { settingsSelectors, useGlobalStore } from '@/store/global';
13
+
14
+ import { useStore } from '../store';
15
+ import { ttsOptions } from './options';
16
+
17
+ const TTS_SETTING_KEY = 'tts';
18
+ const { openaiVoiceOptions, localeOptions } = VoiceList;
19
+
20
+ const AgentTTS = memo(() => {
21
+ const { t } = useTranslation('setting');
22
+ const updateConfig = useStore((s) => s.setAgentConfig);
23
+ const [form] = AFrom.useForm();
24
+ const voiceList = useGlobalStore((s) => {
25
+ const locale = settingsSelectors.currentLanguage(s);
26
+ return (all?: boolean) => new VoiceList(all ? undefined : locale);
27
+ });
28
+ const config = useStore((s) => s.config, isEqual);
29
+
30
+ useEffect(() => {
31
+ form.setFieldsValue(config);
32
+ }, [config]);
33
+
34
+ const showAllLocaleVoice = config.tts.showAllLocaleVoice;
35
+
36
+ const { edgeVoiceOptions, microsoftVoiceOptions } = voiceList(showAllLocaleVoice);
37
+
38
+ const tts: ItemGroup = {
39
+ children: [
40
+ {
41
+ children: <Select options={ttsOptions} />,
42
+ desc: t('settingTTS.ttsService.desc'),
43
+ label: t('settingTTS.ttsService.title'),
44
+ name: [TTS_SETTING_KEY, 'ttsService'],
45
+ },
46
+ {
47
+ children: <Switch />,
48
+ desc: t('settingTTS.showAllLocaleVoice.desc'),
49
+ hidden: config.tts.ttsService === 'openai',
50
+ label: t('settingTTS.showAllLocaleVoice.title'),
51
+ minWidth: undefined,
52
+ name: [TTS_SETTING_KEY, 'showAllLocaleVoice'],
53
+ valuePropName: 'checked',
54
+ },
55
+ {
56
+ children: <SelectWithTTSPreview options={openaiVoiceOptions} server={'openai'} />,
57
+ desc: t('settingTTS.voice.desc'),
58
+ hidden: config.tts.ttsService !== 'openai',
59
+ label: t('settingTTS.voice.title'),
60
+ name: [TTS_SETTING_KEY, 'voice', 'openai'],
61
+ },
62
+ {
63
+ children: <SelectWithTTSPreview options={edgeVoiceOptions} server={'edge'} />,
64
+ desc: t('settingTTS.voice.desc'),
65
+ divider: false,
66
+ hidden: config.tts.ttsService !== 'edge',
67
+ label: t('settingTTS.voice.title'),
68
+ name: [TTS_SETTING_KEY, 'voice', 'edge'],
69
+ },
70
+ {
71
+ children: <SelectWithTTSPreview options={microsoftVoiceOptions} server={'microsoft'} />,
72
+ desc: t('settingTTS.voice.desc'),
73
+ divider: false,
74
+ hidden: config.tts.ttsService !== 'microsoft',
75
+ label: t('settingTTS.voice.title'),
76
+ name: [TTS_SETTING_KEY, 'voice', 'microsoft'],
77
+ },
78
+ {
79
+ children: (
80
+ <Select
81
+ options={[
82
+ { label: t('settingTheme.lang.autoMode'), value: 'auto' },
83
+ ...(localeOptions || []),
84
+ ]}
85
+ />
86
+ ),
87
+ desc: t('settingTTS.sttLocale.desc'),
88
+ label: t('settingTTS.sttLocale.title'),
89
+ name: [TTS_SETTING_KEY, 'sttLocale'],
90
+ },
91
+ ],
92
+ icon: Mic,
93
+ title: t('settingTTS.title'),
94
+ };
95
+
96
+ return (
97
+ <Form
98
+ form={form}
99
+ initialValues={{
100
+ [TTS_SETTING_KEY]: {
101
+ voice: {
102
+ edge: edgeVoiceOptions?.[0].value,
103
+ microsoft: microsoftVoiceOptions?.[0].value,
104
+ openai: openaiVoiceOptions?.[0].value,
105
+ },
106
+ },
107
+ }}
108
+ items={[tts]}
109
+ onValuesChange={debounce(updateConfig, 100)}
110
+ {...FORM_STYLE}
111
+ />
112
+ );
113
+ });
114
+
115
+ export default AgentTTS;
@@ -0,0 +1,16 @@
1
+ import { SelectProps } from 'antd';
2
+
3
+ export const ttsOptions: SelectProps['options'] = [
4
+ {
5
+ label: 'OpenAI',
6
+ value: 'openai',
7
+ },
8
+ {
9
+ label: 'Edge Speech',
10
+ value: 'edge',
11
+ },
12
+ {
13
+ label: 'Microsoft Speech',
14
+ value: 'microsoft',
15
+ },
16
+ ];
@@ -4,6 +4,7 @@ import AgentConfig from './AgentConfig';
4
4
  import AgentMeta from './AgentMeta';
5
5
  import AgentPlugin from './AgentPlugin';
6
6
  import AgentPrompt from './AgentPrompt';
7
+ import AgentTTS from './AgentTTS';
7
8
  import StoreUpdater, { StoreUpdaterProps } from './StoreUpdater';
8
9
  import { Provider, createStore } from './store';
9
10
 
@@ -13,10 +14,10 @@ const AgentSettings = memo<AgentSettingsProps>((props) => {
13
14
  return (
14
15
  <Provider createStore={createStore}>
15
16
  <StoreUpdater {...props} />
16
-
17
17
  <AgentPrompt />
18
18
  <AgentMeta />
19
19
  <AgentConfig />
20
+ <AgentTTS />
20
21
  <AgentPlugin />
21
22
  </Provider>
22
23
  );
@@ -0,0 +1,61 @@
1
+ import { getRecordMineType } from '@lobehub/tts';
2
+ import {
3
+ OpenAISTTOptions,
4
+ SpeechRecognitionOptions,
5
+ useOpenAISTT,
6
+ useSpeechRecognition,
7
+ } from '@lobehub/tts/react';
8
+ import isEqual from 'fast-deep-equal';
9
+ import { SWRConfiguration } from 'swr';
10
+
11
+ import { createHeaderWithOpenAI } from '@/services/_header';
12
+ import { OPENAI_URLS } from '@/services/_url';
13
+ import { settingsSelectors, useGlobalStore } from '@/store/global';
14
+ import { useSessionStore } from '@/store/session';
15
+ import { agentSelectors } from '@/store/session/slices/agentConfig';
16
+
17
+ interface STTConfig extends SWRConfiguration {
18
+ onTextChange: (value: string) => void;
19
+ }
20
+
21
+ export const useSTT = (config: STTConfig) => {
22
+ const ttsSettings = useGlobalStore(settingsSelectors.currentTTS, isEqual);
23
+ const ttsAgentSettings = useSessionStore(agentSelectors.currentAgentTTS, isEqual);
24
+ const locale = useGlobalStore(settingsSelectors.currentLanguage);
25
+
26
+ const autoStop = ttsSettings.sttAutoStop;
27
+ const sttLocale =
28
+ ttsAgentSettings?.sttLocale && ttsAgentSettings.sttLocale !== 'auto'
29
+ ? ttsAgentSettings.sttLocale
30
+ : locale;
31
+
32
+ let useSelectedSTT;
33
+ let options: any = {};
34
+
35
+ switch (ttsSettings.sttServer) {
36
+ case 'openai': {
37
+ useSelectedSTT = useOpenAISTT;
38
+ options = {
39
+ api: {
40
+ headers: createHeaderWithOpenAI(),
41
+ serviceUrl: OPENAI_URLS.stt,
42
+ },
43
+ autoStop,
44
+ options: {
45
+ mineType: getRecordMineType(),
46
+ model: ttsSettings.openAI.sttModel,
47
+ },
48
+ } as OpenAISTTOptions;
49
+ break;
50
+ }
51
+ case 'browser': {
52
+ options = {
53
+ autoStop,
54
+ } as SpeechRecognitionOptions;
55
+ useSelectedSTT = useSpeechRecognition;
56
+ break;
57
+ }
58
+ }
59
+
60
+ return useSelectedSTT(sttLocale, { ...config, ...options });
61
+ };
@@ -0,0 +1,87 @@
1
+ import { VoiceList } from '@lobehub/tts';
2
+ import {
3
+ EdgeSpeechOptions,
4
+ MicrosoftSpeechOptions,
5
+ OpenAITTSOptions,
6
+ useEdgeSpeech,
7
+ useMicrosoftSpeech,
8
+ useOpenAITTS,
9
+ } from '@lobehub/tts/react';
10
+ import isEqual from 'fast-deep-equal';
11
+ import { SWRConfiguration } from 'swr';
12
+
13
+ import { createHeaderWithOpenAI } from '@/services/_header';
14
+ import { OPENAI_URLS, TTS_URL } from '@/services/_url';
15
+ import { settingsSelectors, useGlobalStore } from '@/store/global';
16
+ import { useSessionStore } from '@/store/session';
17
+ import { agentSelectors } from '@/store/session/slices/agentConfig';
18
+ import { TTSServer } from '@/types/session';
19
+
20
+ interface TTSConfig extends SWRConfiguration {
21
+ server?: TTSServer;
22
+ voice?: string;
23
+ }
24
+
25
+ export const useTTS = (content: string, config?: TTSConfig) => {
26
+ const ttsSettings = useGlobalStore(settingsSelectors.currentTTS, isEqual);
27
+ const ttsAgentSettings = useSessionStore(agentSelectors.currentAgentTTS, isEqual);
28
+ const voiceList = useGlobalStore((s) => new VoiceList(settingsSelectors.currentLanguage(s)));
29
+
30
+ let useSelectedTTS;
31
+ let options: any = {};
32
+ switch (config?.server || ttsAgentSettings.ttsService) {
33
+ case 'openai': {
34
+ useSelectedTTS = useOpenAITTS;
35
+ options = {
36
+ api: {
37
+ headers: createHeaderWithOpenAI(),
38
+ serviceUrl: OPENAI_URLS.tts,
39
+ },
40
+ options: {
41
+ model: ttsSettings.openAI.ttsModel,
42
+ voice:
43
+ config?.voice ||
44
+ ttsAgentSettings.voice.openai ||
45
+ VoiceList.openaiVoiceOptions?.[0].value,
46
+ },
47
+ } as OpenAITTSOptions;
48
+ break;
49
+ }
50
+ case 'edge': {
51
+ useSelectedTTS = useEdgeSpeech;
52
+ options = {
53
+ api: {
54
+ /**
55
+ * @description client fetch
56
+ * serviceUrl: TTS_URL.edge,
57
+ */
58
+ },
59
+ options: {
60
+ voice:
61
+ config?.voice || ttsAgentSettings.voice.edge || voiceList.edgeVoiceOptions?.[0].value,
62
+ },
63
+ } as EdgeSpeechOptions;
64
+ break;
65
+ }
66
+ case 'microsoft': {
67
+ useSelectedTTS = useMicrosoftSpeech;
68
+ options = {
69
+ api: {
70
+ serviceUrl: TTS_URL.microsoft,
71
+ },
72
+ options: {
73
+ voice:
74
+ config?.voice ||
75
+ ttsAgentSettings.voice.microsoft ||
76
+ voiceList.microsoftVoiceOptions?.[0].value,
77
+ },
78
+ } as MicrosoftSpeechOptions;
79
+ break;
80
+ }
81
+ }
82
+
83
+ return useSelectedTTS(content, {
84
+ ...config,
85
+ ...options,
86
+ });
87
+ };
@@ -38,6 +38,11 @@ export default {
38
38
  withSystemRole: '包含助手角色设定',
39
39
  },
40
40
  stop: '停止',
41
+ stt: {
42
+ action: '语音输入',
43
+ loading: '识别中...',
44
+ prettifying: '润色中...',
45
+ },
41
46
  temp: '临时',
42
47
  tokenDetail: '角色设定: {{systemRoleToken}} · 历史消息: {{chatsToken}}',
43
48
  tokenTag: {
@@ -58,9 +63,13 @@ export default {
58
63
  title: '话题列表',
59
64
  },
60
65
  translate: {
66
+ action: '翻译',
61
67
  clear: '删除翻译',
62
68
  },
63
- translateTo: '翻译',
69
+ tts: {
70
+ action: '语音朗读',
71
+ clear: '删除语音',
72
+ },
64
73
  updateAgent: '更新助理信息',
65
74
  upload: {
66
75
  actionTooltip: '上传图片',
@@ -35,6 +35,12 @@ export default {
35
35
  NoAPIKey: 'OpenAI API Key 为空,请添加自定义 OpenAI API Key',
36
36
  /* eslint-enable */
37
37
  },
38
+ stt: {
39
+ responseError: '服务请求失败,请检查配置或重试',
40
+ },
41
+ tts: {
42
+ responseError: '服务请求失败,请检查配置或重试',
43
+ },
38
44
  unlock: {
39
45
  apikey: {
40
46
  addProxyUrl: '添加 OpenAI 代理地址(可选)',
@@ -109,7 +109,6 @@ export default {
109
109
  },
110
110
  title: '助手信息',
111
111
  },
112
-
113
112
  settingChat: {
114
113
  chatStyleType: {
115
114
  title: '聊天窗口样式',
@@ -195,6 +194,40 @@ export default {
195
194
  },
196
195
  title: '系统设置',
197
196
  },
197
+ settingTTS: {
198
+ openai: {
199
+ sttModel: 'OpenAI 语音识别模型',
200
+ ttsModel: 'OpenAI 语音合成模型',
201
+ },
202
+ showAllLocaleVoice: {
203
+ desc: '关闭则只显示当前语种的声源',
204
+ title: '显示所有语种声源',
205
+ },
206
+ stt: '语音识别设置',
207
+ sttAutoStop: {
208
+ desc: '关闭后,语音识别将不会自动结束,需要手动点击结束按钮',
209
+ title: '自动结束语音识别',
210
+ },
211
+ sttLocale: {
212
+ desc: '语音输入的语种,此选项可提高语音识别准确率',
213
+ title: '语音识别语种',
214
+ },
215
+ sttService: {
216
+ desc: '其中 broswer 为浏览器原生的语音识别服务',
217
+ title: '语音识别服务',
218
+ },
219
+ title: '语音服务',
220
+ tts: '语音合成设置',
221
+ ttsService: {
222
+ desc: '如使用 OpenAI 语音合成服务,需要保证 OpenAI 模型服务已开启',
223
+ title: '语音合成服务',
224
+ },
225
+ voice: {
226
+ desc: '为当前助手挑选一个声音,不同 TTS 服务支持的声源不同',
227
+ preview: '试听声源',
228
+ title: '语音合成声源',
229
+ },
230
+ },
198
231
  settingTheme: {
199
232
  avatar: {
200
233
  title: '头像',
@@ -234,5 +267,6 @@ export default {
234
267
  agent: '默认助手',
235
268
  common: '通用设置',
236
269
  llm: '语言模型',
270
+ tts: '语音服务',
237
271
  },
238
272
  };
@@ -6,4 +6,11 @@ export const URLS = {
6
6
  export const OPENAI_URLS = {
7
7
  chat: '/api/openai/chat',
8
8
  models: '/api/openai/models',
9
+ stt: '/api/openai/stt',
10
+ tts: '/api/openai/tts',
11
+ };
12
+
13
+ export const TTS_URL = {
14
+ edge: '/api/tts/edge-speech',
15
+ microsoft: '/api/tts/microsoft-speech',
9
16
  };
@@ -11,6 +11,7 @@ export enum SettingsTabs {
11
11
  Agent = 'agent',
12
12
  Common = 'common',
13
13
  LLM = 'llm',
14
+ TTS = 'tts',
14
15
  }
15
16
 
16
17
  export interface Guide {
@@ -20,12 +20,28 @@ describe('settingsSelectors', () => {
20
20
  systemRole: '',
21
21
  model: LanguageModel.GPT3_5,
22
22
  params: {},
23
+ tts: {
24
+ showAllLocaleVoice: false,
25
+ sttLocale: 'auto',
26
+ ttsService: 'openai',
27
+ voice: {
28
+ openai: 'alloy',
29
+ },
30
+ },
23
31
  },
24
32
  meta: {
25
33
  avatar: 'Default Agent',
26
34
  description: 'Default agent for testing',
27
35
  },
28
36
  },
37
+ tts: {
38
+ openAI: {
39
+ sttModel: 'whisper-1',
40
+ ttsModel: 'tts-1',
41
+ },
42
+ sttAutoStop: true,
43
+ sttServer: 'openai',
44
+ },
29
45
  languageModel: {
30
46
  openAI: {
31
47
  OPENAI_API_KEY: 'openai-api-key',
@@ -59,12 +75,28 @@ describe('settingsSelectors', () => {
59
75
  top_p: 1,
60
76
  },
61
77
  plugins: [],
78
+ tts: {
79
+ showAllLocaleVoice: false,
80
+ sttLocale: 'auto',
81
+ ttsService: 'openai',
82
+ voice: {
83
+ openai: 'alloy',
84
+ },
85
+ },
62
86
  },
63
87
  meta: {
64
88
  avatar: 'Default Agent',
65
89
  description: 'Default agent for testing',
66
90
  },
67
91
  },
92
+ tts: {
93
+ openAI: {
94
+ sttModel: 'whisper-1',
95
+ ttsModel: 'tts-1',
96
+ },
97
+ sttAutoStop: true,
98
+ sttServer: 'openai',
99
+ },
68
100
  languageModel: {
69
101
  openAI: {
70
102
  OPENAI_API_KEY: 'openai-api-key',
@@ -1,7 +1,12 @@
1
1
  import { DEFAULT_OPENAI_MODEL_LIST } from '@/const/llm';
2
2
  import { DEFAULT_LANG } from '@/const/locale';
3
3
  import { DEFAULT_AGENT_META } from '@/const/meta';
4
- import { DEFAULT_AGENT, DEFAULT_AGENT_CONFIG, DEFAULT_SETTINGS } from '@/const/settings';
4
+ import {
5
+ DEFAULT_AGENT,
6
+ DEFAULT_AGENT_CONFIG,
7
+ DEFAULT_SETTINGS,
8
+ DEFAULT_TTS_CONFIG,
9
+ } from '@/const/settings';
5
10
  import { Locales } from '@/locales/resources';
6
11
  import { GlobalSettings } from '@/types/settings';
7
12
  import { isOnServerSide } from '@/utils/env';
@@ -11,6 +16,8 @@ import { GlobalStore } from '../store';
11
16
 
12
17
  const currentSettings = (s: GlobalStore) => merge(DEFAULT_SETTINGS, s.settings);
13
18
 
19
+ const currentTTS = (s: GlobalStore) => merge(DEFAULT_TTS_CONFIG, s.settings.tts);
20
+
14
21
  const defaultAgent = (s: GlobalStore) => merge(DEFAULT_AGENT, s.settings.defaultAgent);
15
22
 
16
23
  const defaultAgentConfig = (s: GlobalStore) => merge(DEFAULT_AGENT_CONFIG, defaultAgent(s).config);
@@ -49,6 +56,7 @@ const currentLanguage = (s: GlobalStore) => {
49
56
  export const settingsSelectors = {
50
57
  currentLanguage,
51
58
  currentSettings,
59
+ currentTTS,
52
60
  defaultAgent,
53
61
  defaultAgentConfig,
54
62
  defaultAgentMeta,
@@ -2,9 +2,11 @@ import { t } from 'i18next';
2
2
 
3
3
  import { DEFAULT_OPENAI_MODEL_LIST, VISION_MODEL_WHITE_LIST } from '@/const/llm';
4
4
  import { DEFAULT_AVATAR, DEFAULT_BACKGROUND_COLOR } from '@/const/meta';
5
+ import { DEFAUTT_AGENT_TTS_CONFIG } from '@/const/settings';
5
6
  import { SessionStore } from '@/store/session';
6
7
  import { LanguageModel } from '@/types/llm';
7
8
  import { MetaData } from '@/types/meta';
9
+ import { LobeAgentTTSConfig } from '@/types/session';
8
10
  import { merge } from '@/utils/merge';
9
11
 
10
12
  import { sessionSelectors } from '../session/selectors';
@@ -78,6 +80,12 @@ const showTokenTag = (s: SessionStore) => {
78
80
  return DEFAULT_OPENAI_MODEL_LIST.includes(model);
79
81
  };
80
82
 
83
+ const currentAgentTTS = (s: SessionStore): LobeAgentTTSConfig => {
84
+ const config = currentAgentConfig(s);
85
+
86
+ return config?.tts || DEFAUTT_AGENT_TTS_CONFIG;
87
+ };
88
+
81
89
  export const agentSelectors = {
82
90
  currentAgentAvatar,
83
91
  currentAgentBackgroundColor,
@@ -87,6 +95,7 @@ export const agentSelectors = {
87
95
  currentAgentModel,
88
96
  currentAgentPlugins,
89
97
  currentAgentSystemRole,
98
+ currentAgentTTS,
90
99
  currentAgentTitle,
91
100
  getAvatar,
92
101
  getDescription,
@@ -16,13 +16,15 @@ const t = setNamespace('chat/translate');
16
16
  * 翻译事件
17
17
  */
18
18
  export interface ChatTranslateAction {
19
- clearTranslate: (id: string) => void;
19
+ clearTTS: (id: string) => void;
20
20
 
21
+ clearTranslate: (id: string) => void;
21
22
  /**
22
23
  * 翻译消息
23
24
  * @param id
24
25
  */
25
26
  translateMessage: (id: string, targetLang: string) => Promise<void>;
27
+ ttsMessage: (id: string, init?: boolean) => void;
26
28
  }
27
29
 
28
30
  export const chatTranslate: StateCreator<
@@ -31,6 +33,15 @@ export const chatTranslate: StateCreator<
31
33
  [],
32
34
  ChatTranslateAction
33
35
  > = (set, get) => ({
36
+ clearTTS: (id) => {
37
+ get().dispatchMessage({
38
+ id,
39
+ key: 'tts',
40
+ type: 'updateMessageExtra',
41
+ value: null,
42
+ });
43
+ },
44
+
34
45
  clearTranslate: (id) => {
35
46
  get().dispatchMessage({
36
47
  id,
@@ -85,4 +96,16 @@ export const chatTranslate: StateCreator<
85
96
 
86
97
  toggleChatLoading(false);
87
98
  },
99
+
100
+ ttsMessage: (id, init) => {
101
+ const { dispatchMessage } = get();
102
+ dispatchMessage({
103
+ id,
104
+ key: 'tts',
105
+ type: 'updateMessageExtra',
106
+ value: {
107
+ init: Boolean(init),
108
+ },
109
+ });
110
+ },
88
111
  });
@@ -41,6 +41,14 @@ beforeEach(() => {
41
41
  temperature: 0.6,
42
42
  },
43
43
  systemRole: '',
44
+ tts: {
45
+ ttsService: 'openai',
46
+ sttLocale: 'auto',
47
+ showAllLocaleVoice: false,
48
+ voice: {
49
+ openai: 'alloy',
50
+ },
51
+ },
44
52
  },
45
53
  type: 'agent',
46
54
  createAt: 1690110700808,
@@ -215,6 +223,14 @@ describe('organizeChats', () => {
215
223
  params: {
216
224
  temperature: 0.6,
217
225
  },
226
+ tts: {
227
+ ttsService: 'openai',
228
+ sttLocale: 'auto',
229
+ showAllLocaleVoice: false,
230
+ voice: {
231
+ openai: 'alloy',
232
+ },
233
+ },
218
234
  systemRole: '',
219
235
  },
220
236
  createAt: 1690110700808,
@@ -312,6 +312,14 @@ describe('sessionsReducer', () => {
312
312
  model: 'gpt-3.5-turbo',
313
313
  params: {},
314
314
  systemRole: 'system-role',
315
+ tts: {
316
+ showAllLocaleVoice: false,
317
+ sttLocale: 'auto',
318
+ ttsService: 'openai',
319
+ voice: {
320
+ openai: 'alloy',
321
+ },
322
+ },
315
323
  },
316
324
  type: 'agent',
317
325
  meta: {
@@ -354,6 +362,14 @@ describe('sessionsReducer', () => {
354
362
  model: 'gpt-3.5-turbo',
355
363
  params: {},
356
364
  systemRole: 'system',
365
+ tts: {
366
+ showAllLocaleVoice: false,
367
+ sttLocale: 'auto',
368
+ ttsService: 'openai',
369
+ voice: {
370
+ openai: 'alloy',
371
+ },
372
+ },
357
373
  },
358
374
  } as LobeAgentSession,
359
375
  session2: {
@@ -379,6 +395,14 @@ describe('sessionsReducer', () => {
379
395
  draft.session1.config = {
380
396
  model: LanguageModel.GPT4,
381
397
  params: {},
398
+ tts: {
399
+ ttsService: 'openai',
400
+ sttLocale: 'auto',
401
+ showAllLocaleVoice: false,
402
+ voice: {
403
+ openai: 'alloy',
404
+ },
405
+ },
382
406
  systemRole: 'system',
383
407
  };
384
408
  });
@@ -22,6 +22,10 @@ export interface OpenAIFunctionCall {
22
22
  export interface ChatTranslate extends Translate {
23
23
  content?: string;
24
24
  }
25
+
26
+ export interface ChatTTS {
27
+ init?: boolean;
28
+ }
25
29
  export interface ChatMessage extends BaseDataModel {
26
30
  /**
27
31
  * @title 内容
@@ -34,6 +38,8 @@ export interface ChatMessage extends BaseDataModel {
34
38
  fromModel?: string;
35
39
  // 翻译
36
40
  translate?: ChatTranslate;
41
+ // TTS
42
+ tts?: ChatTTS;
37
43
  } & Record<string, any>;
38
44
 
39
45
  files?: string[];