@lobehub/chat 1.6.6 → 1.6.8
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 +50 -0
- package/README.md +2 -1
- package/README.zh-CN.md +1 -1
- package/docs/usage/providers/novita.mdx +80 -0
- package/docs/usage/providers/novita.zh-CN.mdx +76 -0
- package/package.json +1 -1
- package/src/app/(main)/settings/llm/ProviderList/providers.tsx +9 -2
- package/src/app/api/chat/agentRuntime.ts +7 -0
- package/src/components/ModelProviderIcon/index.tsx +5 -0
- package/src/config/llm.ts +6 -0
- package/src/config/modelProviders/index.ts +4 -0
- package/src/config/modelProviders/novita.ts +91 -0
- package/src/const/settings/llm.ts +5 -0
- package/src/database/server/models/__tests__/user.test.ts +1 -1
- package/src/database/server/models/user.ts +1 -1
- package/src/features/Conversation/Error/APIKeyForm/ProviderAvatar.tsx +4 -0
- package/src/libs/agent-runtime/AgentRuntime.ts +8 -1
- package/src/libs/agent-runtime/novita/index.test.ts +251 -0
- package/src/libs/agent-runtime/novita/index.ts +15 -0
- package/src/libs/agent-runtime/types/type.ts +1 -0
- package/src/server/globalConfig/index.ts +2 -0
- package/src/server/routers/edge/config/__snapshots__/index.test.ts.snap +12 -6
- package/src/server/routers/edge/config/index.test.ts +1 -1
- package/src/server/routers/edge/upload.ts +1 -1
- package/src/server/routers/lambda/importer.ts +15 -10
- package/src/server/{modules/DataImporter → services/dataImporter}/__tests__/index.test.ts +3 -3
- package/src/server/{modules/DataImporter → services/dataImporter}/index.ts +1 -1
- package/src/types/user/settings/keyVaults.ts +1 -0
- package/vitest.config.ts +1 -1
- /package/src/server/{keyVaultsEncrypt → modules/KeyVaultsEncrypt}/index.test.ts +0 -0
- /package/src/server/{keyVaultsEncrypt → modules/KeyVaultsEncrypt}/index.ts +0 -0
- /package/src/server/{files/s3.ts → modules/S3/index.ts} +0 -0
- /package/src/server/{modules/DataImporter → services/dataImporter}/__tests__/fixtures/messages.json +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 1.6.8](https://github.com/lobehub/lobe-chat/compare/v1.6.7...v1.6.8)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-07-23**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **misc**: Move server modules.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Code refactoring
|
|
19
|
+
|
|
20
|
+
- **misc**: Move server modules, closes [#3291](https://github.com/lobehub/lobe-chat/issues/3291) ([c7c9f39](https://github.com/lobehub/lobe-chat/commit/c7c9f39))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 1.6.7](https://github.com/lobehub/lobe-chat/compare/v1.6.6...v1.6.7)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2024-07-23**</sup>
|
|
33
|
+
|
|
34
|
+
#### 💄 Styles
|
|
35
|
+
|
|
36
|
+
- **misc**: Add new model provider Novita AI.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Styles
|
|
44
|
+
|
|
45
|
+
- **misc**: Add new model provider Novita AI, closes [#3177](https://github.com/lobehub/lobe-chat/issues/3177) ([08b063f](https://github.com/lobehub/lobe-chat/commit/08b063f))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 1.6.6](https://github.com/lobehub/lobe-chat/compare/v1.6.5...v1.6.6)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2024-07-22**</sup>
|
package/README.md
CHANGED
|
@@ -134,6 +134,7 @@ We have implemented support for the following model service providers:
|
|
|
134
134
|
- **Minimax**: Integrated the Minimax models, including the MoE model **abab6**, offers a broader range of choices. [Learn more](https://www.minimaxi.com/)
|
|
135
135
|
- **DeepSeek**: Integrated with the DeepSeek series models, an innovative AI startup from China, The product has been designed to provide a model that balances performance with price. [Learn more](https://www.deepseek.com/)
|
|
136
136
|
- **Qwen**: Integrated the Qwen series models, including the latest **qwen-turbo**, **qwen-plus** and **qwen-max**. [Lean more](https://help.aliyun.com/zh/dashscope/developer-reference/model-introduction)
|
|
137
|
+
- **Novita AI**: Access **Llama**, **Mistral**, and other leading open-source models at cheapest prices. Engage in uncensored role-play, spark creative discussions, and foster unrestricted innovation. **Pay For What You Use.** [Learn more](https://novita.ai/llm-api?utm_source=lobechat&utm_medium=ch&utm_campaign=api)
|
|
137
138
|
|
|
138
139
|
At the same time, we are also planning to support more model service providers, such as Replicate and Perplexity, to further enrich our service provider library. If you would like LobeChat to support your favorite service provider, feel free to join our [community discussion](https://github.com/lobehub/lobe-chat/discussions/1284).
|
|
139
140
|
|
|
@@ -272,7 +273,7 @@ Our marketplace is not just a showcase platform but also a collaborative space.
|
|
|
272
273
|
| [Convert SQL Table Structure to Dao and Mapper](https://chat-preview.lobehub.com/market?agent=my-batis-generator)<br/><sup>By **[MeYoung](https://github.com/MeYoung)** on **2024-07-17**</sup> | Generate entity class and MyBatis Mapper based on a table structure<br/>`sql` `sql` `mybatis` |
|
|
273
274
|
| [Auto Extraction Data](https://chat-preview.lobehub.com/market?agent=the-20-autoextract)<br/><sup>By **[vkhoilq](https://github.com/vkhoilq)** on **2024-07-17**</sup> | The20 Auto Extraction Data<br/>`the-20` `autoextract` |
|
|
274
275
|
|
|
275
|
-
> 📊 Total agents: [<kbd>**
|
|
276
|
+
> 📊 Total agents: [<kbd>**302**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
276
277
|
|
|
277
278
|
<!-- AGENT LIST -->
|
|
278
279
|
|
package/README.zh-CN.md
CHANGED
|
@@ -261,7 +261,7 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
|
|
|
261
261
|
| [SQL 表结构转 Dao 和 Mapper](https://chat-preview.lobehub.com/market?agent=my-batis-generator)<br/><sup>By **[MeYoung](https://github.com/MeYoung)** on **2024-07-17**</sup> | 给与一个表结构,生成表的实体和 MyBatis 的 Mapper<br/>`sql` `sql` `mybatis` |
|
|
262
262
|
| [自动提取数据](https://chat-preview.lobehub.com/market?agent=the-20-autoextract)<br/><sup>By **[vkhoilq](https://github.com/vkhoilq)** on **2024-07-17**</sup> | The20 自动提取数据<br/>`the-20` `autoextract` |
|
|
263
263
|
|
|
264
|
-
> 📊 Total agents: [<kbd>**
|
|
264
|
+
> 📊 Total agents: [<kbd>**302**</kbd> ](https://github.com/lobehub/lobe-chat-agents)
|
|
265
265
|
|
|
266
266
|
<!-- AGENT LIST -->
|
|
267
267
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Using Novita AI API Key in LobeChat
|
|
3
|
+
description: >-
|
|
4
|
+
Learn how to integrate Novita AI's language model APIs into LobeChat. Follow the steps to register, create an Novita AI API key,
|
|
5
|
+
configure settings, and chat with our various AI models.
|
|
6
|
+
|
|
7
|
+
tags:
|
|
8
|
+
- Novita AI
|
|
9
|
+
- Llama3
|
|
10
|
+
- Mistral
|
|
11
|
+
- uncensored
|
|
12
|
+
- API key
|
|
13
|
+
- Web UI
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Using Novita AI in LobeChat
|
|
17
|
+
|
|
18
|
+
<Image
|
|
19
|
+
alt={'Using Novita AI in LobeChat'}
|
|
20
|
+
cover
|
|
21
|
+
src={'https://github.com/user-attachments/assets/b2b36128-6a43-4a1f-9c08-99fe73fb565f'}
|
|
22
|
+
/>
|
|
23
|
+
|
|
24
|
+
[Novita AI](https://novita.ai/) is an AI API platform that provides a variety of LLM and image generation APIs, supporting Llama3 (8B, 70B), Mistral, and many other cutting-edge models. We offer a variety of censored and uncensored models to meet your different needs.
|
|
25
|
+
|
|
26
|
+
This document will guide you on how to integrate Novita AI in LobeChat:
|
|
27
|
+
|
|
28
|
+
<Steps>
|
|
29
|
+
|
|
30
|
+
### Step 1: Register and Log in to Novita AI
|
|
31
|
+
|
|
32
|
+
- Visit [Novita.ai](https://novita.ai/) and create an account
|
|
33
|
+
- You can log in with your Google or Github account
|
|
34
|
+
- Upon registration, Novita AI will provide a $0.5 credit.
|
|
35
|
+
|
|
36
|
+
<Image
|
|
37
|
+
alt={'Register OpenRouter'}
|
|
38
|
+
height={457}
|
|
39
|
+
inStep
|
|
40
|
+
src={'https://github.com/user-attachments/assets/f3177ce2-281c-4ed4-a061-239547b466c6'}
|
|
41
|
+
/>
|
|
42
|
+
|
|
43
|
+
### Step 2: Obtain the API Key
|
|
44
|
+
|
|
45
|
+
- Visit Novita AI's [key management page](https://novita.ai/dashboard/key), create and copy an API Key.
|
|
46
|
+
|
|
47
|
+
<Image
|
|
48
|
+
alt={'Obtain Novita AI API key'}
|
|
49
|
+
inStep
|
|
50
|
+
src={'https://github.com/user-attachments/assets/1e33aff2-6186-4e1f-80a8-4a2c855d8cc1'}
|
|
51
|
+
/>
|
|
52
|
+
|
|
53
|
+
### Step 3: Configure Novita AI in LobeChat
|
|
54
|
+
|
|
55
|
+
- Visit the `Settings` interface in LobeChat
|
|
56
|
+
- Find the setting for `novita.ai` under `Language Model`
|
|
57
|
+
|
|
58
|
+
<Image
|
|
59
|
+
alt={'Enter Novita AI API key in LobeChat'}
|
|
60
|
+
inStep
|
|
61
|
+
src={'https://github.com/user-attachments/assets/00c02637-873e-4e7e-9dc3-a95085b16dd7'}
|
|
62
|
+
/>
|
|
63
|
+
|
|
64
|
+
- Open novita.ai and enter the obtained API key
|
|
65
|
+
- Choose a Novita AI model for your assistant to start the conversation
|
|
66
|
+
|
|
67
|
+
<Image
|
|
68
|
+
alt={'Select and use Novita AI model'}
|
|
69
|
+
inStep
|
|
70
|
+
src={'https://github.com/user-attachments/assets/6f9f400a-72e0-49de-94cb-5069fddf1163'}
|
|
71
|
+
/>
|
|
72
|
+
|
|
73
|
+
<Callout type={'warning'}>
|
|
74
|
+
During usage, you may need to pay the API service provider, please refer to Novita AI's pricing
|
|
75
|
+
policy.
|
|
76
|
+
</Callout>
|
|
77
|
+
|
|
78
|
+
</Steps>
|
|
79
|
+
|
|
80
|
+
You can now engage in conversations using the models provided by Novita AI in LobeChat.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 在 LobeChat 中使用 Novita AI API Key
|
|
3
|
+
description: 学习如何将 Novita AI 的大语言模型 API 集成到 LobeChat 中。跟随以下步骤注册 Novita AI 账号、创建 API Key、充值信用额度并在 LobeChat 中进行设置。并与我们的多种 AI 模型交谈。
|
|
4
|
+
tags:
|
|
5
|
+
- Novita AI
|
|
6
|
+
- Llama3
|
|
7
|
+
- Mistral
|
|
8
|
+
- uncensored
|
|
9
|
+
- API key
|
|
10
|
+
- Web UI
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# 在 LobeChat 中使用 Novita AI
|
|
14
|
+
|
|
15
|
+
<Image
|
|
16
|
+
alt={'在 LobeChat 中使用 Novita AI'}
|
|
17
|
+
cover
|
|
18
|
+
src={'https://github.com/user-attachments/assets/b2b36128-6a43-4a1f-9c08-99fe73fb565f'}
|
|
19
|
+
/>
|
|
20
|
+
|
|
21
|
+
[Novita AI](https://novita.ai/) 是一个 AI API 平台,它提供多种大语言模型与 AI 图像生成的 API 服务。支持 Llama3 (8B, 70B),Mistral 和其他最新的模型。
|
|
22
|
+
|
|
23
|
+
本文档将指导你如何在 LobeChat 中使用 Novita AI:
|
|
24
|
+
|
|
25
|
+
<Steps>
|
|
26
|
+
|
|
27
|
+
### 步骤一:注册 Novita AI 账号并登录
|
|
28
|
+
|
|
29
|
+
- 访问 [Novita.ai](https://novita.ai/) 并创建账号
|
|
30
|
+
- 你可以使用 Google 或者 Github 账号登录
|
|
31
|
+
- 注册后,Novita AI 会赠送 0.5 美元的使用额度
|
|
32
|
+
|
|
33
|
+
<Image
|
|
34
|
+
alt={'注册 Novita AI'}
|
|
35
|
+
height={457}
|
|
36
|
+
inStep
|
|
37
|
+
src={'https://github.com/user-attachments/assets/f3177ce2-281c-4ed4-a061-239547b466c6'}
|
|
38
|
+
/>
|
|
39
|
+
|
|
40
|
+
### 步骤二:创建 API 密钥
|
|
41
|
+
|
|
42
|
+
- 访问 Novita AI 的 [密钥管理页面](https://novita.ai/dashboard/key) ,创建并且复制一个 API 密钥.
|
|
43
|
+
|
|
44
|
+
<Image
|
|
45
|
+
alt={'创建 Novita AI API 密钥'}
|
|
46
|
+
inStep
|
|
47
|
+
src={'https://github.com/user-attachments/assets/1e33aff2-6186-4e1f-80a8-4a2c855d8cc1'}
|
|
48
|
+
/>
|
|
49
|
+
|
|
50
|
+
### 步骤三:在 LobeChat 中配置 Novita AI
|
|
51
|
+
|
|
52
|
+
- 访问 LobeChat 的 `设置` 界面
|
|
53
|
+
- 在 `语言模型` 下找到 `novita.ai` 的设置项
|
|
54
|
+
- 打开 novita.ai 并填入获得的 API 密钥
|
|
55
|
+
|
|
56
|
+
<Image
|
|
57
|
+
alt={'在 LobeChat 中输入 Novita AI API 密钥'}
|
|
58
|
+
inStep
|
|
59
|
+
src={'https://github.com/user-attachments/assets/00c02637-873e-4e7e-9dc3-a95085b16dd7'}
|
|
60
|
+
/>
|
|
61
|
+
|
|
62
|
+
- 为你的助手选择一个 Novita AI 模型即可开始对话
|
|
63
|
+
|
|
64
|
+
<Image
|
|
65
|
+
alt={'Select and use Novita AI model'}
|
|
66
|
+
inStep
|
|
67
|
+
src={'https://github.com/user-attachments/assets/6f9f400a-72e0-49de-94cb-5069fddf1163'}
|
|
68
|
+
/>
|
|
69
|
+
|
|
70
|
+
<Callout type={'warning'}>
|
|
71
|
+
在使用过程中你可能需要向 API 服务提供商付费,请参考 Novita AI 的相关费用政策。
|
|
72
|
+
</Callout>
|
|
73
|
+
|
|
74
|
+
</Steps>
|
|
75
|
+
|
|
76
|
+
至此你已经可以在 LobeChat 中使用 Novita AI 提供的模型进行对话了。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.8",
|
|
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",
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
Minimax,
|
|
12
12
|
Mistral,
|
|
13
13
|
Moonshot,
|
|
14
|
+
Novita,
|
|
14
15
|
OpenRouter,
|
|
15
16
|
Perplexity,
|
|
16
17
|
Stepfun,
|
|
@@ -35,6 +36,7 @@ import {
|
|
|
35
36
|
MinimaxProviderCard,
|
|
36
37
|
MistralProviderCard,
|
|
37
38
|
MoonshotProviderCard,
|
|
39
|
+
NovitaProviderCard,
|
|
38
40
|
OpenRouterProviderCard,
|
|
39
41
|
PerplexityProviderCard,
|
|
40
42
|
QwenProviderCard,
|
|
@@ -126,6 +128,11 @@ export const useProviderList = (): ProviderItem[] => {
|
|
|
126
128
|
docUrl: urlJoin(BASE_DOC_URL, 'openrouter'),
|
|
127
129
|
title: <OpenRouter.Combine iconProps={{ color: OpenRouter.colorPrimary }} size={20} />,
|
|
128
130
|
},
|
|
131
|
+
{
|
|
132
|
+
...NovitaProviderCard,
|
|
133
|
+
docUrl: urlJoin(BASE_DOC_URL, 'novita'),
|
|
134
|
+
title: <Novita.Combine size={20} type={'color'} />,
|
|
135
|
+
},
|
|
129
136
|
{
|
|
130
137
|
...TogetherAIProviderCard,
|
|
131
138
|
docUrl: urlJoin(BASE_DOC_URL, 'togetherai'),
|
|
@@ -179,12 +186,12 @@ export const useProviderList = (): ProviderItem[] => {
|
|
|
179
186
|
{
|
|
180
187
|
...BaichuanProviderCard,
|
|
181
188
|
docUrl: urlJoin(BASE_DOC_URL, 'baichuan'),
|
|
182
|
-
title: <Baichuan.Combine size={
|
|
189
|
+
title: <Baichuan.Combine size={20} type={'color'} />,
|
|
183
190
|
},
|
|
184
191
|
{
|
|
185
192
|
...TaichuProviderCard,
|
|
186
193
|
docUrl: urlJoin(BASE_DOC_URL, 'taichu'),
|
|
187
|
-
title: <AiMass.Combine size={
|
|
194
|
+
title: <AiMass.Combine size={28} type={'color'} />,
|
|
188
195
|
},
|
|
189
196
|
{
|
|
190
197
|
...Ai360ProviderCard,
|
|
@@ -172,6 +172,13 @@ const getLlmOptionsFromPayload = (provider: string, payload: JWTPayload) => {
|
|
|
172
172
|
|
|
173
173
|
return { apiKey };
|
|
174
174
|
}
|
|
175
|
+
case ModelProvider.Novita: {
|
|
176
|
+
const { NOVITA_API_KEY } = getLLMConfig();
|
|
177
|
+
|
|
178
|
+
const apiKey = apiKeyManager.pick(payload?.apiKey || NOVITA_API_KEY);
|
|
179
|
+
|
|
180
|
+
return { apiKey };
|
|
181
|
+
}
|
|
175
182
|
case ModelProvider.Baichuan: {
|
|
176
183
|
const { BAICHUAN_API_KEY } = getLLMConfig();
|
|
177
184
|
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
Minimax,
|
|
13
13
|
Mistral,
|
|
14
14
|
Moonshot,
|
|
15
|
+
Novita,
|
|
15
16
|
Ollama,
|
|
16
17
|
OpenAI,
|
|
17
18
|
OpenRouter,
|
|
@@ -117,6 +118,10 @@ const ModelProviderIcon = memo<ModelProviderIconProps>(({ provider }) => {
|
|
|
117
118
|
return <Stepfun size={20} />;
|
|
118
119
|
}
|
|
119
120
|
|
|
121
|
+
case ModelProvider.Novita: {
|
|
122
|
+
return <Novita size={20} />;
|
|
123
|
+
}
|
|
124
|
+
|
|
120
125
|
case ModelProvider.Baichuan: {
|
|
121
126
|
return <Baichuan size={20} />;
|
|
122
127
|
}
|
package/src/config/llm.ts
CHANGED
|
@@ -76,6 +76,9 @@ export const getLLMConfig = () => {
|
|
|
76
76
|
ENABLED_STEPFUN: z.boolean(),
|
|
77
77
|
STEPFUN_API_KEY: z.string().optional(),
|
|
78
78
|
|
|
79
|
+
ENABLED_NOVITA: z.boolean(),
|
|
80
|
+
NOVITA_API_KEY: z.string().optional(),
|
|
81
|
+
|
|
79
82
|
ENABLED_BAICHUAN: z.boolean(),
|
|
80
83
|
BAICHUAN_API_KEY: z.string().optional(),
|
|
81
84
|
|
|
@@ -157,6 +160,9 @@ export const getLLMConfig = () => {
|
|
|
157
160
|
ENABLED_STEPFUN: !!process.env.STEPFUN_API_KEY,
|
|
158
161
|
STEPFUN_API_KEY: process.env.STEPFUN_API_KEY,
|
|
159
162
|
|
|
163
|
+
ENABLED_NOVITA: !!process.env.NOVITA_API_KEY,
|
|
164
|
+
NOVITA_API_KEY: process.env.NOVITA_API_KEY,
|
|
165
|
+
|
|
160
166
|
ENABLED_BAICHUAN: !!process.env.BAICHUAN_API_KEY,
|
|
161
167
|
BAICHUAN_API_KEY: process.env.BAICHUAN_API_KEY,
|
|
162
168
|
|
|
@@ -11,6 +11,7 @@ import GroqProvider from './groq';
|
|
|
11
11
|
import MinimaxProvider from './minimax';
|
|
12
12
|
import MistralProvider from './mistral';
|
|
13
13
|
import MoonshotProvider from './moonshot';
|
|
14
|
+
import NovitaProvider from './novita';
|
|
14
15
|
import OllamaProvider from './ollama';
|
|
15
16
|
import OpenAIProvider from './openai';
|
|
16
17
|
import OpenRouterProvider from './openrouter';
|
|
@@ -40,6 +41,7 @@ export const LOBE_DEFAULT_MODEL_LIST: ChatModelCard[] = [
|
|
|
40
41
|
AnthropicProvider.chatModels,
|
|
41
42
|
ZeroOneProvider.chatModels,
|
|
42
43
|
StepfunProvider.chatModels,
|
|
44
|
+
NovitaProvider.chatModels,
|
|
43
45
|
BaichuanProvider.chatModels,
|
|
44
46
|
TaichuProvider.chatModels,
|
|
45
47
|
Ai360Provider.chatModels,
|
|
@@ -64,6 +66,7 @@ export const DEFAULT_MODEL_PROVIDER_LIST = [
|
|
|
64
66
|
ZeroOneProvider,
|
|
65
67
|
ZhiPuProvider,
|
|
66
68
|
StepfunProvider,
|
|
69
|
+
NovitaProvider,
|
|
67
70
|
BaichuanProvider,
|
|
68
71
|
TaichuProvider,
|
|
69
72
|
Ai360Provider,
|
|
@@ -89,6 +92,7 @@ export { default as GroqProviderCard } from './groq';
|
|
|
89
92
|
export { default as MinimaxProviderCard } from './minimax';
|
|
90
93
|
export { default as MistralProviderCard } from './mistral';
|
|
91
94
|
export { default as MoonshotProviderCard } from './moonshot';
|
|
95
|
+
export { default as NovitaProviderCard } from './novita';
|
|
92
96
|
export { default as OllamaProviderCard } from './ollama';
|
|
93
97
|
export { default as OpenAIProviderCard } from './openai';
|
|
94
98
|
export { default as OpenRouterProviderCard } from './openrouter';
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ModelProviderCard } from '@/types/llm';
|
|
2
|
+
|
|
3
|
+
const Novita: ModelProviderCard = {
|
|
4
|
+
chatModels: [
|
|
5
|
+
{
|
|
6
|
+
displayName: 'Llama3 8B Instruct',
|
|
7
|
+
enabled: true,
|
|
8
|
+
id: 'meta-llama/llama-3-8b-instruct',
|
|
9
|
+
tokens: 8192,
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
displayName: 'Llama3 70B Instruct',
|
|
13
|
+
enabled: true,
|
|
14
|
+
id: 'meta-llama/llama-3-70b-instruct',
|
|
15
|
+
tokens: 8192,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
displayName: 'Nous Hermes 2 Pro - Llama3 8B',
|
|
19
|
+
enabled: true,
|
|
20
|
+
id: 'nousresearch/hermes-2-pro-llama-3-8b',
|
|
21
|
+
tokens: 8192,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
displayName: 'Nous Hermes - Llama2 8B',
|
|
25
|
+
enabled: true,
|
|
26
|
+
id: 'nousresearch/nous-hermes-llama2-13b',
|
|
27
|
+
tokens: 4096,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
displayName: 'Mistral 7B Instruct',
|
|
31
|
+
enabled: true,
|
|
32
|
+
id: 'mistralai/mistral-7b-instruct',
|
|
33
|
+
tokens: 32_768,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
displayName: 'Dolphin Mixtral 8x22B',
|
|
37
|
+
enabled: true,
|
|
38
|
+
id: 'cognitivecomputations/dolphin-mixtral-8x22b',
|
|
39
|
+
tokens: 16_000,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
displayName: 'L3-70b-Euryale-v2.1',
|
|
43
|
+
enabled: true,
|
|
44
|
+
id: 'sao10k/l3-70b-euryale-v2.1',
|
|
45
|
+
tokens: 16_000,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
displayName: 'Midnight Rose 70B',
|
|
49
|
+
enabled: true,
|
|
50
|
+
id: 'sophosympatheia/midnight-rose-70b',
|
|
51
|
+
tokens: 4096,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
displayName: 'Mythomax L2 13b',
|
|
55
|
+
enabled: true,
|
|
56
|
+
id: 'gryphe/mythomax-l2-13b',
|
|
57
|
+
tokens: 4096,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
displayName: 'Nous Hermes 2 - Mixtral 8x7B-DPO',
|
|
61
|
+
enabled: true,
|
|
62
|
+
id: 'Nous-Hermes-2-Mixtral-8x7B-DPO',
|
|
63
|
+
tokens: 32_768,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
displayName: 'Lzlv 70b',
|
|
67
|
+
enabled: true,
|
|
68
|
+
id: 'lzlv_70b',
|
|
69
|
+
tokens: 4096,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
displayName: 'Open Hermes 2.5 Mistral 7B',
|
|
73
|
+
enabled: true,
|
|
74
|
+
id: 'teknium/openhermes-2.5-mistral-7b',
|
|
75
|
+
tokens: 4096,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
displayName: 'Wizardlm2 8x22B',
|
|
79
|
+
enabled: true,
|
|
80
|
+
id: 'microsoft/wizardlm-2-8x22b',
|
|
81
|
+
tokens: 65_535,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
checkModel: 'meta-llama/llama-3-70b-instruct',
|
|
85
|
+
disableBrowserRequest: true,
|
|
86
|
+
id: 'novita',
|
|
87
|
+
modelList: { showModelFetcher: true },
|
|
88
|
+
name: 'Novita',
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export default Novita;
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
MinimaxProviderCard,
|
|
10
10
|
MistralProviderCard,
|
|
11
11
|
MoonshotProviderCard,
|
|
12
|
+
NovitaProviderCard,
|
|
12
13
|
OllamaProviderCard,
|
|
13
14
|
OpenAIProviderCard,
|
|
14
15
|
OpenRouterProviderCard,
|
|
@@ -68,6 +69,10 @@ export const DEFAULT_LLM_CONFIG: UserModelProviderConfig = {
|
|
|
68
69
|
enabled: false,
|
|
69
70
|
enabledModels: filterEnabledModels(MoonshotProviderCard),
|
|
70
71
|
},
|
|
72
|
+
novita: {
|
|
73
|
+
enabled: false,
|
|
74
|
+
enabledModels: filterEnabledModels(NovitaProviderCard),
|
|
75
|
+
},
|
|
71
76
|
ollama: {
|
|
72
77
|
enabled: true,
|
|
73
78
|
enabledModels: filterEnabledModels(OllamaProviderCard),
|
|
@@ -3,7 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
3
3
|
|
|
4
4
|
import { INBOX_SESSION_ID } from '@/const/session';
|
|
5
5
|
import { getTestDBInstance } from '@/database/server/core/dbForTest';
|
|
6
|
-
import { KeyVaultsGateKeeper } from '@/server/
|
|
6
|
+
import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
|
|
7
7
|
import { UserPreference } from '@/types/user';
|
|
8
8
|
import { UserSettings } from '@/types/user/settings';
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ import { eq } from 'drizzle-orm';
|
|
|
3
3
|
import { DeepPartial } from 'utility-types';
|
|
4
4
|
|
|
5
5
|
import { serverDB } from '@/database/server/core/db';
|
|
6
|
-
import { KeyVaultsGateKeeper } from '@/server/
|
|
6
|
+
import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
|
|
7
7
|
import { UserPreference } from '@/types/user';
|
|
8
8
|
import { UserSettings } from '@/types/user/settings';
|
|
9
9
|
import { merge } from '@/utils/merge';
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
Minimax,
|
|
10
10
|
Mistral,
|
|
11
11
|
Moonshot,
|
|
12
|
+
Novita,
|
|
12
13
|
OpenAI,
|
|
13
14
|
OpenRouter,
|
|
14
15
|
Perplexity,
|
|
@@ -94,6 +95,9 @@ const ProviderAvatar = memo<ProviderAvatarProps>(({ provider }) => {
|
|
|
94
95
|
case ModelProvider.ZeroOne: {
|
|
95
96
|
return <ZeroOne color={ZeroOne.colorPrimary} size={56} />;
|
|
96
97
|
}
|
|
98
|
+
case ModelProvider.Novita: {
|
|
99
|
+
return <Novita color={Novita.colorPrimary} size={56} />;
|
|
100
|
+
}
|
|
97
101
|
|
|
98
102
|
case ModelProvider.Ai360: {
|
|
99
103
|
return <Ai360 color={Ai360.colorPrimary} size={56} />;
|
|
@@ -14,6 +14,7 @@ import { LobeGroq } from './groq';
|
|
|
14
14
|
import { LobeMinimaxAI } from './minimax';
|
|
15
15
|
import { LobeMistralAI } from './mistral';
|
|
16
16
|
import { LobeMoonshotAI } from './moonshot';
|
|
17
|
+
import { LobeNovitaAI } from './novita';
|
|
17
18
|
import { LobeOllamaAI } from './ollama';
|
|
18
19
|
import { LobeOpenAI } from './openai';
|
|
19
20
|
import { LobeOpenRouterAI } from './openrouter';
|
|
@@ -115,6 +116,7 @@ class AgentRuntime {
|
|
|
115
116
|
minimax: Partial<ClientOptions>;
|
|
116
117
|
mistral: Partial<ClientOptions>;
|
|
117
118
|
moonshot: Partial<ClientOptions>;
|
|
119
|
+
novita: Partial<ClientOptions>;
|
|
118
120
|
ollama: Partial<ClientOptions>;
|
|
119
121
|
openai: Partial<ClientOptions>;
|
|
120
122
|
openrouter: Partial<ClientOptions>;
|
|
@@ -226,8 +228,13 @@ class AgentRuntime {
|
|
|
226
228
|
break;
|
|
227
229
|
}
|
|
228
230
|
|
|
231
|
+
case ModelProvider.Novita: {
|
|
232
|
+
runtimeModel = new LobeNovitaAI(params.novita ?? {});
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
|
|
229
236
|
case ModelProvider.Baichuan: {
|
|
230
|
-
runtimeModel = new LobeBaichuanAI(params.baichuan);
|
|
237
|
+
runtimeModel = new LobeBaichuanAI(params.baichuan ?? {});
|
|
231
238
|
break;
|
|
232
239
|
}
|
|
233
240
|
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
// @vitest-environment node
|
|
2
|
+
import OpenAI from 'openai';
|
|
3
|
+
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { LobeOpenAICompatibleRuntime } from '@/libs/agent-runtime';
|
|
6
|
+
import { ModelProvider } from '@/libs/agent-runtime';
|
|
7
|
+
import { AgentRuntimeErrorType } from '@/libs/agent-runtime';
|
|
8
|
+
|
|
9
|
+
import * as debugStreamModule from '../utils/debugStream';
|
|
10
|
+
import { LobeNovitaAI } from './index';
|
|
11
|
+
|
|
12
|
+
const provider = ModelProvider.Novita;
|
|
13
|
+
const defaultBaseURL = 'https://api.novita.ai/v3/openai';
|
|
14
|
+
const bizErrorType = AgentRuntimeErrorType.ProviderBizError;
|
|
15
|
+
const invalidErrorType = AgentRuntimeErrorType.InvalidProviderAPIKey;
|
|
16
|
+
|
|
17
|
+
// Mock the console.error to avoid polluting test output
|
|
18
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
19
|
+
|
|
20
|
+
let instance: LobeOpenAICompatibleRuntime;
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
instance = new LobeNovitaAI({ apiKey: 'test' });
|
|
24
|
+
|
|
25
|
+
// 使用 vi.spyOn 来模拟 chat.completions.create 方法
|
|
26
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(
|
|
27
|
+
new ReadableStream() as any,
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
afterEach(() => {
|
|
32
|
+
vi.clearAllMocks();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('NovitaAI', () => {
|
|
36
|
+
describe('init', () => {
|
|
37
|
+
it('should correctly initialize with an API key', async () => {
|
|
38
|
+
const instance = new LobeNovitaAI({ apiKey: 'test_api_key' });
|
|
39
|
+
expect(instance).toBeInstanceOf(LobeNovitaAI);
|
|
40
|
+
expect(instance.baseURL).toEqual(defaultBaseURL);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('chat', () => {
|
|
45
|
+
describe('Error', () => {
|
|
46
|
+
it('should return Error with an openai error response when OpenAI.APIError is thrown', async () => {
|
|
47
|
+
// Arrange
|
|
48
|
+
const apiError = new OpenAI.APIError(
|
|
49
|
+
400,
|
|
50
|
+
{
|
|
51
|
+
status: 400,
|
|
52
|
+
error: {
|
|
53
|
+
message: 'Bad Request',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
'Error message',
|
|
57
|
+
{},
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
|
|
61
|
+
|
|
62
|
+
// Act
|
|
63
|
+
try {
|
|
64
|
+
await instance.chat({
|
|
65
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
66
|
+
model: 'meta-llama/llama-3-8b-instruct',
|
|
67
|
+
temperature: 0.999,
|
|
68
|
+
});
|
|
69
|
+
} catch (e) {
|
|
70
|
+
expect(e).toEqual({
|
|
71
|
+
endpoint: defaultBaseURL,
|
|
72
|
+
error: {
|
|
73
|
+
error: { message: 'Bad Request' },
|
|
74
|
+
status: 400,
|
|
75
|
+
},
|
|
76
|
+
errorType: bizErrorType,
|
|
77
|
+
provider,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should throw AgentRuntimeError if no apiKey is provided', async () => {
|
|
83
|
+
try {
|
|
84
|
+
new LobeNovitaAI({});
|
|
85
|
+
} catch (e) {
|
|
86
|
+
expect(e).toEqual({ errorType: invalidErrorType });
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should return Error with the cause when OpenAI.APIError is thrown with cause', async () => {
|
|
91
|
+
// Arrange
|
|
92
|
+
const errorInfo = {
|
|
93
|
+
stack: 'abc',
|
|
94
|
+
cause: {
|
|
95
|
+
message: 'api is undefined',
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});
|
|
99
|
+
|
|
100
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
|
|
101
|
+
|
|
102
|
+
// Act
|
|
103
|
+
try {
|
|
104
|
+
await instance.chat({
|
|
105
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
106
|
+
model: 'meta-llama/llama-3-8b-instruct',
|
|
107
|
+
temperature: 0.999,
|
|
108
|
+
});
|
|
109
|
+
} catch (e) {
|
|
110
|
+
expect(e).toEqual({
|
|
111
|
+
endpoint: defaultBaseURL,
|
|
112
|
+
error: {
|
|
113
|
+
cause: { message: 'api is undefined' },
|
|
114
|
+
stack: 'abc',
|
|
115
|
+
},
|
|
116
|
+
errorType: bizErrorType,
|
|
117
|
+
provider,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should return Error with an cause response with desensitize Url', async () => {
|
|
123
|
+
// Arrange
|
|
124
|
+
const errorInfo = {
|
|
125
|
+
stack: 'abc',
|
|
126
|
+
cause: { message: 'api is undefined' },
|
|
127
|
+
};
|
|
128
|
+
const apiError = new OpenAI.APIError(400, errorInfo, 'module error', {});
|
|
129
|
+
|
|
130
|
+
instance = new LobeNovitaAI({
|
|
131
|
+
apiKey: 'test',
|
|
132
|
+
|
|
133
|
+
baseURL: 'https://api.abc.com/v1',
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(apiError);
|
|
137
|
+
|
|
138
|
+
// Act
|
|
139
|
+
try {
|
|
140
|
+
await instance.chat({
|
|
141
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
142
|
+
model: 'meta-llama/llama-3-8b-instruct',
|
|
143
|
+
temperature: 0.999,
|
|
144
|
+
});
|
|
145
|
+
} catch (e) {
|
|
146
|
+
expect(e).toEqual({
|
|
147
|
+
endpoint: 'https://api.***.com/v1',
|
|
148
|
+
error: {
|
|
149
|
+
cause: { message: 'api is undefined' },
|
|
150
|
+
stack: 'abc',
|
|
151
|
+
},
|
|
152
|
+
errorType: bizErrorType,
|
|
153
|
+
provider,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should throw an error type on 401 status code', async () => {
|
|
159
|
+
// Mock the API call to simulate a 401 error
|
|
160
|
+
const error = new Error('InvalidApiKey') as any;
|
|
161
|
+
error.status = 401;
|
|
162
|
+
vi.mocked(instance['client'].chat.completions.create).mockRejectedValue(error);
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
await instance.chat({
|
|
166
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
167
|
+
model: 'meta-llama/llama-3-8b-instruct',
|
|
168
|
+
temperature: 0.999,
|
|
169
|
+
});
|
|
170
|
+
} catch (e) {
|
|
171
|
+
expect(e).toEqual({
|
|
172
|
+
endpoint: defaultBaseURL,
|
|
173
|
+
error: new Error('InvalidApiKey'),
|
|
174
|
+
errorType: invalidErrorType,
|
|
175
|
+
provider,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should return AgentRuntimeError for non-OpenAI errors', async () => {
|
|
181
|
+
// Arrange
|
|
182
|
+
const genericError = new Error('Generic Error');
|
|
183
|
+
|
|
184
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockRejectedValue(genericError);
|
|
185
|
+
|
|
186
|
+
// Act
|
|
187
|
+
try {
|
|
188
|
+
await instance.chat({
|
|
189
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
190
|
+
model: 'meta-llama/llama-3-8b-instruct',
|
|
191
|
+
temperature: 0.999,
|
|
192
|
+
});
|
|
193
|
+
} catch (e) {
|
|
194
|
+
expect(e).toEqual({
|
|
195
|
+
endpoint: defaultBaseURL,
|
|
196
|
+
errorType: 'AgentRuntimeError',
|
|
197
|
+
provider,
|
|
198
|
+
error: {
|
|
199
|
+
name: genericError.name,
|
|
200
|
+
cause: genericError.cause,
|
|
201
|
+
message: genericError.message,
|
|
202
|
+
stack: genericError.stack,
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
describe('DEBUG', () => {
|
|
210
|
+
it('should call debugStream and return StreamingTextResponse when DEBUG_NOVITA_CHAT_COMPLETION is 1', async () => {
|
|
211
|
+
// Arrange
|
|
212
|
+
const mockProdStream = new ReadableStream() as any; // 模拟的 prod 流
|
|
213
|
+
const mockDebugStream = new ReadableStream({
|
|
214
|
+
start(controller) {
|
|
215
|
+
controller.enqueue('Debug stream content');
|
|
216
|
+
controller.close();
|
|
217
|
+
},
|
|
218
|
+
}) as any;
|
|
219
|
+
mockDebugStream.toReadableStream = () => mockDebugStream; // 添加 toReadableStream 方法
|
|
220
|
+
|
|
221
|
+
// 模拟 chat.completions.create 返回值,包括模拟的 tee 方法
|
|
222
|
+
(instance['client'].chat.completions.create as Mock).mockResolvedValue({
|
|
223
|
+
tee: () => [mockProdStream, { toReadableStream: () => mockDebugStream }],
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// 保存原始环境变量值
|
|
227
|
+
const originalDebugValue = process.env.DEBUG_NOVITA_CHAT_COMPLETION;
|
|
228
|
+
|
|
229
|
+
// 模拟环境变量
|
|
230
|
+
process.env.DEBUG_NOVITA_CHAT_COMPLETION = '1';
|
|
231
|
+
vi.spyOn(debugStreamModule, 'debugStream').mockImplementation(() => Promise.resolve());
|
|
232
|
+
|
|
233
|
+
// 执行测试
|
|
234
|
+
// 运行你的测试函数,确保它会在条件满足时调用 debugStream
|
|
235
|
+
// 假设的测试函数调用,你可能需要根据实际情况调整
|
|
236
|
+
await instance.chat({
|
|
237
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
|
238
|
+
model: 'meta-llama/llama-3-8b-instruct',
|
|
239
|
+
stream: true,
|
|
240
|
+
temperature: 0.999,
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// 验证 debugStream 被调用
|
|
244
|
+
expect(debugStreamModule.debugStream).toHaveBeenCalled();
|
|
245
|
+
|
|
246
|
+
// 恢复原始环境变量值
|
|
247
|
+
process.env.DEBUG_NOVITA_CHAT_COMPLETION = originalDebugValue;
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ModelProvider } from '../types';
|
|
2
|
+
import { LobeOpenAICompatibleFactory } from '../utils/openaiCompatibleFactory';
|
|
3
|
+
|
|
4
|
+
export const LobeNovitaAI = LobeOpenAICompatibleFactory({
|
|
5
|
+
baseURL: 'https://api.novita.ai/v3/openai',
|
|
6
|
+
constructorOptions: {
|
|
7
|
+
defaultHeaders: {
|
|
8
|
+
'X-Novita-Source': 'lobechat',
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
debug: {
|
|
12
|
+
chatCompletion: () => process.env.DEBUG_NOVITA_CHAT_COMPLETION === '1',
|
|
13
|
+
},
|
|
14
|
+
provider: ModelProvider.Novita,
|
|
15
|
+
});
|
|
@@ -32,6 +32,7 @@ export const getServerGlobalConfig = () => {
|
|
|
32
32
|
ENABLED_ANTHROPIC,
|
|
33
33
|
ENABLED_MINIMAX,
|
|
34
34
|
ENABLED_MISTRAL,
|
|
35
|
+
ENABLED_NOVITA,
|
|
35
36
|
ENABLED_QWEN,
|
|
36
37
|
ENABLED_STEPFUN,
|
|
37
38
|
ENABLED_BAICHUAN,
|
|
@@ -82,6 +83,7 @@ export const getServerGlobalConfig = () => {
|
|
|
82
83
|
minimax: { enabled: ENABLED_MINIMAX },
|
|
83
84
|
mistral: { enabled: ENABLED_MISTRAL },
|
|
84
85
|
moonshot: { enabled: ENABLED_MOONSHOT },
|
|
86
|
+
novita: { enabled: ENABLED_NOVITA },
|
|
85
87
|
ollama: {
|
|
86
88
|
enabled: ENABLED_OLLAMA,
|
|
87
89
|
fetchOnClient: !OLLAMA_PROXY_URL,
|
|
@@ -93,19 +93,25 @@ exports[`configRouter > getGlobalConfig > Model Provider env > OPENROUTER_MODEL_
|
|
|
93
93
|
{
|
|
94
94
|
"enabled": false,
|
|
95
95
|
"enabledModels": [
|
|
96
|
-
"google/gemma-7b-it",
|
|
97
|
-
"mistralai/mistral-7b-instruct",
|
|
96
|
+
"google/gemma-7b-it:free",
|
|
97
|
+
"mistralai/mistral-7b-instruct:free",
|
|
98
98
|
],
|
|
99
99
|
"serverModelCards": [
|
|
100
100
|
{
|
|
101
|
-
"displayName": "
|
|
101
|
+
"displayName": "Google: Gemma 7B (free)",
|
|
102
102
|
"enabled": true,
|
|
103
|
-
"
|
|
103
|
+
"functionCall": false,
|
|
104
|
+
"id": "google/gemma-7b-it:free",
|
|
105
|
+
"tokens": 8192,
|
|
106
|
+
"vision": false,
|
|
104
107
|
},
|
|
105
108
|
{
|
|
106
|
-
"displayName": "Mistral
|
|
109
|
+
"displayName": "Mistral 7B Instruct (free)",
|
|
107
110
|
"enabled": true,
|
|
108
|
-
"
|
|
111
|
+
"functionCall": false,
|
|
112
|
+
"id": "mistralai/mistral-7b-instruct:free",
|
|
113
|
+
"tokens": 32768,
|
|
114
|
+
"vision": false,
|
|
109
115
|
},
|
|
110
116
|
],
|
|
111
117
|
}
|
|
@@ -130,7 +130,7 @@ describe('configRouter', () => {
|
|
|
130
130
|
describe('OPENROUTER_MODEL_LIST', () => {
|
|
131
131
|
it('custom deletion, addition, and renaming of models', async () => {
|
|
132
132
|
process.env.OPENROUTER_MODEL_LIST =
|
|
133
|
-
'-all,+google/gemma-7b-it,+mistralai/mistral-7b-instruct
|
|
133
|
+
'-all,+google/gemma-7b-it:free,+mistralai/mistral-7b-instruct:free';
|
|
134
134
|
|
|
135
135
|
const response = await router.getGlobalConfig();
|
|
136
136
|
|
|
@@ -2,12 +2,21 @@ import { TRPCError } from '@trpc/server';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
4
|
import { authedProcedure, router } from '@/libs/trpc';
|
|
5
|
-
import { S3 } from '@/server/
|
|
6
|
-
import {
|
|
5
|
+
import { S3 } from '@/server/modules/S3';
|
|
6
|
+
import { DataImporterService } from '@/server/services/dataImporter';
|
|
7
7
|
import { ImportResults, ImporterEntryData } from '@/types/importer';
|
|
8
8
|
|
|
9
|
+
const importProcedure = authedProcedure.use(async (opts) => {
|
|
10
|
+
const { ctx } = opts;
|
|
11
|
+
const dataImporterService = new DataImporterService(ctx.userId);
|
|
12
|
+
|
|
13
|
+
return opts.next({
|
|
14
|
+
ctx: { dataImporterService },
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
9
18
|
export const importerRouter = router({
|
|
10
|
-
importByFile:
|
|
19
|
+
importByFile: importProcedure
|
|
11
20
|
.input(z.object({ pathname: z.string() }))
|
|
12
21
|
.mutation(async ({ input, ctx }): Promise<ImportResults> => {
|
|
13
22
|
let data: ImporterEntryData | undefined;
|
|
@@ -27,12 +36,10 @@ export const importerRouter = router({
|
|
|
27
36
|
});
|
|
28
37
|
}
|
|
29
38
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return dataImporter.importData(data);
|
|
39
|
+
return ctx.dataImporterService.importData(data);
|
|
33
40
|
}),
|
|
34
41
|
|
|
35
|
-
importByPost:
|
|
42
|
+
importByPost: importProcedure
|
|
36
43
|
.input(
|
|
37
44
|
z.object({
|
|
38
45
|
data: z.object({
|
|
@@ -45,8 +52,6 @@ export const importerRouter = router({
|
|
|
45
52
|
}),
|
|
46
53
|
)
|
|
47
54
|
.mutation(async ({ input, ctx }): Promise<ImportResults> => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return dataImporter.importData(input.data);
|
|
55
|
+
return ctx.dataImporterService.importData(input.data);
|
|
51
56
|
}),
|
|
52
57
|
});
|
|
@@ -16,7 +16,7 @@ import { CURRENT_CONFIG_VERSION } from '@/migrations';
|
|
|
16
16
|
import { ImportResult } from '@/services/config';
|
|
17
17
|
import { ImporterEntryData } from '@/types/importer';
|
|
18
18
|
|
|
19
|
-
import {
|
|
19
|
+
import { DataImporterService } from '../index';
|
|
20
20
|
import mockImportData from './fixtures/messages.json';
|
|
21
21
|
|
|
22
22
|
let serverDB = await getTestDBInstance();
|
|
@@ -28,7 +28,7 @@ vi.mock('@/database/server/core/db', async () => ({
|
|
|
28
28
|
}));
|
|
29
29
|
|
|
30
30
|
const userId = 'test-user-id';
|
|
31
|
-
let importer:
|
|
31
|
+
let importer: DataImporterService;
|
|
32
32
|
|
|
33
33
|
beforeEach(async () => {
|
|
34
34
|
await serverDB.delete(users);
|
|
@@ -38,7 +38,7 @@ beforeEach(async () => {
|
|
|
38
38
|
await tx.insert(users).values({ id: userId });
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
importer = new
|
|
41
|
+
importer = new DataImporterService(userId);
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
describe('DataImporter', () => {
|
|
@@ -28,6 +28,7 @@ export interface UserKeyVaults {
|
|
|
28
28
|
minimax?: OpenAICompatibleKeyVault;
|
|
29
29
|
mistral?: OpenAICompatibleKeyVault;
|
|
30
30
|
moonshot?: OpenAICompatibleKeyVault;
|
|
31
|
+
novita?: OpenAICompatibleKeyVault;
|
|
31
32
|
ollama?: OpenAICompatibleKeyVault;
|
|
32
33
|
openai?: OpenAICompatibleKeyVault;
|
|
33
34
|
openrouter?: OpenAICompatibleKeyVault;
|
package/vitest.config.ts
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/src/server/{modules/DataImporter → services/dataImporter}/__tests__/fixtures/messages.json
RENAMED
|
File without changes
|