@lobehub/chat 1.14.11 → 1.15.0
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 +51 -0
- package/Dockerfile +2 -0
- package/Dockerfile.database +2 -0
- package/locales/ar/file.json +2 -1
- package/locales/bg-BG/file.json +2 -1
- package/locales/de-DE/file.json +2 -1
- package/locales/en-US/file.json +2 -1
- package/locales/es-ES/file.json +2 -1
- package/locales/fr-FR/file.json +2 -1
- package/locales/it-IT/file.json +2 -1
- package/locales/ja-JP/file.json +2 -1
- package/locales/ko-KR/file.json +2 -1
- package/locales/nl-NL/file.json +2 -1
- package/locales/pl-PL/file.json +2 -1
- package/locales/pt-BR/file.json +2 -1
- package/locales/ru-RU/file.json +2 -1
- package/locales/tr-TR/file.json +2 -1
- package/locales/vi-VN/file.json +2 -1
- package/locales/zh-CN/file.json +2 -1
- package/locales/zh-TW/file.json +2 -1
- package/package.json +1 -1
- package/src/app/(main)/settings/llm/ProviderList/providers.tsx +2 -0
- package/src/app/api/chat/agentRuntime.ts +7 -0
- package/src/components/FileParsingStatus/index.tsx +0 -2
- package/src/config/llm.ts +6 -0
- package/src/config/modelProviders/index.ts +4 -0
- package/src/config/modelProviders/moonshot.ts +6 -6
- package/src/config/modelProviders/upstage.ts +45 -0
- package/src/config/modelProviders/zeroone.ts +30 -29
- package/src/config/modelProviders/zhipu.ts +8 -8
- package/src/const/settings/llm.ts +5 -0
- package/src/const/url.ts +3 -0
- package/src/features/Conversation/Error/APIKeyForm/ProviderAvatar.tsx +5 -0
- package/src/features/FileViewer/NotSupport/index.tsx +15 -4
- package/src/features/FileViewer/Renderer/Image/index.tsx +36 -0
- package/src/features/FileViewer/Renderer/MSDoc/index.tsx +65 -0
- package/src/features/FileViewer/Renderer/index.ts +5 -0
- package/src/features/FileViewer/index.tsx +14 -14
- package/src/libs/agent-runtime/AgentRuntime.ts +7 -0
- package/src/libs/agent-runtime/types/type.ts +1 -0
- package/src/libs/agent-runtime/upstage/index.test.ts +255 -0
- package/src/libs/agent-runtime/upstage/index.ts +10 -0
- package/src/locales/default/file.ts +2 -1
- package/src/server/globalConfig/index.ts +3 -0
- package/src/types/user/settings/keyVaults.ts +1 -0
- /package/src/features/FileViewer/{PDFViewer → Renderer/PDF}/HighlightLayer.tsx +0 -0
- /package/src/features/FileViewer/{PDFViewer → Renderer/PDF}/index.tsx +0 -0
- /package/src/features/FileViewer/{PDFViewer → Renderer/PDF}/style.ts +0 -0
- /package/src/features/FileViewer/{PDFViewer → Renderer/PDF}/useResizeObserver.ts +0 -0
- /package/src/features/FileViewer/{TXTViewer → Renderer/TXT}/index.tsx +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,57 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 1.15.0](https://github.com/lobehub/lobe-chat/compare/v1.14.12...v1.15.0)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-08-30**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **misc**: Add Upstage model provider support.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **misc**: Add Upstage model provider support, closes [#3670](https://github.com/lobehub/lobe-chat/issues/3670) ([4b8591b](https://github.com/lobehub/lobe-chat/commit/4b8591b))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 1.14.12](https://github.com/lobehub/lobe-chat/compare/v1.14.11...v1.14.12)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2024-08-30**</sup>
|
|
33
|
+
|
|
34
|
+
#### 💄 Styles
|
|
35
|
+
|
|
36
|
+
- **misc**: Fix ms doc file preview, Update the sorting of each provider model.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Styles
|
|
44
|
+
|
|
45
|
+
- **misc**: Fix ms doc file preview, closes [#3686](https://github.com/lobehub/lobe-chat/issues/3686) ([2cd78cf](https://github.com/lobehub/lobe-chat/commit/2cd78cf))
|
|
46
|
+
- **misc**: Update the sorting of each provider model, closes [#3688](https://github.com/lobehub/lobe-chat/issues/3688) ([2630bbc](https://github.com/lobehub/lobe-chat/commit/2630bbc))
|
|
47
|
+
|
|
48
|
+
</details>
|
|
49
|
+
|
|
50
|
+
<div align="right">
|
|
51
|
+
|
|
52
|
+
[](#readme-top)
|
|
53
|
+
|
|
54
|
+
</div>
|
|
55
|
+
|
|
5
56
|
### [Version 1.14.11](https://github.com/lobehub/lobe-chat/compare/v1.14.10...v1.14.11)
|
|
6
57
|
|
|
7
58
|
<sup>Released on **2024-08-30**</sup>
|
package/Dockerfile
CHANGED
package/Dockerfile.database
CHANGED
package/locales/ar/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "الوضع الحالي للنشر لا يدعم إدارة الملفات"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "تحميل الملف",
|
|
60
|
+
"unsupportedFileAndContact": "هذا التنسيق من الملفات غير مدعوم للمعاينة عبر الإنترنت، إذا كان لديك طلب للمعاينة، فلا تتردد في <1>إبلاغنا</1>"
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "بحث عن ملف",
|
|
62
63
|
"tab": {
|
package/locales/bg-BG/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "Текущият режим на инсталация не поддържа управление на файлове"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "Изтеглете файла",
|
|
60
|
+
"unsupportedFileAndContact": "Този формат на файла не поддържа онлайн преглед. Ако имате нужда от преглед, моля, <1>свържете се с нас</1>."
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "Търсене на файл",
|
|
62
63
|
"tab": {
|
package/locales/de-DE/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "Der aktuelle Bereitstellungsmodus unterstützt keine Dateiverwaltung"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "Datei herunterladen",
|
|
60
|
+
"unsupportedFileAndContact": "Dieses Dateiformat wird derzeit nicht für die Online-Vorschau unterstützt. Wenn Sie eine Vorschau wünschen, können Sie uns gerne <1>Feedback geben</1>."
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "Datei suchen",
|
|
62
63
|
"tab": {
|
package/locales/en-US/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "The current deployment mode does not support file management"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "Download File",
|
|
60
|
+
"unsupportedFileAndContact": "This file format is not currently supported for online preview. If you have a request for previewing, feel free to <1>contact us</1>."
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "Search Files",
|
|
62
63
|
"tab": {
|
package/locales/es-ES/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "El modo de despliegue actual no soporta la gestión de archivos"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "Descargar archivo",
|
|
60
|
+
"unsupportedFileAndContact": "Este formato de archivo no es compatible con la vista previa en línea. Si desea solicitar una vista previa, no dude en <1>contactarnos</1>."
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "Buscar archivo",
|
|
62
63
|
"tab": {
|
package/locales/fr-FR/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "Le mode de déploiement actuel ne prend pas en charge la gestion des fichiers"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "Télécharger le fichier",
|
|
60
|
+
"unsupportedFileAndContact": "Ce format de fichier n'est pas encore pris en charge pour l'aperçu en ligne. Si vous souhaitez un aperçu, n'hésitez pas à <1>nous contacter</1>."
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "Rechercher un fichier",
|
|
62
63
|
"tab": {
|
package/locales/it-IT/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "La modalità di distribuzione attuale non supporta la gestione dei file"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "Scarica file",
|
|
60
|
+
"unsupportedFileAndContact": "Questo formato di file non è attualmente supportato per la visualizzazione online. Se hai bisogno di una visualizzazione, ti preghiamo di <1>contattarci</1>."
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "Cerca file",
|
|
62
63
|
"tab": {
|
package/locales/ja-JP/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "現在のデプロイメントモードはファイル管理をサポートしていません"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "ファイルをダウンロード",
|
|
60
|
+
"unsupportedFileAndContact": "このファイル形式はオンラインプレビューをサポートしていません。プレビューのリクエストがある場合は、ぜひ<1>ご連絡ください</1>。"
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "ファイルを検索",
|
|
62
63
|
"tab": {
|
package/locales/ko-KR/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "현재 배포 모드는 파일 관리를 지원하지 않습니다."
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "파일 다운로드",
|
|
60
|
+
"unsupportedFileAndContact": "이 파일 형식은 온라인 미리보기를 지원하지 않습니다. 미리보기가 필요하신 경우, <1>저희에게 피드백을 주시기 바랍니다</1>."
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "파일 검색",
|
|
62
63
|
"tab": {
|
package/locales/nl-NL/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "De huidige implementatiemodus ondersteunt geen bestandsbeheer"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "Bestand downloaden",
|
|
60
|
+
"unsupportedFileAndContact": "Dit bestandsformaat wordt momenteel niet ondersteund voor online preview. Als u een preview wilt, neem dan gerust <1>contact met ons op</1>."
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "Zoek bestand",
|
|
62
63
|
"tab": {
|
package/locales/pl-PL/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "Obecny tryb wdrożenia nie obsługuje zarządzania plikami"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "Pobierz plik",
|
|
60
|
+
"unsupportedFileAndContact": "Ten format pliku nie jest obecnie obsługiwany w podglądzie online. Jeśli chcesz uzyskać podgląd, zachęcamy do <1>skontaktowania się z nami</1>."
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "Szukaj pliku",
|
|
62
63
|
"tab": {
|
package/locales/pt-BR/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "O modo de implantação atual não suporta gerenciamento de arquivos"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "Baixar arquivo",
|
|
60
|
+
"unsupportedFileAndContact": "Este formato de arquivo não é suportado para visualização online. Se você tiver interesse em visualizar, sinta-se à vontade para <1>nos enviar um feedback</1>."
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "Pesquisar arquivo",
|
|
62
63
|
"tab": {
|
package/locales/ru-RU/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "Текущий режим развертывания не поддерживает управление файлами"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "Скачать файл",
|
|
60
|
+
"unsupportedFileAndContact": "Этот формат файла в настоящее время не поддерживает онлайн-просмотр. Если у вас есть запрос на просмотр, пожалуйста, <1>сообщите нам</1>."
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "Поиск файла",
|
|
62
63
|
"tab": {
|
package/locales/tr-TR/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "Mevcut dağıtım modu dosya yönetimini desteklemiyor"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "Dosyayı İndir",
|
|
60
|
+
"unsupportedFileAndContact": "Bu dosya formatı çevrimiçi önizleme için desteklenmiyor. Önizleme talebiniz varsa, lütfen <1>bize geri bildirimde bulunun</1>."
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "Dosya Ara",
|
|
62
63
|
"tab": {
|
package/locales/vi-VN/file.json
CHANGED
|
@@ -56,7 +56,8 @@
|
|
|
56
56
|
"title": "Chế độ triển khai hiện tại không hỗ trợ quản lý tệp"
|
|
57
57
|
},
|
|
58
58
|
"preview": {
|
|
59
|
-
"
|
|
59
|
+
"downloadFile": "Tải tệp",
|
|
60
|
+
"unsupportedFileAndContact": "Định dạng tệp này hiện không hỗ trợ xem trước trực tuyến. Nếu bạn có yêu cầu xem trước, vui lòng <1>phản hồi cho chúng tôi</1>"
|
|
60
61
|
},
|
|
61
62
|
"searchFilePlaceholder": "Tìm kiếm tệp",
|
|
62
63
|
"tab": {
|
package/locales/zh-CN/file.json
CHANGED
package/locales/zh-TW/file.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
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",
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
StepfunProviderCard,
|
|
19
19
|
TaichuProviderCard,
|
|
20
20
|
TogetherAIProviderCard,
|
|
21
|
+
UpstageProviderCard,
|
|
21
22
|
ZeroOneProviderCard,
|
|
22
23
|
ZhiPuProviderCard,
|
|
23
24
|
} from '@/config/modelProviders';
|
|
@@ -59,6 +60,7 @@ export const useProviderList = (): ProviderItem[] => {
|
|
|
59
60
|
TaichuProviderCard,
|
|
60
61
|
Ai360ProviderCard,
|
|
61
62
|
SiliconCloudProviderCard,
|
|
63
|
+
UpstageProviderCard,
|
|
62
64
|
],
|
|
63
65
|
[AzureProvider, OllamaProvider, OpenAIProvider, BedrockProvider],
|
|
64
66
|
);
|
|
@@ -208,6 +208,13 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
|
|
|
208
208
|
|
|
209
209
|
return { apiKey, baseURL };
|
|
210
210
|
}
|
|
211
|
+
case ModelProvider.Upstage: {
|
|
212
|
+
const { UPSTAGE_API_KEY } = getLLMConfig();
|
|
213
|
+
|
|
214
|
+
const apiKey = apiKeyManager.pick(payload?.apiKey || UPSTAGE_API_KEY);
|
|
215
|
+
|
|
216
|
+
return { apiKey };
|
|
217
|
+
}
|
|
211
218
|
}
|
|
212
219
|
};
|
|
213
220
|
|
|
@@ -104,8 +104,6 @@ const FileParsingStatus = memo<FileParsingStatusProps>(
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
case AsyncTaskStatus.Success: {
|
|
107
|
-
console.log(embeddingStatus);
|
|
108
|
-
|
|
109
107
|
// if no embedding status, it means that the embedding is not started
|
|
110
108
|
if (!embeddingStatus || preparingEmbedding)
|
|
111
109
|
return (
|
package/src/config/llm.ts
CHANGED
|
@@ -93,6 +93,9 @@ export const getLLMConfig = () => {
|
|
|
93
93
|
SILICONCLOUD_API_KEY: z.string().optional(),
|
|
94
94
|
SILICONCLOUD_MODEL_LIST: z.string().optional(),
|
|
95
95
|
SILICONCLOUD_PROXY_URL: z.string().optional(),
|
|
96
|
+
|
|
97
|
+
ENABLED_UPSTAGE: z.boolean(),
|
|
98
|
+
UPSTAGE_API_KEY: z.string().optional(),
|
|
96
99
|
},
|
|
97
100
|
runtimeEnv: {
|
|
98
101
|
API_KEY_SELECT_MODE: process.env.API_KEY_SELECT_MODE,
|
|
@@ -183,6 +186,9 @@ export const getLLMConfig = () => {
|
|
|
183
186
|
SILICONCLOUD_API_KEY: process.env.SILICONCLOUD_API_KEY,
|
|
184
187
|
SILICONCLOUD_MODEL_LIST: process.env.SILICONCLOUD_MODEL_LIST,
|
|
185
188
|
SILICONCLOUD_PROXY_URL: process.env.SILICONCLOUD_PROXY_URL,
|
|
189
|
+
|
|
190
|
+
ENABLED_UPSTAGE: !!process.env.UPSTAGE_API_KEY,
|
|
191
|
+
UPSTAGE_API_KEY: process.env.UPSTAGE_API_KEY,
|
|
186
192
|
},
|
|
187
193
|
});
|
|
188
194
|
};
|
|
@@ -21,6 +21,7 @@ import SiliconCloudProvider from './siliconcloud';
|
|
|
21
21
|
import StepfunProvider from './stepfun';
|
|
22
22
|
import TaichuProvider from './taichu';
|
|
23
23
|
import TogetherAIProvider from './togetherai';
|
|
24
|
+
import UpstageProvider from './upstage';
|
|
24
25
|
import ZeroOneProvider from './zeroone';
|
|
25
26
|
import ZhiPuProvider from './zhipu';
|
|
26
27
|
|
|
@@ -47,6 +48,7 @@ export const LOBE_DEFAULT_MODEL_LIST: ChatModelCard[] = [
|
|
|
47
48
|
TaichuProvider.chatModels,
|
|
48
49
|
Ai360Provider.chatModels,
|
|
49
50
|
SiliconCloudProvider.chatModels,
|
|
51
|
+
UpstageProvider.chatModels,
|
|
50
52
|
].flat();
|
|
51
53
|
|
|
52
54
|
export const DEFAULT_MODEL_PROVIDER_LIST = [
|
|
@@ -73,6 +75,7 @@ export const DEFAULT_MODEL_PROVIDER_LIST = [
|
|
|
73
75
|
TaichuProvider,
|
|
74
76
|
Ai360Provider,
|
|
75
77
|
SiliconCloudProvider,
|
|
78
|
+
UpstageProvider,
|
|
76
79
|
];
|
|
77
80
|
|
|
78
81
|
export const filterEnabledModels = (provider: ModelProviderCard) => {
|
|
@@ -105,5 +108,6 @@ export { default as SiliconCloudProviderCard } from './siliconcloud';
|
|
|
105
108
|
export { default as StepfunProviderCard } from './stepfun';
|
|
106
109
|
export { default as TaichuProviderCard } from './taichu';
|
|
107
110
|
export { default as TogetherAIProviderCard } from './togetherai';
|
|
111
|
+
export { default as UpstageProviderCard } from './upstage';
|
|
108
112
|
export { default as ZeroOneProviderCard } from './zeroone';
|
|
109
113
|
export { default as ZhiPuProviderCard } from './zhipu';
|
|
@@ -4,11 +4,11 @@ import { ModelProviderCard } from '@/types/llm';
|
|
|
4
4
|
const Moonshot: ModelProviderCard = {
|
|
5
5
|
chatModels: [
|
|
6
6
|
{
|
|
7
|
-
displayName: 'Moonshot V1
|
|
7
|
+
displayName: 'Moonshot V1 128K',
|
|
8
8
|
enabled: true,
|
|
9
9
|
functionCall: true,
|
|
10
|
-
id: 'moonshot-v1-
|
|
11
|
-
tokens:
|
|
10
|
+
id: 'moonshot-v1-128k',
|
|
11
|
+
tokens: 128_000,
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
displayName: 'Moonshot V1 32K',
|
|
@@ -18,11 +18,11 @@ const Moonshot: ModelProviderCard = {
|
|
|
18
18
|
tokens: 32_768,
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
|
-
displayName: 'Moonshot V1
|
|
21
|
+
displayName: 'Moonshot V1 8K',
|
|
22
22
|
enabled: true,
|
|
23
23
|
functionCall: true,
|
|
24
|
-
id: 'moonshot-v1-
|
|
25
|
-
tokens:
|
|
24
|
+
id: 'moonshot-v1-8k',
|
|
25
|
+
tokens: 8192,
|
|
26
26
|
},
|
|
27
27
|
],
|
|
28
28
|
checkModel: 'moonshot-v1-8k',
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { ModelProviderCard } from '@/types/llm';
|
|
2
|
+
|
|
3
|
+
// ref https://developers.upstage.ai/docs/getting-started/models
|
|
4
|
+
const Upstage: ModelProviderCard = {
|
|
5
|
+
chatModels: [
|
|
6
|
+
{
|
|
7
|
+
description: 'A compact LLM offering superior performance to GPT-3.5, with robust multilingual capabilities for both English and Korean, delivering high efficiency in a smaller package. solar-1-mini-chat is alias for our latest solar-1-mini-chat model. (Currently solar-1-mini-chat-240612)',
|
|
8
|
+
displayName: 'Solar 1 Mini Chat',
|
|
9
|
+
enabled: true,
|
|
10
|
+
functionCall: true,
|
|
11
|
+
id: 'solar-1-mini-chat',
|
|
12
|
+
tokens: 32_768,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
description: 'A compact LLM that extends the capabilities of solar-mini-chat with specialization in Japanese, while maintaining high efficiency and performance in English and Korean. solar-1-mini-chat-ja is alias for our latest solar-1-mini-chat-ja model.(Currently solar-1-mini-chat-ja-240612)',
|
|
16
|
+
displayName: 'Solar 1 Mini Chat Ja',
|
|
17
|
+
enabled: true,
|
|
18
|
+
functionCall: false,
|
|
19
|
+
id: 'solar-1-mini-chat-ja',
|
|
20
|
+
tokens: 32_768,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
description: 'English-to-Korean translation specialized model based on the solar-mini. Maximum context length is 32k tokens. solar-1-mini-translate-enko is alias for our latest solar-1-mini-translate-enko model. (Currently solar-1-mini-translate-enko-240507)',
|
|
24
|
+
displayName: 'Solar 1 Mini Translate EnKo',
|
|
25
|
+
enabled: false,
|
|
26
|
+
functionCall: false,
|
|
27
|
+
id: 'solar-1-mini-translate-enko',
|
|
28
|
+
tokens: 32_768,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
description: 'Korean-to-English translation specialized model based on the solar-mini. Maximum context length is 32k tokens. solar-1-mini-translate-koen is alias for our latest solar-1-mini-translate-koen model. (Currently solar-1-mini-translate-koen-240507)',
|
|
32
|
+
displayName: 'Solar 1 Mini Translate KoEn',
|
|
33
|
+
enabled: false,
|
|
34
|
+
functionCall: false,
|
|
35
|
+
id: 'solar-1-mini-translate-koen',
|
|
36
|
+
tokens: 32_768,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
checkModel: 'solar-1-mini-chat',
|
|
40
|
+
id: 'upstage',
|
|
41
|
+
modelList: { showModelFetcher: true },
|
|
42
|
+
name: 'Upstage',
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default Upstage;
|
|
@@ -11,23 +11,39 @@ const ZeroOne: ModelProviderCard = {
|
|
|
11
11
|
tokens: 32_768,
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
|
-
description:
|
|
15
|
-
|
|
14
|
+
description:
|
|
15
|
+
'在 yi-large 模型的基础上支持并强化了工具调用的能力,适用于各种需要搭建 agent 或 workflow 的业务场景。',
|
|
16
|
+
displayName: 'Yi Large FC',
|
|
16
17
|
enabled: true,
|
|
17
|
-
|
|
18
|
+
functionCall: true,
|
|
19
|
+
id: 'yi-large-fc',
|
|
20
|
+
tokens: 32_768,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
description:
|
|
24
|
+
'基于 yi-large 超强模型的高阶服务,结合检索与生成技术提供精准答案,实时全网检索信息服务。',
|
|
25
|
+
displayName: 'Yi Large RAG',
|
|
26
|
+
enabled: true,
|
|
27
|
+
id: 'yi-large-rag',
|
|
18
28
|
tokens: 16_384,
|
|
19
29
|
},
|
|
20
30
|
{
|
|
21
|
-
description: '
|
|
22
|
-
displayName: 'Yi
|
|
31
|
+
description: '超高性价比、卓越性能。根据性能和推理速度、成本,进行平衡性高精度调优。',
|
|
32
|
+
displayName: 'Yi Large Turbo',
|
|
23
33
|
enabled: true,
|
|
24
|
-
id: 'yi-
|
|
34
|
+
id: 'yi-large-turbo',
|
|
35
|
+
tokens: 16_384,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
description: '中型尺寸模型升级微调,能力均衡,性价比高。深度优化指令遵循能力。',
|
|
39
|
+
displayName: 'Yi Medium',
|
|
40
|
+
enabled: true,
|
|
41
|
+
id: 'yi-medium',
|
|
25
42
|
tokens: 16_384,
|
|
26
|
-
vision: true,
|
|
27
43
|
},
|
|
28
44
|
{
|
|
29
45
|
description: '200K 超长上下文窗口,提供长文本深度理解和生成能力。',
|
|
30
|
-
displayName: 'Yi 200K',
|
|
46
|
+
displayName: 'Yi Medium 200K',
|
|
31
47
|
enabled: true,
|
|
32
48
|
id: 'yi-medium-200k',
|
|
33
49
|
tokens: 200_000,
|
|
@@ -35,32 +51,17 @@ const ZeroOne: ModelProviderCard = {
|
|
|
35
51
|
{
|
|
36
52
|
description: '小而精悍,轻量极速模型。提供强化数学运算和代码编写能力。',
|
|
37
53
|
displayName: 'Yi Spark',
|
|
38
|
-
id: 'yi-spark',
|
|
39
|
-
tokens: 16_384,
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
description:
|
|
43
|
-
'基于 yi-large 超强模型的高阶服务,结合检索与生成技术提供精准答案,实时全网检索信息服务。',
|
|
44
|
-
displayName: 'Yi Large RAG',
|
|
45
54
|
enabled: true,
|
|
46
|
-
id: 'yi-
|
|
55
|
+
id: 'yi-spark',
|
|
47
56
|
tokens: 16_384,
|
|
48
57
|
},
|
|
49
58
|
{
|
|
50
|
-
description:
|
|
51
|
-
|
|
52
|
-
displayName: 'Yi Large FC',
|
|
53
|
-
enabled: true,
|
|
54
|
-
functionCall: true,
|
|
55
|
-
id: 'yi-large-fc',
|
|
56
|
-
tokens: 32_768,
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
description: '超高性价比、卓越性能。根据性能和推理速度、成本,进行平衡性高精度调优。',
|
|
60
|
-
displayName: 'Yi Large Turbo',
|
|
59
|
+
description: '复杂视觉任务模型,提供高性能图片理解、分析能力。',
|
|
60
|
+
displayName: 'Yi Vision',
|
|
61
61
|
enabled: true,
|
|
62
|
-
id: 'yi-
|
|
62
|
+
id: 'yi-vision',
|
|
63
63
|
tokens: 16_384,
|
|
64
|
+
vision: true,
|
|
64
65
|
},
|
|
65
66
|
{
|
|
66
67
|
description: '初期版本,推荐使用 yi-large(新版本)',
|
|
@@ -69,7 +70,7 @@ const ZeroOne: ModelProviderCard = {
|
|
|
69
70
|
tokens: 16_384,
|
|
70
71
|
},
|
|
71
72
|
],
|
|
72
|
-
checkModel: 'yi-
|
|
73
|
+
checkModel: 'yi-spark',
|
|
73
74
|
id: 'zeroone',
|
|
74
75
|
name: '01.AI',
|
|
75
76
|
};
|
|
@@ -5,14 +5,6 @@ import { ModelProviderCard } from '@/types/llm';
|
|
|
5
5
|
// ref https://open.bigmodel.cn/modelcenter/square
|
|
6
6
|
const ZhiPu: ModelProviderCard = {
|
|
7
7
|
chatModels: [
|
|
8
|
-
{
|
|
9
|
-
description: '超长输入:专为处理超长文本和记忆型任务设计',
|
|
10
|
-
displayName: 'GLM-4-Long',
|
|
11
|
-
enabled: true,
|
|
12
|
-
functionCall: true,
|
|
13
|
-
id: 'glm-4-long',
|
|
14
|
-
tokens: 1_024_000,
|
|
15
|
-
},
|
|
16
8
|
{
|
|
17
9
|
description:
|
|
18
10
|
'GLM-4-AllTools 是专门为支持智能体和相关任务而进一步优化的模型版本。它能够自主理解用户的意图,规划复杂的指令,并能够调用一个或多个工具(例如网络浏览器、代码解释器和文本生图像)以完成复杂的任务。',
|
|
@@ -60,6 +52,14 @@ const ZhiPu: ModelProviderCard = {
|
|
|
60
52
|
id: 'glm-4-airx',
|
|
61
53
|
tokens: 8192,
|
|
62
54
|
},
|
|
55
|
+
{
|
|
56
|
+
description: '超长输入:专为处理超长文本和记忆型任务设计',
|
|
57
|
+
displayName: 'GLM-4-Long',
|
|
58
|
+
enabled: true,
|
|
59
|
+
functionCall: true,
|
|
60
|
+
id: 'glm-4-long',
|
|
61
|
+
tokens: 1_024_000,
|
|
62
|
+
},
|
|
63
63
|
{
|
|
64
64
|
description: '适用简单任务,速度最快,价格最实惠的版本',
|
|
65
65
|
displayName: 'GLM-4-Flash',
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
StepfunProviderCard,
|
|
20
20
|
TaichuProviderCard,
|
|
21
21
|
TogetherAIProviderCard,
|
|
22
|
+
UpstageProviderCard,
|
|
22
23
|
ZeroOneProviderCard,
|
|
23
24
|
ZhiPuProviderCard,
|
|
24
25
|
filterEnabledModels,
|
|
@@ -111,6 +112,10 @@ export const DEFAULT_LLM_CONFIG: UserModelProviderConfig = {
|
|
|
111
112
|
enabled: false,
|
|
112
113
|
enabledModels: filterEnabledModels(TogetherAIProviderCard),
|
|
113
114
|
},
|
|
115
|
+
upstage: {
|
|
116
|
+
enabled: false,
|
|
117
|
+
enabledModels: filterEnabledModels(UpstageProviderCard),
|
|
118
|
+
},
|
|
114
119
|
zeroone: {
|
|
115
120
|
enabled: false,
|
|
116
121
|
enabledModels: filterEnabledModels(ZeroOneProviderCard),
|
package/src/const/url.ts
CHANGED
|
@@ -47,6 +47,9 @@ export const PLUGINS_INDEX_URL = 'https://chat-plugins.lobehub.com';
|
|
|
47
47
|
export const MORE_MODEL_PROVIDER_REQUEST_URL =
|
|
48
48
|
'https://github.com/lobehub/lobe-chat/discussions/1284';
|
|
49
49
|
|
|
50
|
+
export const MORE_FILE_PREVIEW_REQUEST_URL =
|
|
51
|
+
'https://github.com/lobehub/lobe-chat/discussions/3684';
|
|
52
|
+
|
|
50
53
|
export const AGENTS_INDEX_GITHUB = 'https://github.com/lobehub/lobe-chat-agents';
|
|
51
54
|
export const AGENTS_INDEX_GITHUB_ISSUE = urlJoin(AGENTS_INDEX_GITHUB, 'issues/new');
|
|
52
55
|
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
Stepfun,
|
|
17
17
|
Together,
|
|
18
18
|
Tongyi,
|
|
19
|
+
Upstage,
|
|
19
20
|
ZeroOne,
|
|
20
21
|
Zhipu,
|
|
21
22
|
} from '@lobehub/icons';
|
|
@@ -103,6 +104,10 @@ const ProviderAvatar = memo<ProviderAvatarProps>(({ provider }) => {
|
|
|
103
104
|
return <Ai360 color={Ai360.colorPrimary} size={56} />;
|
|
104
105
|
}
|
|
105
106
|
|
|
107
|
+
case ModelProvider.Upstage: {
|
|
108
|
+
return <Upstage color={Upstage.colorPrimary} size={56} />;
|
|
109
|
+
}
|
|
110
|
+
|
|
106
111
|
default:
|
|
107
112
|
case ModelProvider.OpenAI: {
|
|
108
113
|
return <OpenAI color={theme.colorText} size={64} />;
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { IDocument } from '@cyntler/react-doc-viewer';
|
|
2
|
+
import { FluentEmoji } from '@lobehub/ui';
|
|
2
3
|
import { Button } from 'antd';
|
|
3
4
|
import { createStyles } from 'antd-style';
|
|
5
|
+
import Link from 'next/link';
|
|
4
6
|
import React, { ComponentType, useState } from 'react';
|
|
5
|
-
import { useTranslation } from 'react-i18next';
|
|
7
|
+
import { Trans, useTranslation } from 'react-i18next';
|
|
6
8
|
import { Center, Flexbox } from 'react-layout-kit';
|
|
7
9
|
|
|
10
|
+
import { MORE_FILE_PREVIEW_REQUEST_URL } from '@/const/url';
|
|
8
11
|
import { downloadFile } from '@/utils/client/downloadFile';
|
|
9
12
|
|
|
10
13
|
const useStyles = createStyles(({ css, token }) => ({
|
|
@@ -25,7 +28,7 @@ const NotSupport: ComponentType<{
|
|
|
25
28
|
}> = ({ fileName, document: doc }) => {
|
|
26
29
|
const { styles } = useStyles();
|
|
27
30
|
|
|
28
|
-
const { t } = useTranslation(
|
|
31
|
+
const { t } = useTranslation('file');
|
|
29
32
|
|
|
30
33
|
const [loading, setLoading] = useState(false);
|
|
31
34
|
|
|
@@ -33,7 +36,15 @@ const NotSupport: ComponentType<{
|
|
|
33
36
|
<Flexbox className={styles.page} id="txt-renderer">
|
|
34
37
|
<Center height={'100%'}>
|
|
35
38
|
<Flexbox align={'center'} gap={12}>
|
|
36
|
-
{
|
|
39
|
+
<FluentEmoji emoji={'👀'} size={64} />
|
|
40
|
+
<Flexbox style={{ textAlign: 'center' }}>
|
|
41
|
+
<Trans i18nKey="preview.unsupportedFileAndContact" ns={'file'}>
|
|
42
|
+
此文件格式暂不支持在线预览,如有预览诉求,欢迎
|
|
43
|
+
<Link aria-label={'todo'} href={MORE_FILE_PREVIEW_REQUEST_URL} target="_blank">
|
|
44
|
+
反馈给我们
|
|
45
|
+
</Link>
|
|
46
|
+
</Trans>
|
|
47
|
+
</Flexbox>
|
|
37
48
|
<Button
|
|
38
49
|
loading={loading}
|
|
39
50
|
onClick={async () => {
|
|
@@ -43,7 +54,7 @@ const NotSupport: ComponentType<{
|
|
|
43
54
|
setLoading(false);
|
|
44
55
|
}}
|
|
45
56
|
>
|
|
46
|
-
{t('
|
|
57
|
+
{t('preview.downloadFile')}
|
|
47
58
|
</Button>
|
|
48
59
|
</Flexbox>
|
|
49
60
|
</Center>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DocRenderer } from '@cyntler/react-doc-viewer';
|
|
2
|
+
import { Center } from 'react-layout-kit';
|
|
3
|
+
|
|
4
|
+
const ImageRenderer: DocRenderer = ({ mainState: { currentDocument } }) => {
|
|
5
|
+
const { uri, fileName } = currentDocument || {};
|
|
6
|
+
|
|
7
|
+
return (
|
|
8
|
+
<Center height={'100%'} width={'100%'}>
|
|
9
|
+
<img
|
|
10
|
+
alt={fileName}
|
|
11
|
+
height={'100%'}
|
|
12
|
+
src={uri}
|
|
13
|
+
style={{ objectFit: 'contain', overflow: 'hidden' }}
|
|
14
|
+
width={'100%'}
|
|
15
|
+
/>
|
|
16
|
+
</Center>
|
|
17
|
+
);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export default ImageRenderer;
|
|
21
|
+
|
|
22
|
+
ImageRenderer.fileTypes = [
|
|
23
|
+
'jpg',
|
|
24
|
+
'jpeg',
|
|
25
|
+
'image/jpg',
|
|
26
|
+
'image/jpeg',
|
|
27
|
+
'png',
|
|
28
|
+
'image/png',
|
|
29
|
+
'webp',
|
|
30
|
+
'image/webp',
|
|
31
|
+
'gif',
|
|
32
|
+
'image/gif',
|
|
33
|
+
'bmp',
|
|
34
|
+
'image/bmp',
|
|
35
|
+
];
|
|
36
|
+
ImageRenderer.weight = 0;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { DocRenderer } from '@cyntler/react-doc-viewer';
|
|
2
|
+
import { css, cx } from 'antd-style';
|
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
|
4
|
+
|
|
5
|
+
const container = css`
|
|
6
|
+
position: relative;
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
border-radius: 4px;
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
const content = css`
|
|
12
|
+
position: absolute;
|
|
13
|
+
inset-block: -1px -1px;
|
|
14
|
+
inset-inline-start: -1px;
|
|
15
|
+
|
|
16
|
+
width: calc(100% + 2px);
|
|
17
|
+
height: calc(100% + 2px);
|
|
18
|
+
|
|
19
|
+
border: 0;
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
const MSDocRenderer: DocRenderer = ({ mainState: { currentDocument } }) => {
|
|
23
|
+
if (!currentDocument) return null;
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<Flexbox className={cx(container)} height={'100%'} id="msdoc-renderer" width={'100%'}>
|
|
27
|
+
<iframe
|
|
28
|
+
className={cx(content)}
|
|
29
|
+
id="msdoc-iframe"
|
|
30
|
+
src={`https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(
|
|
31
|
+
currentDocument.uri,
|
|
32
|
+
)}`}
|
|
33
|
+
title="msdoc-iframe"
|
|
34
|
+
/>
|
|
35
|
+
</Flexbox>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default MSDocRenderer;
|
|
40
|
+
|
|
41
|
+
const MSDocFTMaps = {
|
|
42
|
+
doc: ['doc', 'application/msword'],
|
|
43
|
+
docx: [
|
|
44
|
+
'docx',
|
|
45
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
46
|
+
'application/octet-stream',
|
|
47
|
+
],
|
|
48
|
+
odt: ['odt', 'application/vnd.oasis.opendocument.text'],
|
|
49
|
+
ppt: ['ppt', 'application/vnd.ms-powerpoint'],
|
|
50
|
+
pptx: ['pptx', 'application/vnd.openxmlformats-officedocument.presentationml.presentation'],
|
|
51
|
+
xls: ['xls', 'application/vnd.ms-excel'],
|
|
52
|
+
xlsx: ['xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'],
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
MSDocRenderer.fileTypes = [
|
|
56
|
+
...MSDocFTMaps.odt,
|
|
57
|
+
...MSDocFTMaps.doc,
|
|
58
|
+
...MSDocFTMaps.docx,
|
|
59
|
+
...MSDocFTMaps.xls,
|
|
60
|
+
...MSDocFTMaps.xlsx,
|
|
61
|
+
...MSDocFTMaps.ppt,
|
|
62
|
+
...MSDocFTMaps.pptx,
|
|
63
|
+
];
|
|
64
|
+
MSDocRenderer.weight = 0;
|
|
65
|
+
MSDocRenderer.fileLoader = ({ fileLoaderComplete }) => fileLoaderComplete();
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import DocViewer
|
|
4
|
-
import {
|
|
3
|
+
import DocViewer from '@cyntler/react-doc-viewer';
|
|
4
|
+
import { css, cx } from 'antd-style';
|
|
5
5
|
import { CSSProperties, memo } from 'react';
|
|
6
6
|
|
|
7
7
|
import { FileListItem } from '@/types/files';
|
|
8
8
|
|
|
9
9
|
import NotSupport from './NotSupport';
|
|
10
|
-
import
|
|
11
|
-
import
|
|
10
|
+
import { FileViewRenderers } from './Renderer';
|
|
11
|
+
import PDFRenderer from './Renderer/PDF';
|
|
12
12
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
13
|
+
const container = css`
|
|
14
|
+
background: transparent !important;
|
|
15
|
+
|
|
16
|
+
#proxy-renderer {
|
|
17
|
+
height: 100%;
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
19
20
|
|
|
20
21
|
interface FileViewerProps extends FileListItem {
|
|
21
22
|
className?: string;
|
|
@@ -23,20 +24,19 @@ interface FileViewerProps extends FileListItem {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
const FileViewer = memo<FileViewerProps>(({ id, style, fileType, url, name }) => {
|
|
26
|
-
const { styles } = useStyles();
|
|
27
27
|
if (fileType === 'pdf' || name.endsWith('.pdf')) {
|
|
28
|
-
return <
|
|
28
|
+
return <PDFRenderer fileId={id} url={url} />;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
return (
|
|
32
32
|
<DocViewer
|
|
33
|
-
className={
|
|
33
|
+
className={cx(container)}
|
|
34
34
|
config={{
|
|
35
35
|
header: { disableHeader: true },
|
|
36
36
|
noRenderer: { overrideComponent: NotSupport },
|
|
37
37
|
}}
|
|
38
38
|
documents={[{ fileName: name, fileType, uri: url }]}
|
|
39
|
-
pluginRenderers={
|
|
39
|
+
pluginRenderers={FileViewRenderers}
|
|
40
40
|
style={style}
|
|
41
41
|
/>
|
|
42
42
|
);
|
|
@@ -24,6 +24,7 @@ import { LobeSiliconCloudAI } from './siliconcloud';
|
|
|
24
24
|
import { LobeStepfunAI } from './stepfun';
|
|
25
25
|
import { LobeTaichuAI } from './taichu';
|
|
26
26
|
import { LobeTogetherAI } from './togetherai';
|
|
27
|
+
import { LobeUpstageAI } from './upstage';
|
|
27
28
|
import {
|
|
28
29
|
ChatCompetitionOptions,
|
|
29
30
|
ChatStreamPayload,
|
|
@@ -134,6 +135,7 @@ class AgentRuntime {
|
|
|
134
135
|
stepfun: Partial<ClientOptions>;
|
|
135
136
|
taichu: Partial<ClientOptions>;
|
|
136
137
|
togetherai: Partial<ClientOptions>;
|
|
138
|
+
upstage: Partial<ClientOptions>;
|
|
137
139
|
zeroone: Partial<ClientOptions>;
|
|
138
140
|
zhipu: Partial<ClientOptions>;
|
|
139
141
|
}>,
|
|
@@ -261,6 +263,11 @@ class AgentRuntime {
|
|
|
261
263
|
runtimeModel = new LobeSiliconCloudAI(params.siliconcloud ?? {});
|
|
262
264
|
break;
|
|
263
265
|
}
|
|
266
|
+
|
|
267
|
+
case ModelProvider.Upstage: {
|
|
268
|
+
runtimeModel = new LobeUpstageAI(params.upstage);
|
|
269
|
+
break
|
|
270
|
+
}
|
|
264
271
|
}
|
|
265
272
|
|
|
266
273
|
return new AgentRuntime(runtimeModel);
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
import OpenAI from 'openai';
|
|
3
|
+
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
ChatStreamCallbacks,
|
|
7
|
+
LobeOpenAICompatibleRuntime,
|
|
8
|
+
ModelProvider,
|
|
9
|
+
} from '@/libs/agent-runtime';
|
|
10
|
+
|
|
11
|
+
import * as debugStreamModule from '../utils/debugStream';
|
|
12
|
+
import { LobeUpstageAI } from './index';
|
|
13
|
+
|
|
14
|
+
const provider = ModelProvider.Upstage;
|
|
15
|
+
const defaultBaseURL = 'https://api.upstage.ai/v1/solar';
|
|
16
|
+
|
|
17
|
+
const bizErrorType = 'ProviderBizError';
|
|
18
|
+
const invalidErrorType = 'InvalidProviderAPIKey';
|
|
19
|
+
|
|
20
|
+
// Mock the console.error to avoid polluting test output
|
|
21
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
22
|
+
|
|
23
|
+
let instance: LobeOpenAICompatibleRuntime;
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
instance = new LobeUpstageAI({ apiKey: 'test' });
|
|
27
|
+
|
|
28
|
+
// 使用 vi.spyOn 来模拟 chat.completions.create 方法
|
|
29
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(
|
|
30
|
+
new ReadableStream() as any,
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
vi.clearAllMocks();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('LobeUpstageAI', () => {
|
|
39
|
+
describe('init', () => {
|
|
40
|
+
it('should correctly initialize with an API key', async () => {
|
|
41
|
+
const instance = new LobeUpstageAI({ apiKey: 'test_api_key' });
|
|
42
|
+
expect(instance).toBeInstanceOf(LobeUpstageAI);
|
|
43
|
+
expect(instance.baseURL).toEqual(defaultBaseURL);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('chat', () => {
|
|
48
|
+
describe('Error', () => {
|
|
49
|
+
it('should return OpenAIBizError with an openai error response when OpenAI.APIError is thrown', async () => {
|
|
50
|
+
// Arrange
|
|
51
|
+
const apiError = new OpenAI.APIError(
|
|
52
|
+
400,
|
|
53
|
+
{
|
|
54
|
+
status: 400,
|
|
55
|
+
error: {
|
|
56
|
+
message: 'Bad Request',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
'Error message',
|
|
60
|
+
{},
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
|
|
64
|
+
|
|
65
|
+
// Act
|
|
66
|
+
try {
|
|
67
|
+
await instance.chat({
|
|
68
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
69
|
+
model: 'solar-1-mini-chat',
|
|
70
|
+
temperature: 0,
|
|
71
|
+
});
|
|
72
|
+
} catch (e) {
|
|
73
|
+
expect(e).toEqual({
|
|
74
|
+
endpoint: defaultBaseURL,
|
|
75
|
+
error: {
|
|
76
|
+
error: { message: 'Bad Request' },
|
|
77
|
+
status: 400,
|
|
78
|
+
},
|
|
79
|
+
errorType: bizErrorType,
|
|
80
|
+
provider,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should throw AgentRuntimeError with NoOpenAIAPIKey if no apiKey is provided', async () => {
|
|
86
|
+
try {
|
|
87
|
+
new LobeUpstageAI({});
|
|
88
|
+
} catch (e) {
|
|
89
|
+
expect(e).toEqual({ errorType: invalidErrorType });
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should return OpenAIBizError with the cause when OpenAI.APIError is thrown with cause', async () => {
|
|
94
|
+
// Arrange
|
|
95
|
+
const errorInfo = {
|
|
96
|
+
stack: 'abc',
|
|
97
|
+
cause: {
|
|
98
|
+
message: 'api is undefined',
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});
|
|
102
|
+
|
|
103
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
|
|
104
|
+
|
|
105
|
+
// Act
|
|
106
|
+
try {
|
|
107
|
+
await instance.chat({
|
|
108
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
109
|
+
model: 'solar-1-mini-chat',
|
|
110
|
+
temperature: 0,
|
|
111
|
+
});
|
|
112
|
+
} catch (e) {
|
|
113
|
+
expect(e).toEqual({
|
|
114
|
+
endpoint: defaultBaseURL,
|
|
115
|
+
error: {
|
|
116
|
+
cause: { message: 'api is undefined' },
|
|
117
|
+
stack: 'abc',
|
|
118
|
+
},
|
|
119
|
+
errorType: bizErrorType,
|
|
120
|
+
provider,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should return OpenAIBizError with an cause response with desensitize Url', async () => {
|
|
126
|
+
// Arrange
|
|
127
|
+
const errorInfo = {
|
|
128
|
+
stack: 'abc',
|
|
129
|
+
cause: { message: 'api is undefined' },
|
|
130
|
+
};
|
|
131
|
+
const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});
|
|
132
|
+
|
|
133
|
+
instance = new LobeUpstageAI({
|
|
134
|
+
apiKey: 'test',
|
|
135
|
+
|
|
136
|
+
baseURL: 'https://api.abc.com/v1',
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
|
|
140
|
+
|
|
141
|
+
// Act
|
|
142
|
+
try {
|
|
143
|
+
await instance.chat({
|
|
144
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
145
|
+
model: 'solar-1-mini-chat',
|
|
146
|
+
temperature: 0,
|
|
147
|
+
});
|
|
148
|
+
} catch (e) {
|
|
149
|
+
expect(e).toEqual({
|
|
150
|
+
endpoint: 'https://api.***.com/v1',
|
|
151
|
+
error: {
|
|
152
|
+
cause: { message: 'api is undefined' },
|
|
153
|
+
stack: 'abc',
|
|
154
|
+
},
|
|
155
|
+
errorType: bizErrorType,
|
|
156
|
+
provider,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should throw an InvalidUpstageAPIKey error type on 401 status code', async () => {
|
|
162
|
+
// Mock the API call to simulate a 401 error
|
|
163
|
+
const error = new Error('Unauthorized') as any;
|
|
164
|
+
error.status = 401;
|
|
165
|
+
vi.mocked(instance['client'].chat.completions.create).mockRejectedValue(error);
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
await instance.chat({
|
|
169
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
170
|
+
model: 'solar-1-mini-chat',
|
|
171
|
+
temperature: 0,
|
|
172
|
+
});
|
|
173
|
+
} catch (e) {
|
|
174
|
+
// Expect the chat method to throw an error with InvalidUpstageAPIKey
|
|
175
|
+
expect(e).toEqual({
|
|
176
|
+
endpoint: defaultBaseURL,
|
|
177
|
+
error: new Error('Unauthorized'),
|
|
178
|
+
errorType: invalidErrorType,
|
|
179
|
+
provider,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should return AgentRuntimeError for non-OpenAI errors', async () => {
|
|
185
|
+
// Arrange
|
|
186
|
+
const genericError = new Error('Generic Error');
|
|
187
|
+
|
|
188
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(genericError);
|
|
189
|
+
|
|
190
|
+
// Act
|
|
191
|
+
try {
|
|
192
|
+
await instance.chat({
|
|
193
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
194
|
+
model: 'solar-1-mini-chat',
|
|
195
|
+
temperature: 0,
|
|
196
|
+
});
|
|
197
|
+
} catch (e) {
|
|
198
|
+
expect(e).toEqual({
|
|
199
|
+
endpoint: defaultBaseURL,
|
|
200
|
+
errorType: 'AgentRuntimeError',
|
|
201
|
+
provider,
|
|
202
|
+
error: {
|
|
203
|
+
name: genericError.name,
|
|
204
|
+
cause: genericError.cause,
|
|
205
|
+
message: genericError.message,
|
|
206
|
+
stack: genericError.stack,
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe('DEBUG', () => {
|
|
214
|
+
it('should call debugStream and return StreamingTextResponse when DEBUG_UPSTAGE_CHAT_COMPLETION is 1', async () => {
|
|
215
|
+
// Arrange
|
|
216
|
+
const mockProdStream = new ReadableStream() as any; // 模拟的 prod 流
|
|
217
|
+
const mockDebugStream = new ReadableStream({
|
|
218
|
+
start(controller) {
|
|
219
|
+
controller.enqueue('Debug stream content');
|
|
220
|
+
controller.close();
|
|
221
|
+
},
|
|
222
|
+
}) as any;
|
|
223
|
+
mockDebugStream.toReadableStream = () => mockDebugStream; // 添加 toReadableStream 方法
|
|
224
|
+
|
|
225
|
+
// 模拟 chat.completions.create 返回值,包括模拟的 tee 方法
|
|
226
|
+
(instance['client'].chat.completions.create as Mock).mockResolvedValue({
|
|
227
|
+
tee: () => [mockProdStream, { toReadableStream: () => mockDebugStream }],
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// 保存原始环境变量值
|
|
231
|
+
const originalDebugValue = process.env.DEBUG_UPSTAGE_CHAT_COMPLETION;
|
|
232
|
+
|
|
233
|
+
// 模拟环境变量
|
|
234
|
+
process.env.DEBUG_UPSTAGE_CHAT_COMPLETION = '1';
|
|
235
|
+
vi.spyOn(debugStreamModule, 'debugStream').mockImplementation(() => Promise.resolve());
|
|
236
|
+
|
|
237
|
+
// 执行测试
|
|
238
|
+
// 运行你的测试函数,确保它会在条件满足时调用 debugStream
|
|
239
|
+
// 假设的测试函数调用,你可能需要根据实际情况调整
|
|
240
|
+
await instance.chat({
|
|
241
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
242
|
+
model: 'solar-1-mini-chat',
|
|
243
|
+
stream: true,
|
|
244
|
+
temperature: 0,
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// 验证 debugStream 被调用
|
|
248
|
+
expect(debugStreamModule.debugStream).toHaveBeenCalled();
|
|
249
|
+
|
|
250
|
+
// 恢复原始环境变量值
|
|
251
|
+
process.env.DEBUG_UPSTAGE_CHAT_COMPLETION = originalDebugValue;
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ModelProvider } from '../types';
|
|
2
|
+
import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory';
|
|
3
|
+
|
|
4
|
+
export const LobeUpstageAI = LobeOpenAICompatibleFactory({
|
|
5
|
+
baseURL: 'https://api.upstage.ai/v1/solar',
|
|
6
|
+
debug: {
|
|
7
|
+
chatCompletion: () => process.env.DEBUG_UPSTAGE_CHAT_COMPLETION === '1',
|
|
8
|
+
},
|
|
9
|
+
provider: ModelProvider.Upstage,
|
|
10
|
+
});
|
|
@@ -47,6 +47,8 @@ export const getServerGlobalConfig = () => {
|
|
|
47
47
|
ENABLED_SILICONCLOUD,
|
|
48
48
|
SILICONCLOUD_MODEL_LIST,
|
|
49
49
|
|
|
50
|
+
ENABLED_UPSTAGE,
|
|
51
|
+
|
|
50
52
|
ENABLED_AZURE_OPENAI,
|
|
51
53
|
AZURE_MODEL_LIST,
|
|
52
54
|
|
|
@@ -138,6 +140,7 @@ export const getServerGlobalConfig = () => {
|
|
|
138
140
|
modelString: TOGETHERAI_MODEL_LIST,
|
|
139
141
|
}),
|
|
140
142
|
},
|
|
143
|
+
upstage: { enabled: ENABLED_UPSTAGE },
|
|
141
144
|
zeroone: { enabled: ENABLED_ZEROONE },
|
|
142
145
|
zhipu: {
|
|
143
146
|
enabled: ENABLED_ZHIPU,
|
|
@@ -39,6 +39,7 @@ export interface UserKeyVaults {
|
|
|
39
39
|
stepfun?: OpenAICompatibleKeyVault;
|
|
40
40
|
taichu?: OpenAICompatibleKeyVault;
|
|
41
41
|
togetherai?: OpenAICompatibleKeyVault;
|
|
42
|
+
upstage?: OpenAICompatibleKeyVault;
|
|
42
43
|
zeroone?: OpenAICompatibleKeyVault;
|
|
43
44
|
zhipu?: OpenAICompatibleKeyVault;
|
|
44
45
|
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|