@lobehub/chat 0.117.1 → 0.117.3
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 +52 -0
- package/README.md +2 -2
- package/README.zh-CN.md +8 -8
- package/docs/Deployment/Environment-Variable.md +2 -2
- package/docs/Deployment/Environment-Variable.zh-CN.md +2 -2
- package/package.json +1 -1
- package/src/app/api/market/AgentMarket.test.ts +54 -0
- package/src/app/api/market/AgentMarket.ts +6 -6
- package/src/app/api/plugin/store/Store.test.ts +27 -0
- package/src/app/api/plugin/store/Store.ts +4 -4
- package/src/app/settings/common/Common.tsx +1 -1
- package/src/chains/__tests__/summaryTitle.test.ts +0 -1
- package/src/const/llm.ts +16 -1
- package/src/const/locale.ts +7 -4
- package/src/const/message.ts +10 -1
- package/src/const/settings.ts +0 -2
- package/src/features/AgentSetting/AgentPrompt/index.tsx +1 -1
- package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +1 -1
- package/src/features/Conversation/ChatList/Actions/customAction.ts +1 -1
- package/src/features/Conversation/ChatList/Messages/Assistant.tsx +1 -1
- package/src/features/PluginDevModal/UrlManifestForm.tsx +20 -17
- package/src/locales/create.ts +3 -15
- package/src/locales/resources.ts +83 -0
- package/src/services/__tests__/chat.test.ts +1 -2
- package/src/services/chat.ts +1 -3
- package/src/store/chat/slices/enchance/action.ts +1 -1
- package/src/store/chat/slices/message/action.ts +6 -7
- package/src/store/session/slices/agent/selectors.ts +2 -2
- package/src/const/modelTokens.ts +0 -12
- package/src/locales/options.ts +0 -69
- package/src/utils/message.ts +0 -28
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.117.3](https://github.com/lobehub/lobe-chat/compare/v0.117.2...v0.117.3)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-12-28**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: Fix tool calls at end, fix vision model max tokens, improve vision model checker.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **misc**: Fix tool calls at end ([b0b615a](https://github.com/lobehub/lobe-chat/commit/b0b615a))
|
|
21
|
+
- **misc**: Fix vision model max tokens ([8b704a0](https://github.com/lobehub/lobe-chat/commit/8b704a0))
|
|
22
|
+
- **misc**: Improve vision model checker ([da7d177](https://github.com/lobehub/lobe-chat/commit/da7d177))
|
|
23
|
+
|
|
24
|
+
</details>
|
|
25
|
+
|
|
26
|
+
<div align="right">
|
|
27
|
+
|
|
28
|
+
[](#readme-top)
|
|
29
|
+
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
### [Version 0.117.2](https://github.com/lobehub/lobe-chat/compare/v0.117.1...v0.117.2)
|
|
33
|
+
|
|
34
|
+
<sup>Released on **2023-12-28**</sup>
|
|
35
|
+
|
|
36
|
+
#### 🐛 Bug Fixes
|
|
37
|
+
|
|
38
|
+
- **misc**: Fix market locale missing.
|
|
39
|
+
|
|
40
|
+
<br/>
|
|
41
|
+
|
|
42
|
+
<details>
|
|
43
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
44
|
+
|
|
45
|
+
#### What's fixed
|
|
46
|
+
|
|
47
|
+
- **misc**: Fix market locale missing, closes [#851](https://github.com/lobehub/lobe-chat/issues/851) ([e23ec66](https://github.com/lobehub/lobe-chat/commit/e23ec66))
|
|
48
|
+
|
|
49
|
+
</details>
|
|
50
|
+
|
|
51
|
+
<div align="right">
|
|
52
|
+
|
|
53
|
+
[](#readme-top)
|
|
54
|
+
|
|
55
|
+
</div>
|
|
56
|
+
|
|
5
57
|
### [Version 0.117.1](https://github.com/lobehub/lobe-chat/compare/v0.117.0...v0.117.1)
|
|
6
58
|
|
|
7
59
|
<sup>Released on **2023-12-27**</sup>
|
package/README.md
CHANGED
|
@@ -211,11 +211,11 @@ Our marketplace is not just a showcase platform but also a collaborative space.
|
|
|
211
211
|
| Recent Submits | Description |
|
|
212
212
|
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
213
213
|
| [Deployment Specialist Agent](https://chat-preview.lobehub.com/market?agent=deployment-agent)<br/><sup>By **[amitalokbera](https://github.com/amitalokbera)** on **2023-12-27**</sup> | An AI Deployment Specialist is an expert in managing the full deployment lifecycle of software applications, particularly web applications.<br/>`code` `deployment` `software` |
|
|
214
|
+
| [Overview of Art Thesis Experts](https://chat-preview.lobehub.com/market?agent=thesis-overview)<br/><sup>By **[caoyang2002](https://github.com/caoyang2002)** on **2023-12-27**</sup> | Specializing in brief thesis and art criticism<br/>`art` `thesis` `critique` |
|
|
214
215
|
| [American English Transcreation Expert](https://chat-preview.lobehub.com/market?agent=to-local-english)<br/><sup>By **[doresu](https://github.com/doresu)** on **2023-12-27**</sup> | Rough old editor, seasoned writer, and translator, proficient in translating English directly and transforming it into authentic American English<br/>`translation` `editing` `writing` `translator` |
|
|
215
216
|
| [Academic Proofreading Expert](https://chat-preview.lobehub.com/market?agent=academic-paragraph-refiner)<br/><sup>By **[Feliks151450](https://github.com/Feliks151450)** on **2023-12-26**</sup> | Highly skilled in advanced research proofreading and language editing, specializing in multiple research fields and proficient in academic English.<br/>`proofreading` `writing` `research` |
|
|
216
|
-
| [Flutter Maestro](https://chat-preview.lobehub.com/market?agent=flutter-dev)<br/><sup>By **[kamaravichow](https://github.com/kamaravichow)** on **2023-12-25**</sup> | A developer expert in Flutter framework and Dart programming language.<br/>`flutter` `development` `dart` `programming` `widgets` |
|
|
217
217
|
|
|
218
|
-
> 📊 Total agents: [<kbd>**
|
|
218
|
+
> 📊 Total agents: [<kbd>**82**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
219
219
|
|
|
220
220
|
<!-- AGENT LIST -->
|
|
221
221
|
|
package/README.zh-CN.md
CHANGED
|
@@ -184,14 +184,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
|
|
|
184
184
|
|
|
185
185
|
<!-- AGENT LIST -->
|
|
186
186
|
|
|
187
|
-
| 最近新增 | 助手说明
|
|
188
|
-
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
189
|
-
| [部署专家代理](https://chat-preview.lobehub.com/market?agent=deployment-agent)<br/><sup>By **[amitalokbera](https://github.com/amitalokbera)** on **2023-12-27**</sup> | AI 部署专家是管理软件应用的完整部署生命周期的专家,特别是 Web 应用。<br/>`代码` `部署` `容器化`
|
|
190
|
-
| [
|
|
191
|
-
| [
|
|
192
|
-
| [
|
|
193
|
-
|
|
194
|
-
> 📊 Total agents: [<kbd>**
|
|
187
|
+
| 最近新增 | 助手说明 |
|
|
188
|
+
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
189
|
+
| [部署专家代理](https://chat-preview.lobehub.com/market?agent=deployment-agent)<br/><sup>By **[amitalokbera](https://github.com/amitalokbera)** on **2023-12-27**</sup> | AI 部署专家是管理软件应用的完整部署生命周期的专家,特别是 Web 应用。<br/>`代码` `部署` `容器化` |
|
|
190
|
+
| [美术论文概述专家](https://chat-preview.lobehub.com/market?agent=thesis-overview)<br/><sup>By **[caoyang2002](https://github.com/caoyang2002)** on **2023-12-27**</sup> | 擅长论文简述与美术评论<br/>`美术` `论文` `评论` |
|
|
191
|
+
| [美式英语转译专家](https://chat-preview.lobehub.com/market?agent=to-local-english)<br/><sup>By **[doresu](https://github.com/doresu)** on **2023-12-27**</sup> | 粗鲁老编辑、资深作家和翻译家,擅长直译英文并转化为地道的美式英语<br/>`翻译` `编辑` `写作` `翻译家` |
|
|
192
|
+
| [学术润色专家](https://chat-preview.lobehub.com/market?agent=academic-paragraph-refiner)<br/><sup>By **[Feliks151450](https://github.com/Feliks151450)** on **2023-12-26**</sup> | 高级研究校对及语言编辑,专业于多个研究领域,精通学术英语。<br/>`校对` `写作` `研究` |
|
|
193
|
+
|
|
194
|
+
> 📊 Total agents: [<kbd>**82**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
195
195
|
|
|
196
196
|
<!-- AGENT LIST -->
|
|
197
197
|
|
|
@@ -16,7 +16,7 @@ LobeChat provides additional configuration options during deployment, which can
|
|
|
16
16
|
- [`AZURE_API_VERSION`](#azure_api_version)
|
|
17
17
|
- [Plugin Service](#plugin-service)
|
|
18
18
|
- [`PLUGINS_INDEX_URL`](#plugins_index_url)
|
|
19
|
-
- [`
|
|
19
|
+
- [`PLUGIN_SETTINGS`](#plugin_settings)
|
|
20
20
|
- [Agent Service](#agent-service)
|
|
21
21
|
- [`AGENTS_INDEX_URL`](#agents_index_url)
|
|
22
22
|
- [Data Analytics](#data-analytics)
|
|
@@ -94,7 +94,7 @@ If you need to use Azure OpenAI to provide model services, you can refer to the
|
|
|
94
94
|
- Description: The index address of the LobeChat plugin market. If you have deployed the plugin market service yourself, you can use this variable to override the default plugin market address
|
|
95
95
|
- Default: `https://chat-plugins.lobehub.com`
|
|
96
96
|
|
|
97
|
-
### `
|
|
97
|
+
### `PLUGIN_SETTINGS`
|
|
98
98
|
|
|
99
99
|
- Type: Optional
|
|
100
100
|
- Description: Used to set the plugin settings, the format is `plugin-identifier:key1=value1;key2=value2`, multiple settings fields are separated by semicolons `;`, multiple plugin settings are separated by commas `,`.
|
|
@@ -16,7 +16,7 @@ LobeChat 在部署时提供了一些额外的配置项,使用环境变量进
|
|
|
16
16
|
- [`AZURE_API_VERSION`](#azure_api_version)
|
|
17
17
|
- [插件服务](#插件服务)
|
|
18
18
|
- [`PLUGINS_INDEX_URL`](#plugins_index_url)
|
|
19
|
-
- [`
|
|
19
|
+
- [`PLUGIN_SETTINGS`](#plugin_settings)
|
|
20
20
|
- [角色服务](#角色服务)
|
|
21
21
|
- [`AGENTS_INDEX_URL`](#agents_index_url)
|
|
22
22
|
- [数据统计](#数据统计)
|
|
@@ -92,7 +92,7 @@ LobeChat 在部署时提供了一些额外的配置项,使用环境变量进
|
|
|
92
92
|
- 描述:LobeChat 插件市场的索引地址,如果你自行部署了插件市场的服务,可以使用该变量来覆盖默认的插件市场地址
|
|
93
93
|
- 默认值:`https://chat-plugins.lobehub.com`
|
|
94
94
|
|
|
95
|
-
### `
|
|
95
|
+
### `PLUGIN_SETTINGS`
|
|
96
96
|
|
|
97
97
|
- 类型:可选
|
|
98
98
|
- 描述:用于配置插件的设置,使用 `插件名:设置字段=设置值` 的格式来配置插件的设置,多个设置字段用英文分号 `;` 隔开,多个插件设置使用英文逗号`,`隔开。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.117.
|
|
3
|
+
"version": "0.117.3",
|
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { AgentMarket } from './AgentMarket';
|
|
4
|
+
|
|
5
|
+
const baseURL = 'https://chat-agents.lobehub.com';
|
|
6
|
+
describe('AgentMarket', () => {
|
|
7
|
+
it('should return the default index URL when no language is provided', () => {
|
|
8
|
+
const agentMarket = new AgentMarket();
|
|
9
|
+
const url = agentMarket.getAgentIndexUrl();
|
|
10
|
+
expect(url).toBe(baseURL);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('should return the index URL for a supported language', () => {
|
|
14
|
+
const agentMarket = new AgentMarket();
|
|
15
|
+
const url = agentMarket.getAgentIndexUrl('ko-KR');
|
|
16
|
+
expect(url).toBe('https://chat-agents.lobehub.com/index.ko-KR.json');
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should return the zh-CN URL for zh locale', () => {
|
|
20
|
+
const agentMarket = new AgentMarket();
|
|
21
|
+
const url = agentMarket.getAgentIndexUrl('zh' as any);
|
|
22
|
+
expect(url).toBe('https://chat-agents.lobehub.com/index.zh-CN.json');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should return the default URL for en locale', () => {
|
|
26
|
+
const agentMarket = new AgentMarket();
|
|
27
|
+
const url = agentMarket.getAgentIndexUrl('en' as any);
|
|
28
|
+
expect(url).toBe('https://chat-agents.lobehub.com');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should return the base URL if the provided language is not supported', () => {
|
|
32
|
+
const agentMarket = new AgentMarket();
|
|
33
|
+
const url = agentMarket.getAgentIndexUrl('fr' as any);
|
|
34
|
+
expect(url).toBe(baseURL);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should return the agent URL with default language when no language is provided', () => {
|
|
38
|
+
const agentMarket = new AgentMarket();
|
|
39
|
+
const url = agentMarket.getAgentUrl('agent-123');
|
|
40
|
+
expect(url).toBe(`${baseURL}/agent-123.json`);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should return the agent URL for a supported language', () => {
|
|
44
|
+
const agentMarket = new AgentMarket();
|
|
45
|
+
const url = agentMarket.getAgentUrl('agent-123', 'es-ES');
|
|
46
|
+
expect(url).toBe(`${baseURL}/agent-123.es-ES.json`);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should return the agent URL without language suffix if the provided language is not supported', () => {
|
|
50
|
+
const agentMarket = new AgentMarket();
|
|
51
|
+
const url = agentMarket.getAgentUrl('agent-123', 'fr' as any);
|
|
52
|
+
expect(url).toBe(`${baseURL}/agent-123.json`);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import urlJoin from 'url-join';
|
|
2
2
|
|
|
3
3
|
import { getServerConfig } from '@/config/server';
|
|
4
|
-
import { DEFAULT_LANG,
|
|
5
|
-
import { Locales } from '@/locales/resources';
|
|
4
|
+
import { DEFAULT_LANG, isLocaleNotSupport } from '@/const/locale';
|
|
5
|
+
import { Locales, normalizeLocale } from '@/locales/resources';
|
|
6
6
|
|
|
7
7
|
export class AgentMarket {
|
|
8
8
|
private readonly baseUrl: string;
|
|
@@ -12,14 +12,14 @@ export class AgentMarket {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
getAgentIndexUrl = (lang: Locales = DEFAULT_LANG) => {
|
|
15
|
-
if (
|
|
15
|
+
if (isLocaleNotSupport(lang)) return this.baseUrl;
|
|
16
16
|
|
|
17
|
-
return urlJoin(this.baseUrl, `index.${lang}.json`);
|
|
17
|
+
return urlJoin(this.baseUrl, `index.${normalizeLocale(lang)}.json`);
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
getAgentUrl = (identifier: string, lang: Locales = DEFAULT_LANG) => {
|
|
21
|
-
if (
|
|
21
|
+
if (isLocaleNotSupport(lang)) return urlJoin(this.baseUrl, `${identifier}.json`);
|
|
22
22
|
|
|
23
|
-
return urlJoin(this.baseUrl, `${identifier}.${lang}.json`);
|
|
23
|
+
return urlJoin(this.baseUrl, `${identifier}.${normalizeLocale(lang)}.json`);
|
|
24
24
|
};
|
|
25
25
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { isLocaleNotSupport } from '@/const/locale';
|
|
4
|
+
|
|
5
|
+
import { PluginStore } from './Store';
|
|
6
|
+
|
|
7
|
+
const baseURL = 'https://chat-plugins.lobehub.com';
|
|
8
|
+
|
|
9
|
+
describe('PluginStore', () => {
|
|
10
|
+
it('should return the default index URL when no language is provided', () => {
|
|
11
|
+
const pluginStore = new PluginStore();
|
|
12
|
+
const url = pluginStore.getPluginIndexUrl();
|
|
13
|
+
expect(url).toBe(baseURL);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('should return the index URL for a supported language', () => {
|
|
17
|
+
const pluginStore = new PluginStore();
|
|
18
|
+
const url = pluginStore.getPluginIndexUrl('en-US');
|
|
19
|
+
expect(url).toBe(baseURL);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should return the base URL if the provided language is not supported', () => {
|
|
23
|
+
const pluginStore = new PluginStore();
|
|
24
|
+
const url = pluginStore.getPluginIndexUrl('fr-FR');
|
|
25
|
+
expect(url).toBe(`${baseURL}/index.fr-FR.json`);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import urlJoin from 'url-join';
|
|
2
2
|
|
|
3
3
|
import { getServerConfig } from '@/config/server';
|
|
4
|
-
import { DEFAULT_LANG,
|
|
5
|
-
import { Locales } from '@/locales/resources';
|
|
4
|
+
import { DEFAULT_LANG, isLocaleNotSupport } from '@/const/locale';
|
|
5
|
+
import { Locales, normalizeLocale } from '@/locales/resources';
|
|
6
6
|
|
|
7
7
|
export class PluginStore {
|
|
8
8
|
private readonly baseUrl: string;
|
|
@@ -12,8 +12,8 @@ export class PluginStore {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
getPluginIndexUrl = (lang: Locales = DEFAULT_LANG) => {
|
|
15
|
-
if (
|
|
15
|
+
if (isLocaleNotSupport(lang)) return this.baseUrl;
|
|
16
16
|
|
|
17
|
-
return urlJoin(this.baseUrl, `index.${lang}.json`);
|
|
17
|
+
return urlJoin(this.baseUrl, `index.${normalizeLocale(lang)}.json`);
|
|
18
18
|
};
|
|
19
19
|
}
|
|
@@ -9,7 +9,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
9
9
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
10
10
|
import { DEFAULT_SETTINGS } from '@/const/settings';
|
|
11
11
|
import AvatarWithUpload from '@/features/AvatarWithUpload';
|
|
12
|
-
import { localeOptions } from '@/locales/
|
|
12
|
+
import { localeOptions } from '@/locales/resources';
|
|
13
13
|
import { useChatStore } from '@/store/chat';
|
|
14
14
|
import { useFileStore } from '@/store/file';
|
|
15
15
|
import { useGlobalStore } from '@/store/global';
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Mock, describe, expect, it, vi } from 'vitest';
|
|
2
2
|
|
|
3
|
-
import { ModelTokens } from '@/const/modelTokens';
|
|
4
3
|
import { chatHelpers } from '@/store/chat/helpers';
|
|
5
4
|
import { globalHelpers } from '@/store/global/helpers';
|
|
6
5
|
import { LanguageModel } from '@/types/llm';
|
package/src/const/llm.ts
CHANGED
|
@@ -14,4 +14,19 @@ export const LanguageModelWhiteList = [
|
|
|
14
14
|
export const DEFAULT_OPENAI_MODEL_LIST: string[] = Object.values(LanguageModel);
|
|
15
15
|
|
|
16
16
|
// vision model white list, these models will change the content from string to array
|
|
17
|
-
|
|
17
|
+
// refs: https://github.com/lobehub/lobe-chat/issues/790
|
|
18
|
+
export const isVisionModel = (model?: string) => !!model && model.includes('vision');
|
|
19
|
+
|
|
20
|
+
// refs: https://github.com/lobehub/lobe-chat/issues/837
|
|
21
|
+
export const GPT4_VISION_MODEL_DEFAULT_MAX_TOKENS = 2048;
|
|
22
|
+
|
|
23
|
+
// refs to: https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo
|
|
24
|
+
export const ModelTokens: Record<LanguageModel, number> = {
|
|
25
|
+
[LanguageModel.GPT3_5]: 4096,
|
|
26
|
+
[LanguageModel.GPT3_5_1106]: 16_385,
|
|
27
|
+
[LanguageModel.GPT3_5_16K]: 16_385,
|
|
28
|
+
[LanguageModel.GPT4]: 8196,
|
|
29
|
+
[LanguageModel.GPT4_PREVIEW]: 128_000,
|
|
30
|
+
[LanguageModel.GPT4_VISION_PREVIEW]: 128_000,
|
|
31
|
+
[LanguageModel.GPT4_32K]: 32_768,
|
|
32
|
+
};
|
package/src/const/locale.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Locales } from '@/locales/resources';
|
|
1
|
+
import { Locales, normalizeLocale, supportLocales } from '@/locales/resources';
|
|
3
2
|
|
|
4
3
|
export const DEFAULT_LANG = 'en-US';
|
|
5
4
|
export const LOBE_LOCALE_COOKIE = 'LOBE_LOCALE';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Check if the language is supported
|
|
8
|
+
* @param locale
|
|
9
|
+
*/
|
|
10
|
+
export const isLocaleNotSupport = (locale: Locales) => {
|
|
11
|
+
return normalizeLocale(locale) === DEFAULT_LANG || !supportLocales.includes(locale);
|
|
9
12
|
};
|
package/src/const/message.ts
CHANGED
|
@@ -3,4 +3,13 @@ export const LOADING_FLAT = '...';
|
|
|
3
3
|
// start with this,it should be a function message
|
|
4
4
|
export const FUNCTION_MESSAGE_FLAG = '{"tool_calls"';
|
|
5
5
|
|
|
6
|
-
export const
|
|
6
|
+
export const isFunctionMessageAtStart = (content: string) => {
|
|
7
|
+
return content.startsWith(FUNCTION_MESSAGE_FLAG);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const testFunctionMessageAtEnd = (content: string) => {
|
|
11
|
+
const regExp = /{"tool_calls":.*?}}/;
|
|
12
|
+
const match = content.match(regExp);
|
|
13
|
+
|
|
14
|
+
return { content: match ? match[0] : '', valid: match };
|
|
15
|
+
};
|
package/src/const/settings.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
7
7
|
import { Flexbox } from 'react-layout-kit';
|
|
8
8
|
|
|
9
9
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
10
|
-
import { ModelTokens } from '@/const/
|
|
10
|
+
import { ModelTokens } from '@/const/llm';
|
|
11
11
|
import { useTokenCount } from '@/hooks/useTokenCount';
|
|
12
12
|
import { LanguageModel } from '@/types/llm';
|
|
13
13
|
|
|
@@ -2,7 +2,7 @@ import { TokenTag, Tooltip } from '@lobehub/ui';
|
|
|
2
2
|
import { memo } from 'react';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
|
|
5
|
-
import { ModelTokens } from '@/const/
|
|
5
|
+
import { ModelTokens } from '@/const/llm';
|
|
6
6
|
import { useTokenCount } from '@/hooks/useTokenCount';
|
|
7
7
|
import { useChatStore } from '@/store/chat';
|
|
8
8
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
@@ -2,7 +2,7 @@ import { ActionIconGroupItems } from '@lobehub/ui/es/ActionIconGroup';
|
|
|
2
2
|
import { LanguagesIcon, Play } from 'lucide-react';
|
|
3
3
|
import { useTranslation } from 'react-i18next';
|
|
4
4
|
|
|
5
|
-
import { localeOptions } from '@/locales/
|
|
5
|
+
import { localeOptions } from '@/locales/resources';
|
|
6
6
|
|
|
7
7
|
export const useCustomActions = () => {
|
|
8
8
|
const { t } = useTranslation('chat');
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ReactNode, memo } from 'react';
|
|
2
2
|
|
|
3
|
+
import { isFunctionMessageAtStart } from '@/const/message';
|
|
3
4
|
import { useChatStore } from '@/store/chat';
|
|
4
5
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
5
6
|
import { ChatMessage } from '@/types/message';
|
|
6
|
-
import { isFunctionMessageAtStart } from '@/utils/message';
|
|
7
7
|
|
|
8
8
|
import Inspector from '../Plugins/Inspector';
|
|
9
9
|
import { DefaultMessage } from './Default';
|
|
@@ -12,24 +12,27 @@ import { useToolStore } from '@/store/tool';
|
|
|
12
12
|
import { pluginSelectors } from '@/store/tool/selectors';
|
|
13
13
|
import { PluginInstallError } from '@/types/tool/plugin';
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
(
|
|
17
|
-
|
|
15
|
+
interface ProxyCheckerProps {
|
|
16
|
+
onChange?: (value: boolean) => void;
|
|
17
|
+
value?: boolean;
|
|
18
|
+
}
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
20
|
+
const ProxyChecker = memo<ProxyCheckerProps>(({ value, onChange }) => {
|
|
21
|
+
const { t } = useTranslation('plugin');
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<Flexbox
|
|
25
|
+
gap={8}
|
|
26
|
+
horizontal
|
|
27
|
+
onClick={() => {
|
|
28
|
+
onChange?.(!value);
|
|
29
|
+
}}
|
|
30
|
+
style={{ cursor: 'pointer' }}
|
|
31
|
+
>
|
|
32
|
+
<Checkbox checked={value} /> {t('dev.customParams.useProxy.label')}
|
|
33
|
+
</Flexbox>
|
|
34
|
+
);
|
|
35
|
+
});
|
|
33
36
|
|
|
34
37
|
const UrlManifestForm = memo<{ form: FormInstance; isEditMode: boolean }>(
|
|
35
38
|
({ form, isEditMode }) => {
|
package/src/locales/create.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { initReactI18next } from 'react-i18next';
|
|
|
6
6
|
import { getClientConfig } from '@/config/client';
|
|
7
7
|
import { DEFAULT_LANG, LOBE_LOCALE_COOKIE } from '@/const/locale';
|
|
8
8
|
import { COOKIE_CACHE_DAYS } from '@/const/settings';
|
|
9
|
+
import { normalizeLocale } from '@/locales/resources';
|
|
9
10
|
import { isDev, isOnServerSide } from '@/utils/env';
|
|
10
11
|
|
|
11
12
|
const { I18N_DEBUG, I18N_DEBUG_BROWSER, I18N_DEBUG_SERVER } = getClientConfig();
|
|
@@ -17,22 +18,9 @@ export const createI18nNext = (lang?: string) => {
|
|
|
17
18
|
.use(LanguageDetector)
|
|
18
19
|
.use(
|
|
19
20
|
resourcesToBackend(async (lng: string, ns: string) => {
|
|
20
|
-
|
|
21
|
-
case 'zh-CN':
|
|
22
|
-
case 'zh': {
|
|
23
|
-
if (isDev) return import(`./default/${ns}`);
|
|
21
|
+
if (isDev && lng === 'zh-CN') return import(`./default/${ns}`);
|
|
24
22
|
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
case 'en': {
|
|
29
|
-
return import(`@/../locales/en-US/${ns}.json`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
default: {
|
|
33
|
-
return import(`@/../locales/${lng}/${ns}.json`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
23
|
+
return import(`@/../locales/${normalizeLocale(lng)}/${ns}.json`);
|
|
36
24
|
}),
|
|
37
25
|
);
|
|
38
26
|
|
package/src/locales/resources.ts
CHANGED
|
@@ -16,3 +16,86 @@ export const locales = [
|
|
|
16
16
|
|
|
17
17
|
export type DefaultResources = typeof resources;
|
|
18
18
|
export type Locales = (typeof locales)[number];
|
|
19
|
+
|
|
20
|
+
export const normalizeLocale = (locale: string) => {
|
|
21
|
+
switch (locale) {
|
|
22
|
+
case 'zh-CN':
|
|
23
|
+
case 'zh': {
|
|
24
|
+
return 'zh-CN';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
case 'en': {
|
|
28
|
+
return 'en-US';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
default: {
|
|
32
|
+
return locale;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
type LocaleOptions = {
|
|
38
|
+
label: string;
|
|
39
|
+
value: Locales;
|
|
40
|
+
}[];
|
|
41
|
+
|
|
42
|
+
export const localeOptions: LocaleOptions = [
|
|
43
|
+
{
|
|
44
|
+
label: '简体中文',
|
|
45
|
+
value: 'zh-CN',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
label: '繁體中文',
|
|
49
|
+
value: 'zh-TW',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
label: 'English',
|
|
53
|
+
value: 'en-US',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
label: '日本語',
|
|
57
|
+
value: 'ja-JP',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
label: '한국어',
|
|
61
|
+
value: 'ko-KR',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
label: 'Deutsch',
|
|
65
|
+
value: 'de-DE',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
label: 'Español',
|
|
69
|
+
value: 'es-ES',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
label: 'Français',
|
|
73
|
+
value: 'fr-FR',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
label: 'Português',
|
|
77
|
+
value: 'pt-BR',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
label: 'Русский',
|
|
81
|
+
value: 'ru-RU',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
label: 'Türkçe',
|
|
85
|
+
value: 'tr-TR',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
label: 'Polski',
|
|
89
|
+
value: 'pl-PL',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
label: 'Nederlands',
|
|
93
|
+
value: 'nl-NL',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
label: 'Italiano',
|
|
97
|
+
value: 'it-IT',
|
|
98
|
+
},
|
|
99
|
+
] as LocaleOptions;
|
|
100
|
+
|
|
101
|
+
export const supportLocales: string[] = [...locales, 'en', 'zh'];
|
|
@@ -2,7 +2,6 @@ import { LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
|
|
2
2
|
import { act } from '@testing-library/react';
|
|
3
3
|
import { describe, expect, it, vi } from 'vitest';
|
|
4
4
|
|
|
5
|
-
import { VISION_MODEL_WHITE_LIST } from '@/const/llm';
|
|
6
5
|
import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
|
|
7
6
|
import { useFileStore } from '@/store/file';
|
|
8
7
|
import { useToolStore } from '@/store/tool';
|
|
@@ -74,7 +73,7 @@ describe('ChatService', () => {
|
|
|
74
73
|
it('should not use tools for models in the vision model whitelist', async () => {
|
|
75
74
|
const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
|
|
76
75
|
const messages = [{ content: 'Hello', role: 'user' }] as ChatMessage[];
|
|
77
|
-
const modelInWhitelist =
|
|
76
|
+
const modelInWhitelist = 'gpt-4-vision-preview';
|
|
78
77
|
|
|
79
78
|
await chatService.createAssistantMessage({
|
|
80
79
|
messages,
|
package/src/services/chat.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { PluginRequestPayload, createHeadersWithPluginSettings } from '@lobehub/
|
|
|
2
2
|
import { produce } from 'immer';
|
|
3
3
|
import { merge } from 'lodash-es';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { isVisionModel } from '@/const/llm';
|
|
6
6
|
import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
|
|
7
7
|
import { filesSelectors, useFileStore } from '@/store/file';
|
|
8
8
|
import { useToolStore } from '@/store/tool';
|
|
@@ -15,8 +15,6 @@ import { fetchAIFactory, getMessageError } from '@/utils/fetch';
|
|
|
15
15
|
import { createHeaderWithOpenAI } from './_header';
|
|
16
16
|
import { OPENAI_URLS, PLUGINS_URLS } from './_url';
|
|
17
17
|
|
|
18
|
-
const isVisionModel = (model?: string) => model && VISION_MODEL_WHITE_LIST.includes(model);
|
|
19
|
-
|
|
20
18
|
interface FetchOptions {
|
|
21
19
|
signal?: AbortSignal | undefined;
|
|
22
20
|
}
|
|
@@ -4,7 +4,7 @@ import { StateCreator } from 'zustand/vanilla';
|
|
|
4
4
|
|
|
5
5
|
import { chainLangDetect } from '@/chains/langDetect';
|
|
6
6
|
import { chainTranslate } from '@/chains/translate';
|
|
7
|
-
import { supportLocales } from '@/locales/
|
|
7
|
+
import { supportLocales } from '@/locales/resources';
|
|
8
8
|
import { chatService } from '@/services/chat';
|
|
9
9
|
import { fileService } from '@/services/file';
|
|
10
10
|
import { imageGenerationService } from '@/services/imageGeneration';
|
|
@@ -5,9 +5,8 @@ import { template } from 'lodash-es';
|
|
|
5
5
|
import useSWR, { SWRResponse, mutate } from 'swr';
|
|
6
6
|
import { StateCreator } from 'zustand/vanilla';
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import { LOADING_FLAT } from '@/const/message';
|
|
10
|
-
import { VISION_MODEL_DEFAULT_MAX_TOKENS } from '@/const/settings';
|
|
8
|
+
import { GPT4_VISION_MODEL_DEFAULT_MAX_TOKENS } from '@/const/llm';
|
|
9
|
+
import { LOADING_FLAT, isFunctionMessageAtStart, testFunctionMessageAtEnd } from '@/const/message';
|
|
11
10
|
import { CreateMessageParams } from '@/database/models/message';
|
|
12
11
|
import { DB_Message } from '@/database/schemas/message';
|
|
13
12
|
import { chatService } from '@/services/chat';
|
|
@@ -19,7 +18,6 @@ import { useSessionStore } from '@/store/session';
|
|
|
19
18
|
import { agentSelectors } from '@/store/session/selectors';
|
|
20
19
|
import { ChatMessage } from '@/types/message';
|
|
21
20
|
import { fetchSSE } from '@/utils/fetch';
|
|
22
|
-
import { isFunctionMessageAtStart, testFunctionMessageAtEnd } from '@/utils/message';
|
|
23
21
|
import { setNamespace } from '@/utils/storeDebug';
|
|
24
22
|
|
|
25
23
|
import { chatSelectors } from '../../selectors';
|
|
@@ -339,11 +337,12 @@ export const chatMessage: StateCreator<
|
|
|
339
337
|
config.params.max_tokens = config.enableMaxTokens ? config.params.max_tokens : undefined;
|
|
340
338
|
|
|
341
339
|
// 5. handle config for the vision model
|
|
342
|
-
// Due to vision model's default max_tokens is very small
|
|
340
|
+
// Due to the gpt-4-vision-preview model's default max_tokens is very small
|
|
343
341
|
// we need to set the max_tokens a larger one.
|
|
344
|
-
if (
|
|
342
|
+
if (config.model === 'gpt-4-vision-preview') {
|
|
345
343
|
/* eslint-disable unicorn/no-lonely-if */
|
|
346
|
-
if (!config.params.max_tokens)
|
|
344
|
+
if (!config.params.max_tokens)
|
|
345
|
+
config.params.max_tokens = GPT4_VISION_MODEL_DEFAULT_MAX_TOKENS;
|
|
347
346
|
}
|
|
348
347
|
|
|
349
348
|
const fetcher = () =>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { VoiceList } from '@lobehub/tts';
|
|
2
2
|
import { t } from 'i18next';
|
|
3
3
|
|
|
4
|
-
import { DEFAULT_OPENAI_MODEL_LIST,
|
|
4
|
+
import { DEFAULT_OPENAI_MODEL_LIST, isVisionModel } from '@/const/llm';
|
|
5
5
|
import { DEFAULT_AVATAR, DEFAULT_BACKGROUND_COLOR, DEFAULT_INBOX_AVATAR } from '@/const/meta';
|
|
6
6
|
import { DEFAULT_AGENT_CONFIG, DEFAUTT_AGENT_TTS_CONFIG } from '@/const/settings';
|
|
7
7
|
import { useGlobalStore } from '@/store/global';
|
|
@@ -109,7 +109,7 @@ const hasSystemRole = (s: SessionStore) => {
|
|
|
109
109
|
};
|
|
110
110
|
const modelHasVisionAbility = (s: SessionStore): boolean => {
|
|
111
111
|
const model = currentAgentModel(s);
|
|
112
|
-
return
|
|
112
|
+
return isVisionModel(model);
|
|
113
113
|
};
|
|
114
114
|
|
|
115
115
|
export const agentSelectors = {
|
package/src/const/modelTokens.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { LanguageModel } from '@/types/llm';
|
|
2
|
-
|
|
3
|
-
// refs to: https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo
|
|
4
|
-
export const ModelTokens: Record<LanguageModel, number> = {
|
|
5
|
-
[LanguageModel.GPT3_5]: 4096,
|
|
6
|
-
[LanguageModel.GPT3_5_1106]: 16_385,
|
|
7
|
-
[LanguageModel.GPT3_5_16K]: 16_385,
|
|
8
|
-
[LanguageModel.GPT4]: 8196,
|
|
9
|
-
[LanguageModel.GPT4_PREVIEW]: 128_000,
|
|
10
|
-
[LanguageModel.GPT4_VISION_PREVIEW]: 128_000,
|
|
11
|
-
[LanguageModel.GPT4_32K]: 32_768,
|
|
12
|
-
};
|
package/src/locales/options.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import type { Locales } from '@/types/locale';
|
|
2
|
-
|
|
3
|
-
import { locales } from './resources';
|
|
4
|
-
|
|
5
|
-
type LocaleOptions = {
|
|
6
|
-
label: string;
|
|
7
|
-
value: Locales;
|
|
8
|
-
}[];
|
|
9
|
-
|
|
10
|
-
export const localeOptions: LocaleOptions = [
|
|
11
|
-
{
|
|
12
|
-
label: '简体中文',
|
|
13
|
-
value: 'zh-CN',
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
label: '繁體中文',
|
|
17
|
-
value: 'zh-TW',
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
label: 'English',
|
|
21
|
-
value: 'en-US',
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
label: '日本語',
|
|
25
|
-
value: 'ja-JP',
|
|
26
|
-
},
|
|
27
|
-
{
|
|
28
|
-
label: '한국어',
|
|
29
|
-
value: 'ko-KR',
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
label: 'Deutsch',
|
|
33
|
-
value: 'de-DE',
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
label: 'Español',
|
|
37
|
-
value: 'es-ES',
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
label: 'Français',
|
|
41
|
-
value: 'fr-FR',
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
label: 'Português',
|
|
45
|
-
value: 'pt-BR',
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
label: 'Русский',
|
|
49
|
-
value: 'ru-RU',
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
label: 'Türkçe',
|
|
53
|
-
value: 'tr-TR',
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
label: 'Polski',
|
|
57
|
-
value: 'pl-PL',
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
label: 'Nederlands',
|
|
61
|
-
value: 'nl-NL',
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
label: 'Italiano',
|
|
65
|
-
value: 'it-IT',
|
|
66
|
-
},
|
|
67
|
-
] as LocaleOptions;
|
|
68
|
-
|
|
69
|
-
export const supportLocales: string[] = [...locales, 'en', 'zh'];
|
package/src/utils/message.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { FUNCTION_MESSAGE_FLAG } from '@/const/message';
|
|
2
|
-
|
|
3
|
-
export const isFunctionMessageAtStart = (content: string) => {
|
|
4
|
-
return content.startsWith(FUNCTION_MESSAGE_FLAG);
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
export const testFunctionMessageAtEnd = (content: string) => {
|
|
8
|
-
const regExp = /{"function_call":.*?}}/;
|
|
9
|
-
const match = content.match(regExp);
|
|
10
|
-
|
|
11
|
-
return { content: match ? match[0] : '', valid: match };
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
// export const createFunctionCallMessage = () => {
|
|
15
|
-
// return [
|
|
16
|
-
// {
|
|
17
|
-
// content: '',
|
|
18
|
-
// function_call: { arguments: '{\n "city": "杭州"\n}', name: 'realtimeWeather' },
|
|
19
|
-
// role: 'assistant',
|
|
20
|
-
// },
|
|
21
|
-
// {
|
|
22
|
-
// content:
|
|
23
|
-
// '{"status":"1","count":"1","info":"OK","infocode":"10000","forecasts":[{"city":"杭州市","adcode":"300","province":"浙江","reporttime":"2023-07-28 20:32:48","casts":[{"date":"2023-07-28","week":"5","dayweather"小雨","nightweather":"小雨-中雨","daytemp":"32","nighttemp":"26","daywind":"东","nightwind":"东","daypower":"6power":"6","daytemp_float":"32.0","nighttemp_float":"26.0"},{"date":"2023-07-29","week":"6","dayweather":"小雨雨","nightweather":"小雨","daytemp":"30","nighttemp":"25","daywind":"东南","nightwind":"东南","daypower":"4","wer":"4","daytemp_float":"30.0","nighttemp_float":"25.0"},{"date":"2023-07-30","week":"7","dayweather":"小雨",ightweather":"雷阵雨","daytemp":"31","nighttemp":"25","daywind":"东南","nightwind":"东南","daypower":"4","nigh:"4","daytemp_float":"31.0","nighttemp_float":"25.0"},{"date":"2023-07-31","week":"1","dayweather":"雷阵雨","ntweather":"雷阵雨","daytemp":"33","nighttemp":"25","daywind":"东","nightwind":"东","daypower":"4","nightpower""daytemp_float":"33.0","nighttemp_float":"25.0"}]}]}',
|
|
24
|
-
// name: 'realtimeWeather',
|
|
25
|
-
// role: 'function',
|
|
26
|
-
// },
|
|
27
|
-
// ];
|
|
28
|
-
// };
|