@lobehub/chat 0.125.0 → 0.126.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.
- package/CHANGELOG.md +58 -0
- package/README.md +8 -8
- package/README.zh-CN.md +8 -8
- package/docs/Deployment/Environment-Variable.md +34 -1
- package/docs/Deployment/Environment-Variable.zh-CN.md +35 -1
- package/next.config.mjs +3 -0
- package/package.json +1 -1
- package/src/app/chat/features/ChatHeader/ShareButton/style.ts +3 -1
- package/src/app/chat/features/TopicListContent/Topic/index.tsx +2 -1
- package/src/app/chat/settings/(desktop)/features/Header.tsx +1 -1
- package/src/app/market/features/ShareAgentButton/Inner.tsx +2 -2
- package/src/app/metadata.ts +6 -1
- package/src/app/settings/common/Common.tsx +4 -3
- package/src/components/Analytics/Umami.tsx +15 -0
- package/src/components/Analytics/index.tsx +4 -1
- package/src/config/client.ts +11 -0
- package/src/const/url.ts +4 -0
- package/src/features/AgentSetting/AgentConfig/index.tsx +3 -2
- package/src/hooks/useSTT.ts +2 -2
- package/src/hooks/useTTS.ts +3 -3
- package/src/services/_url.ts +29 -11
- package/src/services/chat.ts +3 -3
- package/src/services/file.ts +3 -2
- package/src/services/global.ts +3 -2
- package/src/services/imageGeneration.ts +3 -2
- package/src/services/market.ts +4 -3
- package/src/services/plugin.ts +4 -3
- package/src/store/chat/slices/tool/action.ts +0 -3
- package/src/utils/basePath.ts +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.126.1](https://github.com/lobehub/lobe-chat/compare/v0.126.0...v0.126.1)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-02-09**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: Add basePath to support subdirectory.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **misc**: Add basePath to support subdirectory, closes [#1179](https://github.com/lobehub/lobe-chat/issues/1179) ([43e544a](https://github.com/lobehub/lobe-chat/commit/43e544a))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
## [Version 0.126.0](https://github.com/lobehub/lobe-chat/compare/v0.125.0...v0.126.0)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2024-02-09**</sup>
|
|
33
|
+
|
|
34
|
+
#### ✨ Features
|
|
35
|
+
|
|
36
|
+
- **misc**: Support umami analytics.
|
|
37
|
+
|
|
38
|
+
#### 🐛 Bug Fixes
|
|
39
|
+
|
|
40
|
+
- **misc**: The back button on the chat setting page can correctly return to the configured Agent chat page.
|
|
41
|
+
|
|
42
|
+
<br/>
|
|
43
|
+
|
|
44
|
+
<details>
|
|
45
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
46
|
+
|
|
47
|
+
#### What's improved
|
|
48
|
+
|
|
49
|
+
- **misc**: Support umami analytics, closes [#1267](https://github.com/lobehub/lobe-chat/issues/1267) ([da7beba](https://github.com/lobehub/lobe-chat/commit/da7beba))
|
|
50
|
+
|
|
51
|
+
#### What's fixed
|
|
52
|
+
|
|
53
|
+
- **misc**: The back button on the chat setting page can correctly return to the configured Agent chat page, closes [#1272](https://github.com/lobehub/lobe-chat/issues/1272) ([4cc1ad5](https://github.com/lobehub/lobe-chat/commit/4cc1ad5))
|
|
54
|
+
|
|
55
|
+
</details>
|
|
56
|
+
|
|
57
|
+
<div align="right">
|
|
58
|
+
|
|
59
|
+
[](#readme-top)
|
|
60
|
+
|
|
61
|
+
</div>
|
|
62
|
+
|
|
5
63
|
## [Version 0.125.0](https://github.com/lobehub/lobe-chat/compare/v0.124.3...v0.125.0)
|
|
6
64
|
|
|
7
65
|
<sup>Released on **2024-02-08**</sup>
|
package/README.md
CHANGED
|
@@ -225,14 +225,14 @@ Our marketplace is not just a showcase platform but also a collaborative space.
|
|
|
225
225
|
|
|
226
226
|
<!-- AGENT LIST -->
|
|
227
227
|
|
|
228
|
-
| Recent Submits
|
|
229
|
-
|
|
|
230
|
-
| [
|
|
231
|
-
| [
|
|
232
|
-
| [
|
|
233
|
-
| [
|
|
234
|
-
|
|
235
|
-
> 📊 Total agents: [<kbd>**
|
|
228
|
+
| Recent Submits | Description |
|
|
229
|
+
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
230
|
+
| [Cloze Exercise Generator](https://chat-preview.lobehub.com/market?agent=cloze-exercise-generator)<br/><sup>By **[bentwnghk](https://github.com/bentwnghk)** on **2024-02-08**</sup> | Specializes in generating summary cloze exercises. Please provide the theme of the paragraph.<br/>`summary` `exercise` `generator` `writing` `education` |
|
|
231
|
+
| [Reading Comprehension Wizard](https://chat-preview.lobehub.com/market?agent=reading-comprehension-exercise-generator)<br/><sup>By **[bentwnghk](https://github.com/bentwnghk)** on **2024-02-08**</sup> | Specializes in generating reading comprehension exercises<br/>`reading-comprehension` `exercise-generation` `education` |
|
|
232
|
+
| [Thematic Vocabulary Worksheet Creator](https://chat-preview.lobehub.com/market?agent=thematic-vocabulary-worksheet-generator)<br/><sup>By **[bentwnghk](https://github.com/bentwnghk)** on **2024-02-08**</sup> | Skilled in creating English thematic vocabulary worksheets<br/>`writing` `language-learning` `teaching` `assessment` `educational-resources` |
|
|
233
|
+
| [Vocabulary Worksheet Wizard](https://chat-preview.lobehub.com/market?agent=vocabulary-worksheet-wizard)<br/><sup>By **[bentwnghk](https://github.com/bentwnghk)** on **2024-02-08**</sup> | Specializes in generating English vocabulary worksheets<br/>`vocabulary` `worksheet` `education` `language-learning` |
|
|
234
|
+
|
|
235
|
+
> 📊 Total agents: [<kbd>**164**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
236
236
|
|
|
237
237
|
<!-- AGENT LIST -->
|
|
238
238
|
|
package/README.zh-CN.md
CHANGED
|
@@ -205,14 +205,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
|
|
|
205
205
|
|
|
206
206
|
<!-- AGENT LIST -->
|
|
207
207
|
|
|
208
|
-
| 最近新增
|
|
209
|
-
|
|
|
210
|
-
| [
|
|
211
|
-
| [
|
|
212
|
-
| [
|
|
213
|
-
| [
|
|
214
|
-
|
|
215
|
-
> 📊 Total agents: [<kbd>**
|
|
208
|
+
| 最近新增 | 助手说明 |
|
|
209
|
+
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
210
|
+
| [填空练习生成器](https://chat-preview.lobehub.com/market?agent=cloze-exercise-generator)<br/><sup>By **[bentwnghk](https://github.com/bentwnghk)** on **2024-02-08**</sup> | 专门用于生成摘要填空练习。请提供段落的主题。<br/>`摘要` `练习` `生成器` `写作` `教育` |
|
|
211
|
+
| [阅读理解向导](https://chat-preview.lobehub.com/market?agent=reading-comprehension-exercise-generator)<br/><sup>By **[bentwnghk](https://github.com/bentwnghk)** on **2024-02-08**</sup> | 专门生成阅读理解练习<br/>`阅读理解` `练习生成` `教育` |
|
|
212
|
+
| [主题词汇工作表创建器](https://chat-preview.lobehub.com/market?agent=thematic-vocabulary-worksheet-generator)<br/><sup>By **[bentwnghk](https://github.com/bentwnghk)** on **2024-02-08**</sup> | 擅长创建英语主题词汇工作表<br/>`写作` `语言学习` `教学` `评估` `教育资源` |
|
|
213
|
+
| [词汇工作表向导](https://chat-preview.lobehub.com/market?agent=vocabulary-worksheet-wizard)<br/><sup>By **[bentwnghk](https://github.com/bentwnghk)** on **2024-02-08**</sup> | 专注于生成英语词汇工作表<br/>`词汇` `工作表` `教育` `语言学习` |
|
|
214
|
+
|
|
215
|
+
> 📊 Total agents: [<kbd>**164**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
216
216
|
|
|
217
217
|
<!-- AGENT LIST -->
|
|
218
218
|
|
|
@@ -7,6 +7,7 @@ LobeChat provides additional configuration options during deployment, which can
|
|
|
7
7
|
- [General Variables](#general-variables)
|
|
8
8
|
- [`ACCESS_CODE`](#access_code)
|
|
9
9
|
- [`ENABLE_OAUTH_SSO`](#enable_oauth_sso)
|
|
10
|
+
- [`NEXT_PUBLIC_BASE_PATH`](#next_public_base_path)
|
|
10
11
|
- [Authentication Service Providers](#authentication-service-providers)
|
|
11
12
|
- [Common Settings](#common-settings)
|
|
12
13
|
- [Auth0](#auth0)
|
|
@@ -25,6 +26,7 @@ LobeChat provides additional configuration options during deployment, which can
|
|
|
25
26
|
- [Data Analytics](#data-analytics)
|
|
26
27
|
- [Vercel Analytics](#vercel-analytics)
|
|
27
28
|
- [Posthog Analytics](#posthog-analytics)
|
|
29
|
+
- [Umami Analytics](#umami-analytics)
|
|
28
30
|
|
|
29
31
|
## General Variables
|
|
30
32
|
|
|
@@ -40,7 +42,14 @@ LobeChat provides additional configuration options during deployment, which can
|
|
|
40
42
|
- Type: Optional
|
|
41
43
|
- Description: Enable OAuth single sign-on (SSO) for LobeChat. Set to `1` to enable OAuth SSO. See [Authentication Service Providers](#authentication-service-providers) for more details.
|
|
42
44
|
- Default: `-`
|
|
43
|
-
- Example: `1`
|
|
45
|
+
- Example: `1`
|
|
46
|
+
|
|
47
|
+
### `NEXT_PUBLIC_BASE_PATH`
|
|
48
|
+
|
|
49
|
+
- Type:Optional
|
|
50
|
+
- Description:add `basePath` for LobeChat
|
|
51
|
+
- Default: `-`
|
|
52
|
+
- Example: `/test`
|
|
44
53
|
|
|
45
54
|
## Authentication Service Providers
|
|
46
55
|
|
|
@@ -286,8 +295,32 @@ The above example adds `search-engine` plugin settings, and sets the `SERPAPI_AP
|
|
|
286
295
|
- Default: -
|
|
287
296
|
- Example: `1`
|
|
288
297
|
|
|
298
|
+
### Umami Analytics
|
|
299
|
+
|
|
300
|
+
#### `NEXT_PUBLIC_ANALYTICS_UMAMI`
|
|
301
|
+
|
|
302
|
+
- Type: Optional
|
|
303
|
+
- Description: Environment variable to enable [Umami Analytics][umami-analytics-url]. Set to `1` to enable Umami Analytics.
|
|
304
|
+
- Default: `-`
|
|
305
|
+
- Example: `1`
|
|
306
|
+
|
|
307
|
+
#### `NEXT_PUBLIC_UMAMI_SCRIPT_URL`
|
|
308
|
+
|
|
309
|
+
- Type: Optional
|
|
310
|
+
- Description: Set the url of the umami script. Default is the script address of Umami Cloud.
|
|
311
|
+
- Default: `https://analytics.umami.is/script.js`
|
|
312
|
+
- Example: `https://umami.your-site.com/script.js`
|
|
313
|
+
|
|
314
|
+
#### `NEXT_PUBLIC_UMAMI_WEBSITE_ID`
|
|
315
|
+
|
|
316
|
+
- Type: Required
|
|
317
|
+
- Description: The website ID in umami
|
|
318
|
+
- Default: `-`
|
|
319
|
+
- Example: `E738D82A-EE9E-4806-A81F-0CA3CAE57F65`
|
|
320
|
+
|
|
289
321
|
[auth0-client-page]: https://manage.auth0.com/dashboard
|
|
290
322
|
[azure-api-verion-url]: https://docs.microsoft.com/zh-cn/azure/developer/javascript/api-reference/es-modules/azure-sdk/ai-translation/translationconfiguration?view=azure-node-latest#api-version
|
|
291
323
|
[openai-api-page]: https://platform.openai.com/account/api-keys
|
|
292
324
|
[posthog-analytics-url]: https://posthog.com
|
|
325
|
+
[umami-analytics-url]: https://umami.is
|
|
293
326
|
[vercel-analytics-url]: https://vercel.com/analytics
|
|
@@ -7,6 +7,7 @@ LobeChat 在部署时提供了一些额外的配置项,使用环境变量进
|
|
|
7
7
|
- [通用变量](#通用变量)
|
|
8
8
|
- [`ACCESS_CODE`](#access_code)
|
|
9
9
|
- [`ENABLE_OAUTH_SSO`](#enable_oauth_sso)
|
|
10
|
+
- [`NEXT_PUBLIC_BASE_PATH`](#next_public_base_path)
|
|
10
11
|
- [身份验证服务](#身份验证服务)
|
|
11
12
|
- [通用设置](#通用设置)
|
|
12
13
|
- [Auth0](#auth0)
|
|
@@ -25,6 +26,7 @@ LobeChat 在部署时提供了一些额外的配置项,使用环境变量进
|
|
|
25
26
|
- [数据统计](#数据统计)
|
|
26
27
|
- [Vercel Analytics](#vercel-analytics)
|
|
27
28
|
- [Posthog Analytics](#posthog-analytics)
|
|
29
|
+
- [Umami Analytics](#umami-analytics)
|
|
28
30
|
|
|
29
31
|
## 通用变量
|
|
30
32
|
|
|
@@ -40,7 +42,14 @@ LobeChat 在部署时提供了一些额外的配置项,使用环境变量进
|
|
|
40
42
|
- 类型:可选
|
|
41
43
|
- 描述:为 LobeChat 启用单点登录 (SSO)。设置为 `1` 以启用单点登录。有关详细信息,请参阅[身份验证服务](#身份验证服务)。
|
|
42
44
|
- 默认值: `-`
|
|
43
|
-
- 示例: `1`
|
|
45
|
+
- 示例: `1`
|
|
46
|
+
|
|
47
|
+
### `NEXT_PUBLIC_BASE_PATH`
|
|
48
|
+
|
|
49
|
+
- 类型:可选
|
|
50
|
+
- 描述:为 LobeChat 添加 `basePath`
|
|
51
|
+
- 默认值: `-`
|
|
52
|
+
- 示例: `/test`
|
|
44
53
|
|
|
45
54
|
## 身份验证服务
|
|
46
55
|
|
|
@@ -282,7 +291,32 @@ LobeChat 在部署时提供了一些额外的配置项,使用环境变量进
|
|
|
282
291
|
- 默认值: `-`
|
|
283
292
|
- 示例:`1`
|
|
284
293
|
|
|
294
|
+
### Umami Analytics
|
|
295
|
+
|
|
296
|
+
#### `NEXT_PUBLIC_ANALYTICS_UMAMI`
|
|
297
|
+
|
|
298
|
+
- 类型:可选
|
|
299
|
+
- 描述:用于开启 [Umami Analytics][umami-analytics-url] 的环境变量,设为 `1`
|
|
300
|
+
时开启 Umami Analytics
|
|
301
|
+
- 默认值: `-`
|
|
302
|
+
- 示例:`1`
|
|
303
|
+
|
|
304
|
+
#### `NEXT_PUBLIC_UMAMI_SCRIPT_URL`
|
|
305
|
+
|
|
306
|
+
- 类型:可选
|
|
307
|
+
- 描述:Umami 脚本的网址,默认为 Umami Cloud 提供的脚本网址
|
|
308
|
+
- 默认值:`https://analytics.umami.is/script.js`
|
|
309
|
+
- 示例:`https://umami.your-site.com/script.js`
|
|
310
|
+
|
|
311
|
+
#### `NEXT_PUBLIC_UMAMI_WEBSITE_ID`
|
|
312
|
+
|
|
313
|
+
- 类型:必选
|
|
314
|
+
- 描述:你的 Umami 的 Website ID
|
|
315
|
+
- 默认值:`-`
|
|
316
|
+
- 示例:`E738D82A-EE9E-4806-A81F-0CA3CAE57F65`
|
|
317
|
+
|
|
285
318
|
[auth0-client-page]: https://manage.auth0.com/dashboard
|
|
286
319
|
[azure-api-verion-url]: https://docs.microsoft.com/zh-cn/azure/developer/javascript/api-reference/es-modules/azure-sdk/ai-translation/translationconfiguration?view=azure-node-latest#api-version
|
|
287
320
|
[openai-api-page]: https://platform.openai.com/account/api-keys
|
|
288
321
|
[posthog-analytics-url]: https://posthog.com
|
|
322
|
+
[umami-analytics-url]: https://umami.is
|
package/next.config.mjs
CHANGED
|
@@ -7,6 +7,8 @@ const buildWithDocker = process.env.DOCKER === 'true';
|
|
|
7
7
|
// if you need to proxy the api endpoint to remote server
|
|
8
8
|
const API_PROXY_ENDPOINT = process.env.API_PROXY_ENDPOINT || '';
|
|
9
9
|
|
|
10
|
+
const basePath = process.env.NEXT_PUBLIC_BASE_PATH;
|
|
11
|
+
|
|
10
12
|
const withBundleAnalyzer = analyzer({
|
|
11
13
|
enabled: process.env.ANALYZE === 'true',
|
|
12
14
|
});
|
|
@@ -22,6 +24,7 @@ const withPWA = nextPWA({
|
|
|
22
24
|
/** @type {import('next').NextConfig} */
|
|
23
25
|
const nextConfig = {
|
|
24
26
|
compress: isProd,
|
|
27
|
+
basePath,
|
|
25
28
|
experimental: {
|
|
26
29
|
optimizePackageImports: [
|
|
27
30
|
'emoji-mart',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.126.1",
|
|
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",
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { createStyles } from 'antd-style';
|
|
2
2
|
|
|
3
|
+
import { imageUrl } from '@/const/url';
|
|
4
|
+
|
|
3
5
|
export const useStyles = createStyles(({ css, token, stylish, cx }, withBackground: boolean) => ({
|
|
4
6
|
background: css`
|
|
5
7
|
padding: 24px;
|
|
6
8
|
|
|
7
9
|
background-color: ${token.colorBgLayout};
|
|
8
|
-
background-image: url('
|
|
10
|
+
background-image: url(${imageUrl('screenshot_background.webp')});
|
|
9
11
|
background-position: center;
|
|
10
12
|
background-size: 120% 120%;
|
|
11
13
|
`,
|
|
@@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
6
6
|
import { Flexbox } from 'react-layout-kit';
|
|
7
7
|
import { Virtuoso, VirtuosoHandle } from 'react-virtuoso';
|
|
8
8
|
|
|
9
|
+
import { imageUrl } from '@/const/url';
|
|
9
10
|
import { useChatStore } from '@/store/chat';
|
|
10
11
|
import { topicSelectors } from '@/store/chat/selectors';
|
|
11
12
|
import { useGlobalStore } from '@/store/global';
|
|
@@ -60,7 +61,7 @@ export const Topic = memo(() => {
|
|
|
60
61
|
<Flexbox flex={1}>
|
|
61
62
|
<EmptyCard
|
|
62
63
|
alt={t('topic.guide.desc')}
|
|
63
|
-
cover={
|
|
64
|
+
cover={imageUrl(`empty_topic_${isDarkMode ? 'dark' : 'light'}.webp`)}
|
|
64
65
|
desc={t('topic.guide.desc')}
|
|
65
66
|
height={120}
|
|
66
67
|
onVisibleChange={(visible) => {
|
|
@@ -13,7 +13,7 @@ const Header = memo(() => {
|
|
|
13
13
|
return (
|
|
14
14
|
<ChatHeader
|
|
15
15
|
left={<ChatHeaderTitle title={t('header.session')} />}
|
|
16
|
-
onBackClick={() => router.push(pathString('/chat', {
|
|
16
|
+
onBackClick={() => router.push(pathString('/chat', { search: location.search }))}
|
|
17
17
|
right={<HeaderContent />}
|
|
18
18
|
showBackButton
|
|
19
19
|
/>
|
|
@@ -5,7 +5,7 @@ import Image from 'next/image';
|
|
|
5
5
|
import { memo } from 'react';
|
|
6
6
|
import { useTranslation } from 'react-i18next';
|
|
7
7
|
|
|
8
|
-
import { AGENTS_INDEX_GITHUB } from '@/const/url';
|
|
8
|
+
import { AGENTS_INDEX_GITHUB, imageUrl } from '@/const/url';
|
|
9
9
|
|
|
10
10
|
const Inner = memo(() => {
|
|
11
11
|
const { t } = useTranslation('market');
|
|
@@ -14,7 +14,7 @@ const Inner = memo(() => {
|
|
|
14
14
|
<Image
|
|
15
15
|
alt={'banner'}
|
|
16
16
|
height={602}
|
|
17
|
-
src={'
|
|
17
|
+
src={imageUrl('banner_market_modal.webp')}
|
|
18
18
|
style={{ height: 'auto', marginBottom: 24, width: '100%' }}
|
|
19
19
|
width={1602}
|
|
20
20
|
/>
|
package/src/app/metadata.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Metadata } from 'next';
|
|
2
2
|
|
|
3
|
+
import { getClientConfig } from '@/config/client';
|
|
3
4
|
import { getServerConfig } from '@/config/server';
|
|
4
5
|
|
|
5
6
|
import pkg from '../../package.json';
|
|
@@ -8,6 +9,10 @@ const title = 'LobeChat';
|
|
|
8
9
|
const { description, homepage } = pkg;
|
|
9
10
|
|
|
10
11
|
const { METADATA_BASE_URL = 'https://chat-preview.lobehub.com/' } = getServerConfig();
|
|
12
|
+
const { BASE_PATH } = getClientConfig();
|
|
13
|
+
|
|
14
|
+
// if there is a base path, then we don't need the manifest
|
|
15
|
+
const noManifest = !!BASE_PATH;
|
|
11
16
|
|
|
12
17
|
const metadata: Metadata = {
|
|
13
18
|
appleWebApp: {
|
|
@@ -22,7 +27,7 @@ const metadata: Metadata = {
|
|
|
22
27
|
shortcut:
|
|
23
28
|
'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/favicon.ico',
|
|
24
29
|
},
|
|
25
|
-
manifest: '/manifest.json',
|
|
30
|
+
manifest: noManifest ? undefined : '/manifest.json',
|
|
26
31
|
metadataBase: new URL(METADATA_BASE_URL),
|
|
27
32
|
openGraph: {
|
|
28
33
|
description: description,
|
|
@@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
8
8
|
|
|
9
9
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
10
10
|
import { DEFAULT_SETTINGS } from '@/const/settings';
|
|
11
|
+
import { imageUrl } from '@/const/url';
|
|
11
12
|
import AvatarWithUpload from '@/features/AvatarWithUpload';
|
|
12
13
|
import { localeOptions } from '@/locales/resources';
|
|
13
14
|
import { useChatStore } from '@/store/chat';
|
|
@@ -118,19 +119,19 @@ const Common = memo<SettingsCommonProps>(({ showAccessCodeConfig, showOAuthLogin
|
|
|
118
119
|
options={[
|
|
119
120
|
{
|
|
120
121
|
icon: Sun,
|
|
121
|
-
img: '
|
|
122
|
+
img: imageUrl('theme_light.webp'),
|
|
122
123
|
label: t('settingTheme.themeMode.light'),
|
|
123
124
|
value: 'light',
|
|
124
125
|
},
|
|
125
126
|
{
|
|
126
127
|
icon: Moon,
|
|
127
|
-
img: '
|
|
128
|
+
img: imageUrl('theme_dark.webp'),
|
|
128
129
|
label: t('settingTheme.themeMode.dark'),
|
|
129
130
|
value: 'dark',
|
|
130
131
|
},
|
|
131
132
|
{
|
|
132
133
|
icon: Monitor,
|
|
133
|
-
img: '
|
|
134
|
+
img: imageUrl('theme_auto.webp'),
|
|
134
135
|
label: t('settingTheme.themeMode.auto'),
|
|
135
136
|
value: 'auto',
|
|
136
137
|
},
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import Script from 'next/script';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
|
|
6
|
+
import { getClientConfig } from '@/config/client';
|
|
7
|
+
|
|
8
|
+
const { UMAMI_SCRIPT_URL, UMAMI_WEBSITE_ID } = getClientConfig();
|
|
9
|
+
|
|
10
|
+
const UmamiAnalytics = memo(
|
|
11
|
+
() =>
|
|
12
|
+
UMAMI_WEBSITE_ID && <Script data-website-id={UMAMI_WEBSITE_ID} defer src={UMAMI_SCRIPT_URL} />,
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export default UmamiAnalytics;
|
|
@@ -5,8 +5,10 @@ import { getClientConfig } from '@/config/client';
|
|
|
5
5
|
const Vercel = dynamic(() => import('./Vercel'), { ssr: false });
|
|
6
6
|
const Plausible = dynamic(() => import('./Plausible'), { ssr: false });
|
|
7
7
|
const Posthog = dynamic(() => import('./Posthog'), { ssr: false });
|
|
8
|
+
const Umami = dynamic(() => import('./Umami'), { ssr: false });
|
|
8
9
|
|
|
9
|
-
const { ANALYTICS_VERCEL, ANALYTICS_POSTHOG, ANALYTICS_PLAUSIBLE } =
|
|
10
|
+
const { ANALYTICS_VERCEL, ANALYTICS_POSTHOG, ANALYTICS_PLAUSIBLE, ANALYTICS_UMAMI } =
|
|
11
|
+
getClientConfig();
|
|
10
12
|
|
|
11
13
|
const Analytics = () => {
|
|
12
14
|
return (
|
|
@@ -14,6 +16,7 @@ const Analytics = () => {
|
|
|
14
16
|
{ANALYTICS_VERCEL && <Vercel />}
|
|
15
17
|
{ANALYTICS_PLAUSIBLE && <Plausible />}
|
|
16
18
|
{ANALYTICS_POSTHOG && <Posthog />}
|
|
19
|
+
{ANALYTICS_UMAMI && <Umami />}
|
|
17
20
|
</>
|
|
18
21
|
);
|
|
19
22
|
};
|
package/src/config/client.ts
CHANGED
|
@@ -24,6 +24,10 @@ declare global {
|
|
|
24
24
|
NEXT_PUBLIC_POSTHOG_HOST: string;
|
|
25
25
|
NEXT_PUBLIC_POSTHOG_DEBUG: string;
|
|
26
26
|
|
|
27
|
+
NEXT_PUBLIC_ANALYTICS_UMAMI?: string;
|
|
28
|
+
NEXT_PUBLIC_UMAMI_SCRIPT_URL?: string;
|
|
29
|
+
NEXT_PUBLIC_UMAMI_WEBSITE_ID?: string;
|
|
30
|
+
|
|
27
31
|
NEXT_PUBLIC_I18N_DEBUG: string;
|
|
28
32
|
NEXT_PUBLIC_I18N_DEBUG_BROWSER: string;
|
|
29
33
|
NEXT_PUBLIC_I18N_DEBUG_SERVER: string;
|
|
@@ -34,6 +38,7 @@ declare global {
|
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
export const getClientConfig = () => ({
|
|
41
|
+
BASE_PATH: process.env.NEXT_PUBLIC_BASE_PATH || '',
|
|
37
42
|
// Vercel Analytics
|
|
38
43
|
ANALYTICS_VERCEL: process.env.NEXT_PUBLIC_ANALYTICS_VERCEL === '1',
|
|
39
44
|
VERCEL_DEBUG: process.env.NEXT_PUBLIC_VERCEL_DEBUG === '1',
|
|
@@ -50,6 +55,12 @@ export const getClientConfig = () => ({
|
|
|
50
55
|
POSTHOG_HOST: process.env.NEXT_PUBLIC_POSTHOG_HOST,
|
|
51
56
|
POSTHOG_DEBUG: process.env.NEXT_PUBLIC_POSTHOG_DEBUG === '1',
|
|
52
57
|
|
|
58
|
+
// Umami Analytics
|
|
59
|
+
ANALYTICS_UMAMI: process.env.NEXT_PUBLIC_ANALYTICS_UMAMI === '1',
|
|
60
|
+
UMAMI_SCRIPT_URL:
|
|
61
|
+
process.env.NEXT_PUBLIC_UMAMI_SCRIPT_URL || 'https://analytics.umami.is/script.js',
|
|
62
|
+
UMAMI_WEBSITE_ID: process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID,
|
|
63
|
+
|
|
53
64
|
// i18n debug mode
|
|
54
65
|
I18N_DEBUG: process.env.NEXT_PUBLIC_I18N_DEBUG === '1',
|
|
55
66
|
I18N_DEBUG_BROWSER: process.env.NEXT_PUBLIC_I18N_DEBUG_BROWSER === '1',
|
package/src/const/url.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import urlJoin from 'url-join';
|
|
2
2
|
|
|
3
|
+
import { withBasePath } from '@/utils/basePath';
|
|
4
|
+
|
|
3
5
|
import pkg from '../../package.json';
|
|
4
6
|
import { INBOX_SESSION_ID } from './session';
|
|
5
7
|
|
|
@@ -19,3 +21,5 @@ export const AGENTS_INDEX_GITHUB_ISSUE = urlJoin(AGENTS_INDEX_GITHUB, 'issues/ne
|
|
|
19
21
|
export const SESSION_CHAT_URL = (id: string = INBOX_SESSION_ID, mobile?: boolean) =>
|
|
20
22
|
mobile ? `/chat/mobile?session=${id}` : `/chat?session=${id}`;
|
|
21
23
|
export const MANUAL_UPGRADE_URL = 'https://github.com/lobehub/lobe-chat/wiki/Upstream-Sync';
|
|
24
|
+
|
|
25
|
+
export const imageUrl = (filename: string) => withBasePath(`/images/${filename}`);
|
|
@@ -7,6 +7,7 @@ import { memo, useMemo } from 'react';
|
|
|
7
7
|
import { useTranslation } from 'react-i18next';
|
|
8
8
|
|
|
9
9
|
import { FORM_STYLE } from '@/const/layoutTokens';
|
|
10
|
+
import { imageUrl } from '@/const/url';
|
|
10
11
|
|
|
11
12
|
import { useStore } from '../store';
|
|
12
13
|
import ModelSelect from './ModelSelect';
|
|
@@ -46,13 +47,13 @@ const AgentConfig = memo(() => {
|
|
|
46
47
|
options={[
|
|
47
48
|
{
|
|
48
49
|
icon: MessagesSquare,
|
|
49
|
-
img:
|
|
50
|
+
img: imageUrl(`chatmode_chat_${isDarkMode ? 'dark' : 'light'}.webp`),
|
|
50
51
|
label: t('settingChat.chatStyleType.type.chat'),
|
|
51
52
|
value: 'chat',
|
|
52
53
|
},
|
|
53
54
|
{
|
|
54
55
|
icon: LayoutList,
|
|
55
|
-
img:
|
|
56
|
+
img: imageUrl(`chatmode_docs_${isDarkMode ? 'dark' : 'light'}.webp`),
|
|
56
57
|
label: t('settingChat.chatStyleType.type.docs'),
|
|
57
58
|
value: 'docs',
|
|
58
59
|
},
|
package/src/hooks/useSTT.ts
CHANGED
|
@@ -9,7 +9,7 @@ import isEqual from 'fast-deep-equal';
|
|
|
9
9
|
import { SWRConfiguration } from 'swr';
|
|
10
10
|
|
|
11
11
|
import { createHeaderWithOpenAI } from '@/services/_header';
|
|
12
|
-
import {
|
|
12
|
+
import { API_ENDPOINTS } from '@/services/_url';
|
|
13
13
|
import { useGlobalStore } from '@/store/global';
|
|
14
14
|
import { settingsSelectors } from '@/store/global/selectors';
|
|
15
15
|
import { useSessionStore } from '@/store/session';
|
|
@@ -39,7 +39,7 @@ export const useSTT = (config: STTConfig) => {
|
|
|
39
39
|
options = {
|
|
40
40
|
api: {
|
|
41
41
|
headers: createHeaderWithOpenAI(),
|
|
42
|
-
serviceUrl:
|
|
42
|
+
serviceUrl: API_ENDPOINTS.stt,
|
|
43
43
|
},
|
|
44
44
|
autoStop,
|
|
45
45
|
options: {
|
package/src/hooks/useTTS.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import isEqual from 'fast-deep-equal';
|
|
11
11
|
|
|
12
12
|
import { createHeaderWithOpenAI } from '@/services/_header';
|
|
13
|
-
import {
|
|
13
|
+
import { API_ENDPOINTS } from '@/services/_url';
|
|
14
14
|
import { useGlobalStore } from '@/store/global';
|
|
15
15
|
import { settingsSelectors } from '@/store/global/selectors';
|
|
16
16
|
import { useSessionStore } from '@/store/session';
|
|
@@ -36,7 +36,7 @@ export const useTTS = (content: string, config?: TTSConfig) => {
|
|
|
36
36
|
options = {
|
|
37
37
|
api: {
|
|
38
38
|
headers: createHeaderWithOpenAI(),
|
|
39
|
-
serviceUrl:
|
|
39
|
+
serviceUrl: API_ENDPOINTS.tts,
|
|
40
40
|
},
|
|
41
41
|
options: {
|
|
42
42
|
model: ttsSettings.openAI.ttsModel,
|
|
@@ -64,7 +64,7 @@ export const useTTS = (content: string, config?: TTSConfig) => {
|
|
|
64
64
|
useSelectedTTS = useMicrosoftSpeech;
|
|
65
65
|
options = {
|
|
66
66
|
api: {
|
|
67
|
-
serviceUrl:
|
|
67
|
+
serviceUrl: API_ENDPOINTS.microsoft,
|
|
68
68
|
},
|
|
69
69
|
options: {
|
|
70
70
|
voice: config?.voice || voice,
|
package/src/services/_url.ts
CHANGED
|
@@ -1,21 +1,39 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable sort-keys-fix/sort-keys-fix */
|
|
2
|
+
import { transform } from 'lodash-es';
|
|
3
|
+
|
|
4
|
+
import { withBasePath } from '@/utils/basePath';
|
|
5
|
+
|
|
6
|
+
const mapWithBasePath = <T extends object>(apis: T): T => {
|
|
7
|
+
return transform(apis, (result, value, key) => {
|
|
8
|
+
if (typeof value === 'string') {
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
result[key] = withBasePath(value);
|
|
11
|
+
} else {
|
|
12
|
+
result[key] = value;
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const API_ENDPOINTS = mapWithBasePath({
|
|
2
18
|
config: '/api/config',
|
|
3
|
-
market: '/api/market',
|
|
4
19
|
proxy: '/api/proxy',
|
|
5
|
-
};
|
|
6
20
|
|
|
7
|
-
|
|
21
|
+
// agent markets
|
|
22
|
+
market: '/api/market',
|
|
23
|
+
|
|
24
|
+
// plugins
|
|
8
25
|
gateway: '/api/plugin/gateway',
|
|
9
|
-
|
|
10
|
-
};
|
|
26
|
+
pluginStore: '/api/plugin/store',
|
|
11
27
|
|
|
12
|
-
|
|
28
|
+
// chat
|
|
29
|
+
chat: (provider: string) => withBasePath(`/api/chat/${provider}`),
|
|
30
|
+
|
|
31
|
+
// image
|
|
13
32
|
images: '/api/openai/images',
|
|
33
|
+
|
|
34
|
+
// TTS & STT
|
|
14
35
|
stt: '/api/openai/stt',
|
|
15
36
|
tts: '/api/openai/tts',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const TTS_URL = {
|
|
19
37
|
edge: '/api/tts/edge-speech',
|
|
20
38
|
microsoft: '/api/tts/microsoft-speech',
|
|
21
|
-
};
|
|
39
|
+
});
|
package/src/services/chat.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { fetchAIFactory, getMessageError } from '@/utils/fetch';
|
|
|
16
16
|
|
|
17
17
|
import { createHeaderWithAuth } from './_auth';
|
|
18
18
|
import { createHeaderWithOpenAI } from './_header';
|
|
19
|
-
import {
|
|
19
|
+
import { API_ENDPOINTS } from './_url';
|
|
20
20
|
|
|
21
21
|
interface FetchOptions {
|
|
22
22
|
signal?: AbortSignal | undefined;
|
|
@@ -81,7 +81,7 @@ class ChatService {
|
|
|
81
81
|
provider,
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
return fetch(
|
|
84
|
+
return fetch(API_ENDPOINTS.chat(provider), {
|
|
85
85
|
body: JSON.stringify(payload),
|
|
86
86
|
headers,
|
|
87
87
|
method: 'POST',
|
|
@@ -102,7 +102,7 @@ class ChatService {
|
|
|
102
102
|
|
|
103
103
|
const gatewayURL = manifest?.gateway;
|
|
104
104
|
|
|
105
|
-
const res = await fetch(gatewayURL ??
|
|
105
|
+
const res = await fetch(gatewayURL ?? API_ENDPOINTS.gateway, {
|
|
106
106
|
body: JSON.stringify({ ...params, manifest }),
|
|
107
107
|
// TODO: we can have a better auth way
|
|
108
108
|
headers: createHeadersWithPluginSettings(settings, createHeaderWithOpenAI()),
|
package/src/services/file.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { FileModel } from '@/database/models/file';
|
|
2
2
|
import { DB_File } from '@/database/schemas/files';
|
|
3
|
-
import { URLS } from '@/services/_url';
|
|
4
3
|
import { FilePreview } from '@/types/files';
|
|
5
4
|
import compressImage from '@/utils/compressImage';
|
|
6
5
|
|
|
6
|
+
import { API_ENDPOINTS } from './_url';
|
|
7
|
+
|
|
7
8
|
class FileService {
|
|
8
9
|
private isImage(fileType: string) {
|
|
9
10
|
const imageRegex = /^image\//;
|
|
@@ -43,7 +44,7 @@ class FileService {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
async uploadImageByUrl(url: string, file: Pick<DB_File, 'name' | 'metadata'>) {
|
|
46
|
-
const res = await fetch(
|
|
47
|
+
const res = await fetch(API_ENDPOINTS.proxy, { body: url, method: 'POST' });
|
|
47
48
|
const data = await res.arrayBuffer();
|
|
48
49
|
const fileType = res.headers.get('content-type') || 'image/webp';
|
|
49
50
|
|
package/src/services/global.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { URLS } from '@/services/_url';
|
|
2
1
|
import { GlobalServerConfig } from '@/types/settings';
|
|
3
2
|
|
|
3
|
+
import { API_ENDPOINTS } from './_url';
|
|
4
|
+
|
|
4
5
|
const VERSION_URL = 'https://registry.npmmirror.com/@lobehub/chat';
|
|
5
6
|
|
|
6
7
|
class GlobalService {
|
|
@@ -15,7 +16,7 @@ class GlobalService {
|
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
getGlobalConfig = async (): Promise<GlobalServerConfig> => {
|
|
18
|
-
const res = await fetch(
|
|
19
|
+
const res = await fetch(API_ENDPOINTS.config);
|
|
19
20
|
|
|
20
21
|
return res.json();
|
|
21
22
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createHeaderWithOpenAI } from '@/services/_header';
|
|
2
|
-
import { OPENAI_URLS } from '@/services/_url';
|
|
3
2
|
import { OpenAIImagePayload } from '@/types/openai/image';
|
|
4
3
|
|
|
4
|
+
import { API_ENDPOINTS } from './_url';
|
|
5
|
+
|
|
5
6
|
interface FetchOptions {
|
|
6
7
|
signal?: AbortSignal | undefined;
|
|
7
8
|
}
|
|
@@ -10,7 +11,7 @@ class ImageGenerationService {
|
|
|
10
11
|
async generateImage(params: Omit<OpenAIImagePayload, 'model' | 'n'>, options?: FetchOptions) {
|
|
11
12
|
const payload: OpenAIImagePayload = { ...params, model: 'dall-e-3', n: 1 };
|
|
12
13
|
|
|
13
|
-
const res = await fetch(
|
|
14
|
+
const res = await fetch(API_ENDPOINTS.images, {
|
|
14
15
|
body: JSON.stringify(payload),
|
|
15
16
|
headers: createHeaderWithOpenAI({ 'Content-Type': 'application/json' }),
|
|
16
17
|
method: 'POST',
|
package/src/services/market.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { URLS } from '@/services/_url';
|
|
2
1
|
import { LobeChatAgentsMarketIndex } from '@/types/market';
|
|
3
2
|
|
|
3
|
+
import { API_ENDPOINTS } from './_url';
|
|
4
|
+
|
|
4
5
|
class MarketService {
|
|
5
6
|
getAgentList = async (locale: string): Promise<LobeChatAgentsMarketIndex> => {
|
|
6
|
-
const res = await fetch(`${
|
|
7
|
+
const res = await fetch(`${API_ENDPOINTS.market}?locale=${locale}`);
|
|
7
8
|
|
|
8
9
|
return res.json();
|
|
9
10
|
};
|
|
@@ -13,7 +14,7 @@ class MarketService {
|
|
|
13
14
|
*/
|
|
14
15
|
getAgentManifest = async (identifier: string, locale: string) => {
|
|
15
16
|
if (!identifier) return;
|
|
16
|
-
const res = await fetch(`${
|
|
17
|
+
const res = await fetch(`${API_ENDPOINTS.market}/${identifier}?locale=${locale}`);
|
|
17
18
|
|
|
18
19
|
return res.json();
|
|
19
20
|
};
|
package/src/services/plugin.ts
CHANGED
|
@@ -5,12 +5,13 @@ import {
|
|
|
5
5
|
} from '@lobehub/chat-plugin-sdk';
|
|
6
6
|
|
|
7
7
|
import { PluginModel } from '@/database/models/plugin';
|
|
8
|
-
import { PLUGINS_URLS, URLS } from '@/services/_url';
|
|
9
8
|
import { globalHelpers } from '@/store/global/helpers';
|
|
10
9
|
import { OpenAIPluginManifest } from '@/types/openai/plugin';
|
|
11
10
|
import { LobeTool } from '@/types/tool';
|
|
12
11
|
import { LobeToolCustomPlugin } from '@/types/tool/plugin';
|
|
13
12
|
|
|
13
|
+
import { API_ENDPOINTS } from './_url';
|
|
14
|
+
|
|
14
15
|
export interface InstallPluginParams {
|
|
15
16
|
identifier: string;
|
|
16
17
|
manifest: LobeChatPluginManifest;
|
|
@@ -21,7 +22,7 @@ class PluginService {
|
|
|
21
22
|
// 2. 发送请求
|
|
22
23
|
let res: Response;
|
|
23
24
|
try {
|
|
24
|
-
res = await (proxy ? fetch(
|
|
25
|
+
res = await (proxy ? fetch(API_ENDPOINTS.proxy, { body: url, method: 'POST' }) : fetch(url));
|
|
25
26
|
} catch {
|
|
26
27
|
throw new TypeError('fetchError');
|
|
27
28
|
}
|
|
@@ -54,7 +55,7 @@ class PluginService {
|
|
|
54
55
|
getPluginList = async (): Promise<LobeChatPluginsMarketIndex> => {
|
|
55
56
|
const locale = globalHelpers.getCurrentLanguage();
|
|
56
57
|
|
|
57
|
-
const res = await fetch(`${
|
|
58
|
+
const res = await fetch(`${API_ENDPOINTS.pluginStore}?locale=${locale}`);
|
|
58
59
|
|
|
59
60
|
return res.json();
|
|
60
61
|
};
|
|
@@ -112,9 +112,6 @@ export const chatPlugin: StateCreator<
|
|
|
112
112
|
|
|
113
113
|
invokeStandaloneTypePlugin: async (id, payload) => {
|
|
114
114
|
const result = await useToolStore.getState().validatePluginSettings(payload.identifier);
|
|
115
|
-
console.log('------------------');
|
|
116
|
-
console.log(result);
|
|
117
|
-
console.log('------------------');
|
|
118
115
|
if (!result) return;
|
|
119
116
|
|
|
120
117
|
// if the plugin settings is not valid, then set the message with error type
|