@lobehub/chat 1.53.9 → 1.53.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/locales/ar/modelProvider.json +2 -2
  4. package/locales/bg-BG/modelProvider.json +2 -2
  5. package/locales/de-DE/modelProvider.json +2 -2
  6. package/locales/en-US/modelProvider.json +2 -2
  7. package/locales/es-ES/modelProvider.json +2 -2
  8. package/locales/fa-IR/modelProvider.json +2 -2
  9. package/locales/fr-FR/modelProvider.json +2 -2
  10. package/locales/it-IT/modelProvider.json +2 -2
  11. package/locales/ja-JP/modelProvider.json +2 -2
  12. package/locales/ko-KR/modelProvider.json +2 -2
  13. package/locales/nl-NL/modelProvider.json +2 -2
  14. package/locales/pl-PL/modelProvider.json +2 -2
  15. package/locales/pt-BR/modelProvider.json +2 -2
  16. package/locales/ru-RU/modelProvider.json +2 -2
  17. package/locales/tr-TR/modelProvider.json +2 -2
  18. package/locales/vi-VN/modelProvider.json +2 -2
  19. package/locales/zh-CN/modelProvider.json +3 -3
  20. package/locales/zh-TW/modelProvider.json +2 -2
  21. package/package.json +1 -1
  22. package/src/app/[variants]/(main)/settings/provider/(detail)/[id]/page.tsx +0 -2
  23. package/src/app/[variants]/(main)/settings/provider/features/CreateNewProvider/index.tsx +8 -8
  24. package/src/features/Conversation/Error/APIKeyForm/LoadingContext.ts +11 -0
  25. package/src/features/Conversation/Error/APIKeyForm/ProviderApiKeyForm.tsx +14 -11
  26. package/src/features/Conversation/Error/APIKeyForm/index.tsx +38 -33
  27. package/src/features/Conversation/Error/APIKeyForm/useApiKey.ts +9 -5
  28. package/src/locales/default/modelProvider.ts +1 -2
  29. package/src/server/manifest.ts +2 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.53.11](https://github.com/lobehub/lobe-chat/compare/v1.53.10...v1.53.11)
6
+
7
+ <sup>Released on **2025-02-13**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Fix provider form api key.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Fix provider form api key, closes [#6115](https://github.com/lobehub/lobe-chat/issues/6115) ([d074238](https://github.com/lobehub/lobe-chat/commit/d074238))
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.53.10](https://github.com/lobehub/lobe-chat/compare/v1.53.9...v1.53.10)
31
+
32
+ <sup>Released on **2025-02-13**</sup>
33
+
34
+ #### 🐛 Bug Fixes
35
+
36
+ - **misc**: Fix api key input issue.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### What's fixed
44
+
45
+ - **misc**: Fix api key input issue, closes [#6112](https://github.com/lobehub/lobe-chat/issues/6112) ([48e3b85](https://github.com/lobehub/lobe-chat/commit/48e3b85))
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.53.9](https://github.com/lobehub/lobe-chat/compare/v1.53.8...v1.53.9)
6
56
 
7
57
  <sup>Released on **2025-02-13**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,22 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "fixes": [
5
+ "Fix provider form api key."
6
+ ]
7
+ },
8
+ "date": "2025-02-13",
9
+ "version": "1.53.11"
10
+ },
11
+ {
12
+ "children": {
13
+ "fixes": [
14
+ "Fix api key input issue."
15
+ ]
16
+ },
17
+ "date": "2025-02-13",
18
+ "version": "1.53.10"
19
+ },
2
20
  {
3
21
  "children": {
4
22
  "improvements": [
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "يرجى إدخال مفتاح API الخاص بك",
69
- "required": "يرجى إدخال مفتاح API الخاص بك",
70
69
  "title": "مفتاح API"
71
70
  },
72
71
  "basicTitle": "المعلومات الأساسية",
@@ -94,7 +93,8 @@
94
93
  "title": "اسم المزود"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "يرجى إدخال عنوان الطلب الخاص بك، إذا لم يتم إدخاله سيتم استخدام عنوان الطلب المقابل لـ SDK",
96
+ "placeholder": "يرجى إدخال عنوان الطلب الخاص بك",
97
+ "required": "يرجى إدخال عنوان الوكيل",
98
98
  "title": "عنوان الوكيل"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "Моля, въведете вашия API ключ",
69
- "required": "Моля, въведете вашия API ключ",
70
69
  "title": "API ключ"
71
70
  },
72
71
  "basicTitle": "Основна информация",
@@ -94,7 +93,8 @@
94
93
  "title": "Име на доставчика"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "Моля, въведете адреса на вашето запитване, ако не е попълнен, ще се използва съответния адрес на SDK",
96
+ "placeholder": "Моля, въведете адреса на вашето запитване",
97
+ "required": "Моля, въведете адреса на проксито",
98
98
  "title": "Адрес на прокси"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "Bitte geben Sie Ihren API-Schlüssel ein",
69
- "required": "Bitte geben Sie Ihren API-Schlüssel ein",
70
69
  "title": "API-Schlüssel"
71
70
  },
72
71
  "basicTitle": "Grundinformationen",
@@ -94,7 +93,8 @@
94
93
  "title": "Name des Anbieters"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "Bitte geben Sie Ihre Anforderungsadresse ein, wenn nicht angegeben, wird die entsprechende Anforderungsadresse des SDK verwendet",
96
+ "placeholder": "Bitte geben Sie Ihre Anforderungs-URL ein",
97
+ "required": "Bitte geben Sie die Proxy-Adresse ein",
98
98
  "title": "Proxy-Adresse"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "Please enter your API Key",
69
- "required": "Please enter your API Key",
70
69
  "title": "API Key"
71
70
  },
72
71
  "basicTitle": "Basic Information",
@@ -94,7 +93,8 @@
94
93
  "title": "Provider Name"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "Please enter your request URL, if left blank, the corresponding SDK request URL will be used",
96
+ "placeholder": "Please enter your request URL",
97
+ "required": "Please enter the proxy address",
98
98
  "title": "Proxy URL"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "Por favor, introduce tu API Key",
69
- "required": "Por favor, introduce tu API Key",
70
69
  "title": "API Key"
71
70
  },
72
71
  "basicTitle": "Información básica",
@@ -94,7 +93,8 @@
94
93
  "title": "Nombre del proveedor"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "Por favor, introduce tu dirección de solicitud, si no se completa, se usará la dirección de solicitud correspondiente del SDK",
96
+ "placeholder": "Por favor, introduce tu dirección de solicitud",
97
+ "required": "Por favor, introduce la dirección del proxy",
98
98
  "title": "Dirección del proxy"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "لطفاً کلید API خود را وارد کنید",
69
- "required": "لطفاً کلید API خود را وارد کنید",
70
69
  "title": "کلید API"
71
70
  },
72
71
  "basicTitle": "اطلاعات پایه",
@@ -94,7 +93,8 @@
94
93
  "title": "نام ارائه‌دهنده"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "لطفاً آدرس درخواست خود را وارد کنید، در صورت عدم وارد کردن از آدرس درخواست مربوط به SDK استفاده خواهد شد",
96
+ "placeholder": "لطفاً آدرس درخواست خود را وارد کنید",
97
+ "required": "لطفاً آدرس پروکسی را وارد کنید",
98
98
  "title": "آدرس پروکسی"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "Veuillez entrer votre clé API",
69
- "required": "Veuillez entrer votre clé API",
70
69
  "title": "Clé API"
71
70
  },
72
71
  "basicTitle": "Informations de base",
@@ -94,7 +93,8 @@
94
93
  "title": "Nom du fournisseur"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "Veuillez entrer votre adresse de requête, sinon l'adresse de requête correspondante au SDK sera utilisée",
96
+ "placeholder": "Veuillez saisir votre adresse de requête",
97
+ "required": "Veuillez remplir l'adresse du proxy",
98
98
  "title": "Adresse du proxy"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "Inserisci la tua API Key",
69
- "required": "Inserisci la tua API Key",
70
69
  "title": "API Key"
71
70
  },
72
71
  "basicTitle": "Informazioni di base",
@@ -94,7 +93,8 @@
94
93
  "title": "Nome del fornitore"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "Inserisci il tuo indirizzo di richiesta, se non specificato verrà utilizzato l'indirizzo di richiesta corrispondente all'SDK",
96
+ "placeholder": "Inserisci il tuo URL di richiesta",
97
+ "required": "Inserisci l'indirizzo del proxy",
98
98
  "title": "Indirizzo proxy"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "あなたの API キーを入力してください",
69
- "required": "あなたの API キーを入力してください",
70
69
  "title": "API キー"
71
70
  },
72
71
  "basicTitle": "基本情報",
@@ -94,7 +93,8 @@
94
93
  "title": "サービスプロバイダー名"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "リクエストアドレスを入力してください。未入力の場合は SDK に対応するリクエストアドレスが使用されます",
96
+ "placeholder": "リクエストURLを入力してください",
97
+ "required": "プロキシURLを入力してください",
98
98
  "title": "プロキシアドレス"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "API 키를 입력하세요",
69
- "required": "API 키를 입력하세요",
70
69
  "title": "API 키"
71
70
  },
72
71
  "basicTitle": "기본 정보",
@@ -94,7 +93,8 @@
94
93
  "title": "서비스 제공자 이름"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "요청 주소를 입력하세요, 입력하지 않으면 SDK의 요청 주소가 사용됩니다",
96
+ "placeholder": "요청 주소를 입력하세요",
97
+ "required": "프록시 주소를 입력하세요",
98
98
  "title": "프록시 주소"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "Vul je API-sleutel in",
69
- "required": "Vul je API-sleutel in",
70
69
  "title": "API-sleutel"
71
70
  },
72
71
  "basicTitle": "Basisinformatie",
@@ -94,7 +93,8 @@
94
93
  "title": "Naam van de provider"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "Vul je aanvraagadres in, als je dit niet invult, wordt het overeenkomstige aanvraagadres van de SDK gebruikt",
96
+ "placeholder": "Vul je verzoekadres in",
97
+ "required": "Vul het proxyadres in",
98
98
  "title": "Proxy-adres"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "Proszę wpisać swój klucz API",
69
- "required": "Proszę wpisać swój klucz API",
70
69
  "title": "Klucz API"
71
70
  },
72
71
  "basicTitle": "Podstawowe informacje",
@@ -94,7 +93,8 @@
94
93
  "title": "Nazwa dostawcy"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "Proszę wpisać adres żądania, jeśli nie zostanie podany, użyty zostanie odpowiedni adres żądania SDK",
96
+ "placeholder": "Proszę wpisać adres żądania",
97
+ "required": "Proszę wpisać adres proxy",
98
98
  "title": "Adres proxy"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "Por favor, insira sua API Key",
69
- "required": "Por favor, insira sua API Key",
70
69
  "title": "API Key"
71
70
  },
72
71
  "basicTitle": "Informações Básicas",
@@ -94,7 +93,8 @@
94
93
  "title": "Nome do Provedor"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "Por favor, insira seu endereço de requisição, se não for preenchido, será usado o endereço correspondente do SDK",
96
+ "placeholder": "Por favor, insira o seu endereço de solicitação",
97
+ "required": "Por favor, insira o endereço do proxy",
98
98
  "title": "Endereço do Proxy"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "Пожалуйста, введите ваш API Key",
69
- "required": "Пожалуйста, введите ваш API Key",
70
69
  "title": "API Key"
71
70
  },
72
71
  "basicTitle": "Основная информация",
@@ -94,7 +93,8 @@
94
93
  "title": "Имя провайдера"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "Пожалуйста, введите ваш адрес запроса, если не заполните, будет использован соответствующий адрес SDK",
96
+ "placeholder": "Пожалуйста, введите ваш адрес запроса",
97
+ "required": "Пожалуйста, введите адрес прокси",
98
98
  "title": "Адрес прокси"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "Lütfen API Anahtarınızı girin",
69
- "required": "Lütfen API Anahtarınızı girin",
70
69
  "title": "API Anahtarı"
71
70
  },
72
71
  "basicTitle": "Temel Bilgiler",
@@ -94,7 +93,8 @@
94
93
  "title": "Hizmet Sağlayıcı Adı"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "Lütfen istek adresinizi girin, boş bırakılırsa SDK'nın ilgili istek adresi kullanılacaktır",
96
+ "placeholder": "Lütfen istek adresinizi girin",
97
+ "required": "Lütfen proxy adresini girin",
98
98
  "title": "Proxy Adresi"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "Vui lòng nhập API Key của bạn",
69
- "required": "Vui lòng nhập API Key của bạn",
70
69
  "title": "API Key"
71
70
  },
72
71
  "basicTitle": "Thông tin cơ bản",
@@ -94,7 +93,8 @@
94
93
  "title": "Tên nhà cung cấp"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "Vui lòng nhập địa chỉ yêu cầu của bạn, nếu không sẽ sử dụng địa chỉ yêu cầu tương ứng của SDK",
96
+ "placeholder": "Vui lòng nhập địa chỉ yêu cầu của bạn",
97
+ "required": "Vui lòng nhập địa chỉ proxy",
98
98
  "title": "Địa chỉ proxy"
99
99
  },
100
100
  "sdkType": {
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "请填写你的 API Key",
69
- "required": "请填写你的 API Key",
70
69
  "title": "API Key"
71
70
  },
72
71
  "basicTitle": "基本信息",
@@ -94,7 +93,8 @@
94
93
  "title": "服务商名称"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "请填写你的请求地址,如果不填则会使用 SDK 对应的请求地址",
96
+ "placeholder": "请填写你的请求地址",
97
+ "required": "请填写代理地址",
98
98
  "title": "代理地址"
99
99
  },
100
100
  "sdkType": {
@@ -305,4 +305,4 @@
305
305
  "zhipu": {
306
306
  "title": "智谱"
307
307
  }
308
- }
308
+ }
@@ -66,7 +66,6 @@
66
66
  "createNewAiProvider": {
67
67
  "apiKey": {
68
68
  "placeholder": "請填寫你的 API Key",
69
- "required": "請填寫你的 API Key",
70
69
  "title": "API Key"
71
70
  },
72
71
  "basicTitle": "基本資訊",
@@ -94,7 +93,8 @@
94
93
  "title": "服務商名稱"
95
94
  },
96
95
  "proxyUrl": {
97
- "placeholder": "請填寫你的請求地址,如果不填則會使用 SDK 對應的請求地址",
96
+ "placeholder": "請填寫你的請求地址",
97
+ "required": "請填寫代理地址",
98
98
  "title": "代理地址"
99
99
  },
100
100
  "sdkType": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.53.9",
3
+ "version": "1.53.11",
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",
@@ -45,5 +45,3 @@ const Page = async (props: PagePropsWithId) => {
45
45
  };
46
46
 
47
47
  export default Page;
48
-
49
- export const dynamic = 'auto';
@@ -91,6 +91,7 @@ const CreateNewProvider = memo<CreateNewProviderProps>(({ onClose, open }) => {
91
91
  options={[
92
92
  { label: 'OpenAI', value: 'openai' },
93
93
  { label: 'Anthropic', value: 'anthropic' },
94
+ { label: 'Ollama', value: 'ollama' },
94
95
  ]}
95
96
  />
96
97
  ),
@@ -98,6 +99,13 @@ const CreateNewProvider = memo<CreateNewProviderProps>(({ onClose, open }) => {
98
99
  name: 'sdkType',
99
100
  rules: [{ message: t('createNewAiProvider.sdkType.required'), required: true }],
100
101
  },
102
+ {
103
+ children: <Input allowClear placeholder={'https://xxxx-proxy.com/v1'} variant={'filled'} />,
104
+ label: t('createNewAiProvider.proxyUrl.title'),
105
+ minWidth: 400,
106
+ name: [KeyVaultsConfigKey, LLMProviderBaseUrlKey],
107
+ rules: [{ message: t('createNewAiProvider.proxyUrl.required'), required: true }],
108
+ },
101
109
  {
102
110
  children: (
103
111
  <Input.Password
@@ -109,14 +117,6 @@ const CreateNewProvider = memo<CreateNewProviderProps>(({ onClose, open }) => {
109
117
  label: t('createNewAiProvider.apiKey.title'),
110
118
  minWidth: 400,
111
119
  name: [KeyVaultsConfigKey, LLMProviderApiTokenKey],
112
- rules: [{ message: t('createNewAiProvider.apiKey.required'), required: true }],
113
- },
114
- {
115
- children: <Input allowClear placeholder={'https://xxxx-proxy.com/v1'} variant={'filled'} />,
116
- desc: t('createNewAiProvider.proxyUrl.placeholder'),
117
- label: t('createNewAiProvider.proxyUrl.title'),
118
- minWidth: 400,
119
- name: [KeyVaultsConfigKey, LLMProviderBaseUrlKey],
120
120
  },
121
121
  ];
122
122
 
@@ -0,0 +1,11 @@
1
+ import { createContext } from 'react';
2
+
3
+ interface LoadingContextValue {
4
+ loading: boolean;
5
+ setLoading: (loading: boolean) => void;
6
+ }
7
+
8
+ export const LoadingContext = createContext<LoadingContextValue>({
9
+ loading: false,
10
+ setLoading: () => {},
11
+ });
@@ -1,9 +1,11 @@
1
1
  import { Icon } from '@lobehub/ui';
2
- import { Button, Input } from 'antd';
3
- import { Network } from 'lucide-react';
4
- import { ReactNode, memo, useState } from 'react';
2
+ import { Button } from 'antd';
3
+ import { Loader2Icon, Network } from 'lucide-react';
4
+ import { ReactNode, memo, useContext, useState } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
7
+ import { FormInput, FormPassword } from '@/components/FormInput';
8
+ import { LoadingContext } from '@/features/Conversation/Error/APIKeyForm/LoadingContext';
7
9
  import { useProviderName } from '@/hooks/useProviderName';
8
10
  import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
9
11
  import { GlobalLLMProviderKey } from '@/types/user/settings';
@@ -27,6 +29,7 @@ const ProviderApiKeyForm = memo<ProviderApiKeyFormProps>(
27
29
  const { apiKey, baseURL, setConfig } = useApiKey(provider);
28
30
  const { showOpenAIProxyUrl } = useServerConfigStore(featureFlagsSelectors);
29
31
  const providerName = useProviderName(provider);
32
+ const { loading } = useContext(LoadingContext);
30
33
 
31
34
  return (
32
35
  <FormAction
@@ -34,25 +37,25 @@ const ProviderApiKeyForm = memo<ProviderApiKeyFormProps>(
34
37
  description={t(`unlock.apiKey.description`, { name: providerName, ns: 'error' })}
35
38
  title={t(`unlock.apiKey.title`, { name: providerName, ns: 'error' })}
36
39
  >
37
- <Input.Password
40
+ <FormPassword
38
41
  autoComplete={'new-password'}
39
- onChange={(e) => {
40
- setConfig(provider, { apiKey: e.target.value });
42
+ onChange={(value) => {
43
+ setConfig(provider, { apiKey: value });
41
44
  }}
42
45
  placeholder={apiKeyPlaceholder || 'sk-***********************'}
43
- type={'block'}
46
+ suffix={<div>{loading && <Icon icon={Loader2Icon} spin />}</div>}
44
47
  value={apiKey}
45
48
  />
46
49
 
47
50
  {showEndpoint &&
48
51
  showOpenAIProxyUrl &&
49
52
  (showProxy ? (
50
- <Input
51
- onChange={(e) => {
52
- setConfig(provider, { baseURL: e.target.value });
53
+ <FormInput
54
+ onChange={(value) => {
55
+ setConfig(provider, { baseURL: value });
53
56
  }}
54
57
  placeholder={'https://api.openai.com/v1'}
55
- type={'block'}
58
+ suffix={<div>{loading && <Icon icon={Loader2Icon} spin />}</div>}
56
59
  value={baseURL}
57
60
  />
58
61
  ) : (
@@ -1,6 +1,6 @@
1
1
  import { ProviderIcon } from '@lobehub/icons';
2
2
  import { Button } from 'antd';
3
- import { memo, useMemo } from 'react';
3
+ import { memo, useMemo, useState } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
  import { Center, Flexbox } from 'react-layout-kit';
6
6
 
@@ -9,6 +9,7 @@ import { useChatStore } from '@/store/chat';
9
9
  import { GlobalLLMProviderKey } from '@/types/user/settings';
10
10
 
11
11
  import BedrockForm from './Bedrock';
12
+ import { LoadingContext } from './LoadingContext';
12
13
  import ProviderApiKeyForm from './ProviderApiKeyForm';
13
14
 
14
15
  interface APIKeyFormProps {
@@ -18,6 +19,7 @@ interface APIKeyFormProps {
18
19
 
19
20
  const APIKeyForm = memo<APIKeyFormProps>(({ id, provider }) => {
20
21
  const { t } = useTranslation('error');
22
+ const [loading, setLoading] = useState(false);
21
23
 
22
24
  const [resend, deleteMessage] = useChatStore((s) => [s.regenerateMessage, s.deleteMessage]);
23
25
 
@@ -62,38 +64,41 @@ const APIKeyForm = memo<APIKeyFormProps>(({ id, provider }) => {
62
64
  }, [provider]);
63
65
 
64
66
  return (
65
- <Center gap={16} style={{ maxWidth: 300 }}>
66
- {provider === ModelProvider.Bedrock ? (
67
- <BedrockForm />
68
- ) : (
69
- <ProviderApiKeyForm
70
- apiKeyPlaceholder={apiKeyPlaceholder}
71
- avatar={<ProviderIcon provider={provider} size={80} type={'avatar'} />}
72
- provider={provider as GlobalLLMProviderKey}
73
- showEndpoint={provider === ModelProvider.OpenAI}
74
- />
75
- )}
76
- <Flexbox gap={12} width={'100%'}>
77
- <Button
78
- block
79
- onClick={() => {
80
- resend(id);
81
- deleteMessage(id);
82
- }}
83
- style={{ marginTop: 8 }}
84
- type={'primary'}
85
- >
86
- {t('unlock.confirm')}
87
- </Button>
88
- <Button
89
- onClick={() => {
90
- deleteMessage(id);
91
- }}
92
- >
93
- {t('unlock.closeMessage')}
94
- </Button>
95
- </Flexbox>
96
- </Center>
67
+ <LoadingContext value={{ loading, setLoading }}>
68
+ <Center gap={16} style={{ maxWidth: 300 }}>
69
+ {provider === ModelProvider.Bedrock ? (
70
+ <BedrockForm />
71
+ ) : (
72
+ <ProviderApiKeyForm
73
+ apiKeyPlaceholder={apiKeyPlaceholder}
74
+ avatar={<ProviderIcon provider={provider} size={80} type={'avatar'} />}
75
+ provider={provider as GlobalLLMProviderKey}
76
+ showEndpoint={provider === ModelProvider.OpenAI}
77
+ />
78
+ )}
79
+ <Flexbox gap={12} width={'100%'}>
80
+ <Button
81
+ block
82
+ disabled={loading}
83
+ onClick={() => {
84
+ resend(id);
85
+ deleteMessage(id);
86
+ }}
87
+ style={{ marginTop: 8 }}
88
+ type={'primary'}
89
+ >
90
+ {t('unlock.confirm')}
91
+ </Button>
92
+ <Button
93
+ onClick={() => {
94
+ deleteMessage(id);
95
+ }}
96
+ >
97
+ {t('unlock.closeMessage')}
98
+ </Button>
99
+ </Flexbox>
100
+ </Center>
101
+ </LoadingContext>
97
102
  );
98
103
  });
99
104
 
@@ -1,6 +1,8 @@
1
1
  import isEqual from 'fast-deep-equal';
2
+ import { useContext } from 'react';
2
3
 
3
4
  import { isDeprecatedEdition } from '@/const/version';
5
+ import { LoadingContext } from '@/features/Conversation/Error/APIKeyForm/LoadingContext';
4
6
  import { aiProviderSelectors, useAiInfraStore } from '@/store/aiInfra';
5
7
  import { useUserStore } from '@/store/user';
6
8
  import { keyVaultsConfigSelectors } from '@/store/user/selectors';
@@ -11,7 +13,7 @@ export const useApiKey = (provider: string) => {
11
13
  keyVaultsConfigSelectors.getVaultByProvider(provider as any)(s)?.baseURL,
12
14
  s.updateKeyVaultConfig,
13
15
  ]);
14
-
16
+ const { setLoading } = useContext(LoadingContext);
15
17
  const updateAiProviderConfig = useAiInfraStore((s) => s.updateAiProviderConfig);
16
18
  const data = useAiInfraStore(aiProviderSelectors.providerConfigById(provider), isEqual);
17
19
 
@@ -23,12 +25,14 @@ export const useApiKey = (provider: string) => {
23
25
  apiKey: data?.keyVaults.apiKey,
24
26
  baseURL: data?.keyVaults?.baseURL,
25
27
  setConfig: async (id: string, params: Record<string, string>) => {
28
+ const next = { ...data?.keyVaults, ...params };
29
+ if (isEqual(data?.keyVaults, next)) return;
30
+
31
+ setLoading(true);
26
32
  await updateAiProviderConfig(id, {
27
- keyVaults: {
28
- ...data?.keyVaults,
29
- ...params,
30
- },
33
+ keyVaults: { ...data?.keyVaults, ...params },
31
34
  });
35
+ setLoading(false);
32
36
  },
33
37
  };
34
38
  };
@@ -67,7 +67,6 @@ export default {
67
67
  createNewAiProvider: {
68
68
  apiKey: {
69
69
  placeholder: '请填写你的 API Key',
70
- required: '请填写你的 API Key',
71
70
  title: 'API Key',
72
71
  },
73
72
  basicTitle: '基本信息',
@@ -95,7 +94,7 @@ export default {
95
94
  title: '服务商名称',
96
95
  },
97
96
  proxyUrl: {
98
- placeholder: '请填写你的请求地址,如果不填则会使用 SDK 对应的请求地址',
97
+ required: '请填写代理地址',
99
98
  title: '代理地址',
100
99
  },
101
100
  sdkType: {
@@ -63,10 +63,10 @@ export class Manifest {
63
63
  screenshots: screenshots.map((item) => this._getScreenshot(item)),
64
64
  short_name: name,
65
65
  splash_pages: null,
66
- start_url: '.',
66
+ start_url: '/chat',
67
67
  tab_strip: {
68
68
  new_tab_button: {
69
- url: '/',
69
+ url: '/chat',
70
70
  },
71
71
  },
72
72
  theme_color: color,