@lobehub/chat 1.12.3 → 1.12.5

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 CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.12.5](https://github.com/lobehub/lobe-chat/compare/v1.12.4...v1.12.5)
6
+
7
+ <sup>Released on **2024-08-22**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Fix clipboard copy issue and improve upload cors feedback.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Fix clipboard copy issue and improve upload cors feedback, closes [#3557](https://github.com/lobehub/lobe-chat/issues/3557) ([86c5a99](https://github.com/lobehub/lobe-chat/commit/86c5a99))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ### [Version 1.12.4](https://github.com/lobehub/lobe-chat/compare/v1.12.3...v1.12.4)
31
+
32
+ <sup>Released on **2024-08-22**</sup>
33
+
34
+ #### 💄 Styles
35
+
36
+ - **misc**: Fix link style.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### Styles
44
+
45
+ - **misc**: Fix link style, closes [#3552](https://github.com/lobehub/lobe-chat/issues/3552) ([aa936c8](https://github.com/lobehub/lobe-chat/commit/aa936c8))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ### [Version 1.12.3](https://github.com/lobehub/lobe-chat/compare/v1.12.2...v1.12.3)
6
56
 
7
57
  <sup>Released on **2024-08-22**</sup>
@@ -1,19 +1,16 @@
1
1
  ---
2
- title: LobeChat Authorization Service
3
- description: >-
4
- Learn about LobeChat's support for configuring external identity verification
5
- services for centralized user authorization within enterprises/organizations.
6
- Explore supported services like Auth0, Microsoft Entra ID, Authentik, Github,
7
- and ZITADEL.
2
+ title: LobeChat Authentication Service Configuration
3
+ description: Learn how to configure external authentication services using Clerk or Next Auth for centralized user authorization management. Supported authentication services include Auth0, Azure ID, etc.
8
4
  tags:
9
- - SSO Providers
5
+ - Authentication Service
10
6
  - Next Auth
7
+ - SSO
11
8
  - Clerk
12
9
  ---
13
10
 
14
- # LobeChat Authorization
11
+ # Authentication Service
15
12
 
16
- LobeChat supports the configuration of external identity verification services for internal use within enterprises/organizations to centrally manage user authorization.
13
+ LobeChat supports the configuration of external authentication services using Clerk or Next Auth for internal use within enterprises/organizations to centrally manage user authorization.
17
14
 
18
15
  ## Clerk
19
16
 
@@ -21,7 +18,7 @@ Clerk is a comprehensive identity verification solution that has recently gained
21
18
 
22
19
  LobeChat has deeply integrated with Clerk to provide users with a more secure and convenient login and registration experience. It also relieves developers from the burden of managing authentication logic. Clerk's concise and modern design philosophy aligns perfectly with LobeChat's goals, making user management on the entire platform more efficient and reliable.
23
20
 
24
- By setting the environment variables NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY in LobeChat's environment, you can enable and use Clerk.
21
+ By setting the environment variables `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` in LobeChat's environment, you can enable and use Clerk.
25
22
 
26
23
  ## Next Auth
27
24
 
@@ -45,6 +42,7 @@ Currently supported identity verification services include:
45
42
  <Card href={'/docs/self-hosting/advanced/sso-providers/github'} title={'Github'} />
46
43
  <Card href={'/docs/self-hosting/advanced/sso-providers/zitadel'} title={'ZITADEL'} />
47
44
  </Cards>
45
+
48
46
  Click on the links to view the corresponding platform's configuration documentation.
49
47
 
50
48
  ## Advanced Configuration
@@ -18,6 +18,45 @@ The best practice in this area is to use a file storage service (S3) to store im
18
18
  In this documentation, S3 refers to a compatible S3 storage solution, which supports the Amazon S3 API for object storage systems. Common examples include Cloudflare R2, Alibaba Cloud OSS, and self-deployable Minio, all of which support the S3 compatible API.
19
19
  </Callout>
20
20
 
21
+ ## Core Environment Variables
22
+
23
+ <Steps>
24
+ ### `S3_ACCESS_KEY_ID` and `S3_SECRET_ACCESS_KEY`
25
+
26
+ These are the two keys required by all S3 compatible storage services to access the S3 storage service, not detailed here.
27
+
28
+ ### `S3_ENDPOINT`
29
+
30
+ The request endpoint of the storage bucket. Note that this link should not contain the name of the storage bucket.
31
+
32
+ <Callout type={'warning'}>`S3_ENDPOINT` must remove the suffix path, otherwise the uploaded files will not be accessible</Callout>
33
+
34
+ For example, for Cloudflare:
35
+
36
+ ```shell
37
+ S3_ENDPOINT=https://0b33a03b5c993fd2f453379dc36558e5.r2.cloudflarestorage.com
38
+ ```
39
+
40
+ ### `S3_BUCKET` and `S3_REGION`
41
+
42
+ The name and region of the storage bucket. `S3_BUCKET` is required to specify the name of the storage bucket. `S3_REGION` is optional and is used to specify the region of the storage bucket. Generally, it does not need to be added, but some service providers may require configuration.
43
+
44
+ ### `S3_SET_ACL`
45
+
46
+ Whether to set the ACL to `public-read` when uploading files. This option is enabled by default. If the service provider does not support setting individual ACLs for files (i.e., all files inherit the ACL of the storage bucket), enabling this option may cause request errors. Set `S3_SET_ACL` to `0` to disable it.
47
+
48
+ ### `NEXT_PUBLIC_S3_DOMAIN`
49
+
50
+ The public access domain of the storage bucket, used to access files in the storage bucket. This address needs to be **publicly readable**. The reason is that when OpenAI's gpt-4o and other vision models recognize images, OpenAI will try to download this image link on their servers. Therefore, this link must be publicly accessible. If it is a private link, OpenAI will not be able to access the image and thus will not be able to recognize the image content properly.
51
+
52
+ <Callout type={'warning'}>
53
+ Additionally, since this access domain is often a separate URL, it needs to be configured to allow cross-origin access to the site. Otherwise, cross-origin issues will occur in the browser.
54
+ </Callout>
55
+
56
+ </Steps>
57
+
58
+ ## S3 Configuration Guide
59
+
21
60
  Currently, the S3 configuration tutorials included in the documentation are:
22
61
 
23
62
  <Cards>
@@ -32,26 +32,35 @@ Here is the process for deploying the LobeChat server database version on a Linu
32
32
 
33
33
  ### Create a Postgres Database Instance
34
34
 
35
- Create a Postgres database instance according to your needs, for example:
35
+ Please create a Postgres database instance with the PGVector plugin according to your needs, for example:
36
36
 
37
37
  ```sh
38
- docker run --name my-postgres --network pg -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgres
38
+ docker network create pg
39
+
40
+ docker run --name my-postgres --network pg -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d pgvector/pgvector:pg16
39
41
  ```
40
42
 
41
- <Callout type="warning">
42
- The above command is only for testing/demonstration purposes because this pg instance does not include a persistent part.
43
+ The above command will create a PG instance named `my-postgres` on the network `pg`, where `pgvector/pgvector:pg16` is a Postgres 16 image with the pgvector plugin installed by default.
44
+
45
+ <Callout type="info">
46
+ The pgvector plugin provides vector search capabilities for Postgres, which is an important component for LobeChat to implement RAG.
43
47
  </Callout>
44
48
 
45
- The above command will create a PG instance named `my-postgres` on the network `pg`.
49
+ <Callout type="warning">
50
+ The above command does not specify a persistent storage location for the pg instance, so it is only for testing/demonstration purposes. Please configure persistent storage for production environments.
51
+ </Callout>
46
52
 
47
53
  ### Create a file named `lobe-chat.env` to store environment variables:
48
54
 
49
55
  ```shell
50
- # DB required
56
+ # Website domain
57
+ APP_URL=https://your-prod-domain.com
58
+
59
+ # DB required environment variables
51
60
  KEY_VAULTS_SECRET=jgwsK28dspyVQoIf8/M3IIHl1h6LYYceSYNXeLpy6uk=
52
61
  DATABASE_URL=postgres://postgres:mysecretpassword@my-postgres:5432/postgres
53
62
 
54
- # NEXT_AUTH related
63
+ # NEXT_AUTH related, can use auth0, Azure AD, GitHub, Authentik, zitadel, etc. If you have other access requirements, feel free to submit a PR
55
64
  NEXT_AUTH_SECRET=3904039cd41ea1bdf6c93db0db96e250
56
65
  NEXT_AUTH_SSO_PROVIDERS=auth0
57
66
  NEXTAUTH_URL=https://your-prod-domain.com/api/auth
@@ -103,20 +112,21 @@ The script command you need to execute is:
103
112
 
104
113
  ```shell
105
114
  $ docker run -it -d --name lobe-chat-database -p 3210:3210 \
106
- -e DATABASE_URL=postgres://postgres:mysecretpassword@host.docker.internal:5432/postgres \
107
- -e KEY_VAULTS_SECRET=jgwsK28dspyVQoIf8/M3IIHl1h6LYYceSYNXeLpy6uk= \
108
- -e NEXT_AUTH_SECRET=3904039cd41ea1bdf6c93db0db96e250 \
109
- -e NEXT_AUTH_SSO_PROVIDERS=auth0 \
110
- -e AUTH0_CLIENT_ID=xxxxxx \
111
- -e AUTH0_CLIENT_SECRET=cSX_xxxxx \
112
- -e AUTH0_ISSUER=https://lobe-chat-demo.us.auth0.com \
113
- -e NEXTAUTH_URL=http://localhost:3210/api/auth \
114
- -e S3_ACCESS_KEY_ID=xxxxxxxxxx \
115
- -e S3_SECRET_ACCESS_KEY=xxxxxxxxxx \
116
- -e S3_ENDPOINT=https://xxxxxxxxxx.r2.cloudflarestorage.com \
117
- -e S3_BUCKET=lobechat \
118
- -e NEXT_PUBLIC_S3_DOMAIN=https://s3-for-lobechat.your-domain.com \
119
- lobehub/lobe-chat-database
115
+ -e DATABASE_URL=postgres://postgres:mysecretpassword@host.docker.internal:5432/postgres \
116
+ -e KEY_VAULTS_SECRET=jgwsK28dspyVQoIf8/M3IIHl1h6LYYceSYNXeLpy6uk= \
117
+ -e NEXT_AUTH_SECRET=3904039cd41ea1bdf6c93db0db96e250 \
118
+ -e NEXT_AUTH_SSO_PROVIDERS=auth0 \
119
+ -e AUTH0_CLIENT_ID=xxxxxx \
120
+ -e AUTH0_CLIENT_SECRET=cSX_xxxxx \
121
+ -e AUTH0_ISSUER=https://lobe-chat-demo.us.auth0.com \
122
+ -e APP_URL=http://localhost:3210 \
123
+ -e NEXTAUTH_URL=http://localhost:3210/api/auth \
124
+ -e S3_ACCESS_KEY_ID=xxxxxxxxxx \
125
+ -e S3_SECRET_ACCESS_KEY=xxxxxxxxxx \
126
+ -e S3_ENDPOINT=https://xxxxxxxxxx.r2.cloudflarestorage.com \
127
+ -e S3_BUCKET=lobechat \
128
+ -e NEXT_PUBLIC_S3_DOMAIN=https://s3-for-lobechat.your-domain.com \
129
+ lobehub/lobe-chat-database
120
130
  ```
121
131
 
122
132
  <Callout type="tip">
@@ -36,7 +36,9 @@ Before deployment, make sure you have a Postgres database instance ready. You ca
36
36
  - `A.` Use Serverless Postgres instances like Vercel/Neon;
37
37
  - `B.` Use self-deployed Postgres instances like Docker/Railway/Zeabur, collectively referred to as Node Postgres instances;
38
38
 
39
- There is a slight difference in the way they are configured in terms of environment variables.
39
+ <Callout>There is a slight difference in the way they are configured in terms of environment variables.</Callout>
40
+
41
+ Since we support file-based conversations/knowledge base conversations, we need to install the `pgvector` plugin for Postgres. This plugin provides vector search capabilities and is a key component for LobeChat to implement RAG.
40
42
 
41
43
  <Steps>
42
44
  ### `NEXT_PUBLIC_SERVICE_MODE`
@@ -49,6 +51,12 @@ For server-side database deployment scenarios, you need to set `NEXT_PUBLIC_SERV
49
51
  In the official `lobe-chat-database` Docker image, this environment variable is already set to `server` by default. Therefore, if you deploy using the Docker image, you do not need to configure this environment variable again.
50
52
  </Callout>
51
53
 
54
+ <Callout type={'tip'}>
55
+ Since environment variables starting with `NEXT_PUBLIC` take effect in the front-end code, they cannot be modified through container runtime injection. (Refer to the `next.js` documentation [Configuring: Environment Variables | Next.js (nextjs.org)](https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables)). This is why we chose to create a separate DB version image.
56
+
57
+ If you need to modify variables with the `NEXT_PUBLIC` prefix in a Docker deployment, you must build the image yourself and inject your own `NEXT_PUBLIC` prefixed environment variables during the build.
58
+ </Callout>
59
+
52
60
  ### `DATABASE_URL`
53
61
 
54
62
  The core of configuring the database is to add the `DATABASE_URL` environment variable and fill in the Postgres database connection URL you have prepared. The typical format of the database connection URL is `postgres://username:password@host:port/database`.
@@ -87,7 +95,7 @@ In the server-side database mode, we need an authentication service to distingui
87
95
 
88
96
  ### Clerk
89
97
 
90
- [Clerk](https://clerk.com?utm_source=lobehub\&utm_medium=docs) is an authentication SaaS service that provides out-of-the-box authentication capabilities with high productization, low integration costs, and a great user experience. For those who offer SaaS products, Clerk is a good choice. Our official [LobeChat Cloud](https://lobechat.com) uses Clerk as the authentication service.
98
+ [Clerk](https://clerk.com?utm_source=lobehub&utm_medium=docs) is an authentication SaaS service that provides out-of-the-box authentication capabilities with high productization, low integration costs, and a great user experience. For those who offer SaaS products, Clerk is a good choice. Our official [LobeChat Cloud](https://lobechat.com) uses Clerk as the authentication service.
91
99
 
92
100
  The integration of Clerk is relatively simple, requiring only the configuration of the `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY`, `CLERK_SECRET_KEY`, and `CLERK_WEBHOOK_SECRET` environment variables, which can be obtained from the Clerk console.
93
101
 
@@ -123,40 +131,6 @@ The best practice in this area is to use a file storage service (S3) to store im
123
131
  In this documentation, S3 refers to a compatible S3 storage solution, which supports the Amazon S3 API-compatible object storage system. Common examples include Cloudflare R2, Alibaba Cloud OSS, and self-deployable Minio, all of which support the S3-compatible API.
124
132
  </Callout>
125
133
 
126
- <Steps>
127
- ### `S3_ACCESS_KEY_ID` and `S3_SECRET_ACCESS_KEY`
128
-
129
- These are the two keys required by all S3-compatible storage services to access the S3 storage service, without going into detail.
130
-
131
- ### `S3_ENDPOINT`
132
-
133
- The request endpoint of the bucket, note that the link here should not include the bucket's name.
134
-
135
- <Callout type={'warning'}>`S3_ENDPOINT` must remove the suffix path, otherwise the uploaded files will not be accessible.</Callout>
136
-
137
- For example, for Cloudflare:
138
-
139
- ```shell
140
- S3_ENDPOINT=https://0b33a03b5c993fd2f453379dc36558e5.r2.cloudflarestorage.com
141
- ```
142
-
143
- ### `S3_BUCKET` and `S3_REGION`
144
-
145
- The name and region of the bucket. `S3_BUCKET` is mandatory for specifying the bucket's name. `S3_REGION` is optional for specifying the bucket's region, generally not required to add, but some service providers may need to configure it.
146
-
147
- ### `S3_SET_ACL`
148
- Whether to set the ACL to `public-read` when uploading files. This option is enabled by default. If the service provider does not support setting individual ACLs for files (i.e., all files inherit the bucket's ACL), enabling this option may result in a request error. You can disable it by setting `S3_SET_ACL` to `0`.
149
-
150
- ### `NEXT_PUBLIC_S3_DOMAIN`
151
-
152
- The public access domain of the bucket, used to access files in the bucket. This address needs to be **internet-readable**. The reason is that when OpenAI's GPT-4o and other visual models recognize images, OpenAI will try to download the image link on their servers. Therefore, this link must be publicly accessible. If it is a private link, OpenAI will not be able to access the image and will not be able to recognize the image content properly.
153
-
154
- <Callout type={'warning'}>
155
- In addition, since this access domain is often an independent URL, it needs to be configured to allow cross-origin access to the site, otherwise cross-origin issues will occur in the browser.
156
- </Callout>
157
-
158
- </Steps>
159
-
160
134
  For detailed configuration guidelines on S3, please refer to [S3 Object Storage](/en/docs/self-hosting/advanced/s3) for more information.
161
135
 
162
136
  ## Getting Started with Deployment
@@ -164,4 +138,3 @@ For detailed configuration guidelines on S3, please refer to [S3 Object Storage]
164
138
  The above is a detailed explanation of configuring LobeChat with a server-side database. You can configure it according to your actual situation and then choose a deployment platform that suits you to start deployment:
165
139
 
166
140
  <PlatformCards urlPrefix={'server-database'} />
167
-
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "التفاصيل: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "وضع النشر الحالي لا يدعم تحميل ملفات غير الصور. إذا كنت بحاجة إلى تحميل تنسيق {{ext}}، يرجى التبديل إلى نشر قاعدة بيانات الخادم أو استخدام خدمة LobeChat Cloud.",
119
- "title": "فشل تحميل الملف، يرجى التحقق من الاتصال بالشبكة أو المحاولة لاحقًا"
119
+ "networkError": "يرجى التأكد من أن اتصال الشبكة لديك يعمل بشكل صحيح، والتحقق من إعدادات تكوين خدمة تخزين الملفات عبر النطاق.",
120
+ "title": "فشل تحميل الملف، يرجى التحقق من الاتصال بالشبكة أو المحاولة لاحقًا",
121
+ "unknownError": "سبب الخطأ: {{reason}}",
122
+ "uploadFailed": "فشل تحميل الملف"
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "Подробности: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "Текущият режим на разполагане не поддържа качване на файлове, различни от изображения. За да качите формат {{ext}}, моля, превключете на разполагане с база данни на сървъра или използвайте услугата LobeChat Cloud.",
119
- "title": "Неуспешно качване на файл, моля проверете интернет връзката или опитайте по-късно"
119
+ "networkError": "Моля, уверете се, че вашата мрежа работи нормално и проверете дали конфигурацията за крос-домейн на услугата за съхранение на файлове е правилна.",
120
+ "title": "Неуспешно качване на файл, моля проверете интернет връзката или опитайте по-късно",
121
+ "unknownError": "Причина за грешка: {{reason}}",
122
+ "uploadFailed": "Неуспешно качване на файла."
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "Details: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "Der aktuelle Bereitstellungsmodus unterstützt das Hochladen von Nicht-Bilddateien nicht. Um Dateien im {{ext}}-Format hochzuladen, wechseln Sie bitte zum Serverdatenbank-Bereitstellungsmodus oder verwenden Sie den LobeChat Cloud-Dienst.",
119
- "title": "Dateiupload fehlgeschlagen. Bitte überprüfen Sie Ihre Netzwerkverbindung und versuchen Sie es später erneut."
119
+ "networkError": "Bitte überprüfen Sie, ob Ihre Internetverbindung stabil ist, und prüfen Sie die Cross-Origin-Konfiguration des Dateispeicherdienstes.",
120
+ "title": "Dateiupload fehlgeschlagen. Bitte überprüfen Sie Ihre Netzwerkverbindung und versuchen Sie es später erneut.",
121
+ "unknownError": "Fehlerursache: {{reason}}",
122
+ "uploadFailed": "Der Datei-Upload ist fehlgeschlagen."
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "Details: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "The current deployment mode does not support uploading non-image files. To upload files in {{ext}} format, please switch to server database deployment or use LobeChat Cloud service.",
119
- "title": "File upload failed. Please check your network connection or try again later"
119
+ "networkError": "Please check your network connection and ensure that the file storage service's cross-origin configuration is correct.",
120
+ "title": "File upload failed. Please check your network connection or try again later",
121
+ "unknownError": "Error reason: {{reason}}",
122
+ "uploadFailed": "File upload failed."
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "Detalles: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "El modo de implementación actual no admite la carga de archivos que no sean imágenes. Si desea cargar un archivo en formato {{ext}}, cambie a la implementación de base de datos en servidor o utilice el servicio LobeChat Cloud.",
119
- "title": "Error al subir el archivo, por favor verifica la conexión a internet o inténtalo de nuevo más tarde"
119
+ "networkError": "Por favor, verifica que tu red esté funcionando correctamente y comprueba si la configuración de CORS del servicio de almacenamiento de archivos es correcta.",
120
+ "title": "Error al subir el archivo, por favor verifica la conexión a internet o inténtalo de nuevo más tarde",
121
+ "unknownError": "Razón del error: {{reason}}",
122
+ "uploadFailed": "La carga del archivo ha fallado."
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "Détails : {{detail}}",
118
118
  "fileOnlySupportInServerMode": "Le mode de déploiement actuel ne prend pas en charge le téléchargement de fichiers non image. Pour télécharger un format {{ext}}, veuillez passer à un déploiement de base de données côté serveur ou utiliser le service LobeChat Cloud.",
119
- "title": "Échec de l'envoi du fichier, veuillez vérifier votre connexion réseau ou réessayer plus tard"
119
+ "networkError": "Veuillez vérifier si votre réseau fonctionne correctement et assurez-vous que la configuration CORS du service de stockage de fichiers est correcte.",
120
+ "title": "Échec de l'envoi du fichier, veuillez vérifier votre connexion réseau ou réessayer plus tard",
121
+ "unknownError": "Raison de l'erreur : {{reason}}",
122
+ "uploadFailed": "Échec du téléchargement du fichier."
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "Dettagli: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "L'attuale modalità di distribuzione non supporta il caricamento di file non immagine. Se desideri caricare un formato {{ext}}, ti preghiamo di passare alla distribuzione del database sul server o di utilizzare il servizio LobeChat Cloud.",
119
- "title": "Caricamento del file fallito, controlla la connessione di rete o riprova più tardi"
119
+ "networkError": "Si prega di verificare che la connessione di rete sia stabile e controllare se la configurazione CORS del servizio di archiviazione file è corretta.",
120
+ "title": "Caricamento del file fallito, controlla la connessione di rete o riprova più tardi",
121
+ "unknownError": "Motivo dell'errore: {{reason}}",
122
+ "uploadFailed": "Caricamento del file non riuscito."
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "詳細: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "現在のデプロイモードでは、画像以外のファイルのアップロードはサポートされていません。{{ext}} 形式のファイルをアップロードするには、サーバーデータベースデプロイに切り替えるか、LobeChat Cloud サービスを使用してください。",
119
- "title": "ファイルのアップロードに失敗しました。ネットワーク接続を確認するか、後でもう一度お試しください"
119
+ "networkError": "ネットワークが正常であることを確認し、ファイルストレージサービスのクロスオリジン設定が正しいかどうかを確認してください。",
120
+ "title": "ファイルのアップロードに失敗しました。ネットワーク接続を確認するか、後でもう一度お試しください",
121
+ "unknownError": "エラーの原因: {{reason}}",
122
+ "uploadFailed": "ファイルのアップロードに失敗しました。"
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "상세 내용: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "현재 배포 모드에서는 이미지 파일이 아닌 파일 업로드를 지원하지 않습니다. {{ext}} 형식을 업로드하려면 서버 데이터베이스 배포로 전환하거나 LobeChat Cloud 서비스를 사용하세요.",
119
- "title": "파일 업로드 실패, 네트워크 연결을 확인하거나 나중에 다시 시도해주세요"
119
+ "networkError": "네트워크가 정상인지 확인하고 파일 저장 서비스의 교차 출처 구성도 올바른지 확인하세요.",
120
+ "title": "파일 업로드 실패, 네트워크 연결을 확인하거나 나중에 다시 시도해주세요",
121
+ "unknownError": "오류 원인: {{reason}}",
122
+ "uploadFailed": "파일 업로드에 실패했습니다."
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "Details: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "De huidige implementatiemodus ondersteunt het uploaden van niet-afbeeldingsbestanden niet. Als u bestanden in {{ext}}-formaat wilt uploaden, schakelt u over naar de serverdatabase-implementatie of gebruikt u de LobeChat Cloud-service.",
119
- "title": "Bestand uploaden mislukt, controleer uw internetverbinding of probeer het later opnieuw"
119
+ "networkError": "Controleer of je netwerk goed werkt en of de cross-origin configuratie van de bestandsopslagservice correct is.",
120
+ "title": "Bestand uploaden mislukt, controleer uw internetverbinding of probeer het later opnieuw",
121
+ "unknownError": "Foutreden: {{reason}}",
122
+ "uploadFailed": "Bestand uploaden is mislukt."
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "Szczegóły: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "Aktualny tryb wdrożenia nie obsługuje przesyłania plików, które nie są obrazami. Aby przesłać pliki w formacie {{ext}}, przełącz się na wdrożenie bazy danych na serwerze lub skorzystaj z usługi LobeChat Cloud.",
119
- "title": "Nie udało się przesłać pliku. Sprawdź połączenie sieciowe lub spróbuj ponownie później"
119
+ "networkError": "Proszę upewnić się, że Twoja sieć działa poprawnie oraz sprawdzić, czy konfiguracja CORS dla usługi przechowywania plików jest prawidłowa.",
120
+ "title": "Nie udało się przesłać pliku. Sprawdź połączenie sieciowe lub spróbuj ponownie później",
121
+ "unknownError": "Przyczyna błędu: {{reason}}",
122
+ "uploadFailed": "Wysyłanie pliku nie powiodło się."
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "Detalhes: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "O modo de implantação atual não suporta o upload de arquivos que não sejam imagens. Para fazer o upload de arquivos no formato {{ext}}, por favor, mude para a implantação do banco de dados no servidor ou utilize o serviço LobeChat Cloud.",
119
- "title": "Falha ao enviar o arquivo, verifique a conexão de rede ou tente novamente mais tarde"
119
+ "networkError": "Por favor, verifique se sua rede está funcionando corretamente e se a configuração de CORS do serviço de armazenamento de arquivos está correta.",
120
+ "title": "Falha ao enviar o arquivo, verifique a conexão de rede ou tente novamente mais tarde",
121
+ "unknownError": "Erro: {{reason}}",
122
+ "uploadFailed": "Falha ao fazer o upload do arquivo."
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "Подробности: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "Текущий режим развертывания не поддерживает загрузку файлов, отличных от изображений. Если вы хотите загрузить файл формата {{ext}}, пожалуйста, переключитесь на развертывание с серверной базой данных или используйте LobeChat Cloud.",
119
- "title": "Ошибка загрузки файла. Проверьте подключение к сети или попробуйте позже"
119
+ "networkError": "Пожалуйста, убедитесь, что ваше соединение с сетью работает нормально, и проверьте правильность конфигурации кросс-доменных запросов для службы хранения файлов.",
120
+ "title": "Ошибка загрузки файла. Проверьте подключение к сети или попробуйте позже",
121
+ "unknownError": "Причина ошибки: {{reason}}",
122
+ "uploadFailed": "Ошибка загрузки файла"
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "Detay: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "Mevcut dağıtım modu, yalnızca resim dosyalarının yüklenmesini desteklemektedir. {{ext}} formatında bir dosya yüklemek istiyorsanız, lütfen sunucu veritabanı dağıtımına geçin veya LobeChat Cloud hizmetini kullanın.",
119
- "title": "Dosya yükleme başarısız, lütfen bağlantınızı kontrol edin veya daha sonra tekrar deneyin"
119
+ "networkError": "Lütfen bağlantınızın düzgün çalıştığından emin olun ve dosya depolama hizmetinin çapraz alan yapılandırmasının doğru olup olmadığını kontrol edin.",
120
+ "title": "Dosya yükleme başarısız, lütfen ağ bağlantınızı kontrol edin veya daha sonra tekrar deneyin",
121
+ "unknownError": "Hata nedeni: {{reason}}",
122
+ "uploadFailed": "Dosya yüklemesi başarısız oldu."
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "Chi tiết: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "Chế độ triển khai hiện tại không hỗ trợ tải lên các tệp không phải hình ảnh. Nếu bạn cần tải lên định dạng {{ext}}, vui lòng chuyển sang triển khai cơ sở dữ liệu trên máy chủ hoặc sử dụng dịch vụ LobeChat Cloud.",
119
- "title": "Tải lên tệp thất bại, vui lòng kiểm tra kết nối mạng hoặc thử lại sau"
119
+ "networkError": "Vui lòng kiểm tra xem mạng của bạn có hoạt động bình thường không và kiểm tra cấu hình chia sẻ tệp giữa các miền có đúng không",
120
+ "title": "Tải lên tệp thất bại, vui lòng kiểm tra kết nối mạng hoặc thử lại sau",
121
+ "unknownError": "Lỗi: {{reason}}",
122
+ "uploadFailed": "Tải tệp lên không thành công"
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "详情: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "当前部署模式不支持上传非图片文件,如需上传 {{ext}} 格式,请切换到服务端数据库部署或使用 LobeChat Cloud 服务",
119
- "title": "文件上传失败,请检查网络连接或稍后再试"
119
+ "networkError": "请确认你的网络是否正常,并检查文件存储服务跨域配置是否正确",
120
+ "title": "文件上传失败,请检查网络连接或稍后再试",
121
+ "unknownError": "错误原因: {{reason}}",
122
+ "uploadFailed": "文件上传失败"
120
123
  }
121
124
  }
@@ -116,6 +116,9 @@
116
116
  "upload": {
117
117
  "desc": "詳情: {{detail}}",
118
118
  "fileOnlySupportInServerMode": "當前部署模式不支持上傳非圖片文件,如需上傳 {{ext}} 格式,請切換到伺服器端資料庫部署或使用 LobeChat Cloud 服務",
119
- "title": "檔案上傳失敗,請檢查網路連線或稍後再試"
119
+ "networkError": "請確認你的網路是否正常,並檢查檔案儲存服務的跨域配置是否正確",
120
+ "title": "檔案上傳失敗,請檢查網路連線或稍後再試",
121
+ "unknownError": "錯誤原因: {{reason}}",
122
+ "uploadFailed": "檔案上傳失敗"
120
123
  }
121
124
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.12.3",
3
+ "version": "1.12.5",
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",
@@ -135,7 +135,7 @@
135
135
  "@vercel/speed-insights": "^1.0.12",
136
136
  "ahooks": "^3.8.0",
137
137
  "ai": "^3.2.16",
138
- "antd": "5.20.0",
138
+ "antd": "^5.20.2",
139
139
  "antd-style": "^3.6.2",
140
140
  "brotli-wasm": "^3.0.1",
141
141
  "chroma-js": "^2.4.2",
@@ -164,7 +164,7 @@
164
164
  "mammoth": "^1.8.0",
165
165
  "modern-screenshot": "^4.4.39",
166
166
  "nanoid": "^5.0.7",
167
- "next": "14.2.5",
167
+ "next": "^14.2.6",
168
168
  "next-auth": "5.0.0-beta.15",
169
169
  "next-sitemap": "^4.2.3",
170
170
  "numeral": "^2.0.6",
@@ -0,0 +1,130 @@
1
+ import { act, renderHook } from '@testing-library/react';
2
+ import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
+
4
+ import { getContainer, useDragUpload } from './useDragUpload';
5
+
6
+ describe('useDragUpload', () => {
7
+ let mockOnUploadFiles: Mock;
8
+
9
+ beforeEach(() => {
10
+ mockOnUploadFiles = vi.fn();
11
+ vi.useFakeTimers();
12
+ document.body.innerHTML = '';
13
+ });
14
+
15
+ afterEach(() => {
16
+ vi.useRealTimers();
17
+ vi.clearAllMocks();
18
+ });
19
+
20
+ it('should initialize and cleanup correctly', () => {
21
+ const { result, unmount } = renderHook(() => useDragUpload(mockOnUploadFiles));
22
+
23
+ expect(result.current).toBe(false);
24
+ expect(document.getElementById('dragging-root')).not.toBeNull();
25
+
26
+ unmount();
27
+
28
+ expect(document.getElementById('dragging-root')).toBeNull();
29
+ });
30
+
31
+ it('should handle drag events correctly', () => {
32
+ const { result } = renderHook(() => useDragUpload(mockOnUploadFiles));
33
+
34
+ act(() => {
35
+ window.dispatchEvent(new Event('dragenter'));
36
+ });
37
+
38
+ expect(result.current).toBe(false);
39
+
40
+ act(() => {
41
+ const dragEnterEvent = new Event('dragenter') as DragEvent;
42
+ Object.defineProperty(dragEnterEvent, 'dataTransfer', {
43
+ value: {
44
+ items: [{}],
45
+ types: ['Files'],
46
+ },
47
+ });
48
+ window.dispatchEvent(dragEnterEvent);
49
+ });
50
+
51
+ expect(result.current).toBe(true);
52
+
53
+ act(() => {
54
+ const dragLeaveEvent = new Event('dragleave') as DragEvent;
55
+ Object.defineProperty(dragLeaveEvent, 'dataTransfer', {
56
+ value: {
57
+ items: [{}],
58
+ types: ['Files'],
59
+ },
60
+ });
61
+ window.dispatchEvent(dragLeaveEvent);
62
+ });
63
+
64
+ expect(result.current).toBe(false);
65
+ });
66
+
67
+ it('should handle file drop', async () => {
68
+ renderHook(() => useDragUpload(mockOnUploadFiles));
69
+
70
+ const mockFile = new File([''], 'test.txt', { type: 'text/plain' });
71
+ const dropEvent = new Event('drop') as DragEvent;
72
+ Object.defineProperty(dropEvent, 'dataTransfer', {
73
+ value: {
74
+ items: [
75
+ {
76
+ kind: 'file',
77
+ getAsFile: () => mockFile,
78
+ webkitGetAsEntry: () => ({
79
+ isFile: true,
80
+ file: (cb: (file: File) => void) => cb(mockFile),
81
+ }),
82
+ },
83
+ ],
84
+ types: ['Files'],
85
+ },
86
+ });
87
+
88
+ await act(async () => {
89
+ window.dispatchEvent(dropEvent);
90
+ });
91
+
92
+ expect(mockOnUploadFiles).toHaveBeenCalledWith([mockFile]);
93
+ });
94
+
95
+ it('should handle paste event', async () => {
96
+ renderHook(() => useDragUpload(mockOnUploadFiles));
97
+
98
+ const mockFile = new File([''], 'test.txt', { type: 'text/plain' });
99
+ const pasteEvent = new Event('paste') as ClipboardEvent;
100
+ Object.defineProperty(pasteEvent, 'clipboardData', {
101
+ value: {
102
+ items: [
103
+ {
104
+ kind: 'file',
105
+ getAsFile: () => mockFile,
106
+ webkitGetAsEntry: () => null,
107
+ },
108
+ ],
109
+ },
110
+ });
111
+
112
+ await act(async () => {
113
+ window.dispatchEvent(pasteEvent);
114
+ });
115
+
116
+ expect(mockOnUploadFiles).toHaveBeenCalledWith([mockFile]);
117
+ });
118
+ });
119
+
120
+ describe('getContainer', () => {
121
+ it('should return the dragging root element', () => {
122
+ const rootElement = document.createElement('div');
123
+ rootElement.id = 'dragging-root';
124
+ document.body.appendChild(rootElement);
125
+
126
+ const container = getContainer();
127
+ expect(container).not.toBeNull();
128
+ expect(container?.id).toBe('dragging-root');
129
+ });
130
+ });
@@ -40,6 +40,15 @@ const getFileListFromDataTransferItems = async (items: DataTransferItem[]) => {
40
40
  const entry = item.webkitGetAsEntry();
41
41
  if (entry) {
42
42
  filePromises.push(processEntry(entry));
43
+ } else {
44
+ const file = item.getAsFile();
45
+
46
+ if (file)
47
+ filePromises.push(
48
+ new Promise((resolve) => {
49
+ resolve([file]);
50
+ }),
51
+ );
43
52
  }
44
53
  }
45
54
  }
@@ -142,6 +142,9 @@ export default {
142
142
  desc: '详情: {{detail}}',
143
143
  fileOnlySupportInServerMode:
144
144
  '当前部署模式不支持上传非图片文件,如需上传 {{ext}} 格式,请切换到服务端数据库部署或使用 LobeChat Cloud 服务',
145
+ networkError: '请确认你的网络是否正常,并检查文件存储服务跨域配置是否正确',
145
146
  title: '文件上传失败,请检查网络连接或稍后再试',
147
+ unknownError: '错误原因: {{reason}}',
148
+ uploadFailed: '文件上传失败',
146
149
  },
147
150
  };
@@ -5,6 +5,8 @@ import { FileMetadata, UploadFileParams } from '@/types/files';
5
5
  import { FileUploadState, FileUploadStatus } from '@/types/files/upload';
6
6
  import { uuid } from '@/utils/uuid';
7
7
 
8
+ export const UPLOAD_NETWORK_ERROR = 'NetWorkError';
9
+
8
10
  class UploadService {
9
11
  uploadWithProgress = async (
10
12
  file: File,
@@ -13,7 +15,6 @@ class UploadService {
13
15
  const xhr = new XMLHttpRequest();
14
16
 
15
17
  const { preSignUrl, ...result } = await this.getSignedUploadUrl(file);
16
-
17
18
  let startTime = Date.now();
18
19
  xhr.upload.addEventListener('progress', (event) => {
19
20
  if (event.lengthComputable) {
@@ -49,7 +50,10 @@ class UploadService {
49
50
  reject(xhr.statusText);
50
51
  }
51
52
  });
52
- xhr.addEventListener('error', () => reject(xhr.statusText));
53
+ xhr.addEventListener('error', () => {
54
+ if (xhr.status === 0) reject(UPLOAD_NETWORK_ERROR);
55
+ else reject(xhr.statusText);
56
+ });
53
57
  xhr.send(data);
54
58
  });
55
59
 
@@ -1,11 +1,14 @@
1
+ import { t } from 'i18next';
1
2
  import { produce } from 'immer';
2
3
  import useSWR, { SWRResponse } from 'swr';
3
4
  import { StateCreator } from 'zustand/vanilla';
4
5
 
6
+ import { notification } from '@/components/AntdStaticMethods';
5
7
  import { FILE_UPLOAD_BLACKLIST } from '@/const/file';
6
8
  import { fileService } from '@/services/file';
7
9
  import { ServerService } from '@/services/file/server';
8
10
  import { ragService } from '@/services/rag';
11
+ import { UPLOAD_NETWORK_ERROR } from '@/services/upload';
9
12
  import { userService } from '@/services/user';
10
13
  import { useAgentStore } from '@/store/agent';
11
14
  import {
@@ -128,10 +131,30 @@ export const createFileSlice: StateCreator<
128
131
 
129
132
  // upload files and process it
130
133
  const pools = files.map(async (file) => {
131
- const fileResult = await get().uploadWithProgress({
132
- file,
133
- onStatusUpdate: dispatchChatUploadFileList,
134
- });
134
+ let fileResult: { id: string; url: string } | undefined;
135
+
136
+ try {
137
+ fileResult = await get().uploadWithProgress({
138
+ file,
139
+ onStatusUpdate: dispatchChatUploadFileList,
140
+ });
141
+ } catch (error) {
142
+ // skip `UNAUTHORIZED` error
143
+ if ((error as any)?.message !== 'UNAUTHORIZED')
144
+ notification.error({
145
+ description:
146
+ // it may be a network error or the cors error
147
+ error === UPLOAD_NETWORK_ERROR
148
+ ? t('upload.networkError', { ns: 'error' })
149
+ : // or the error from the server
150
+ typeof error === 'string'
151
+ ? error
152
+ : t('upload.unknownError', { ns: 'error', reason: (error as Error).message }),
153
+ message: t('upload.uploadFailed', { ns: 'error' }),
154
+ });
155
+
156
+ dispatchChatUploadFileList({ id: file.name, type: 'removeFile' });
157
+ }
135
158
 
136
159
  if (!fileResult) return;
137
160