plugin-ai-api 1.0.2 → 1.0.4
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/README.md +15 -1
- package/client-v2.d.ts +2 -0
- package/client-v2.js +1 -0
- package/dist/client/778.180aac1b13a38702.js +10 -0
- package/dist/client/950.2797862732563625.js +10 -0
- package/dist/client/index.js +10 -1
- package/dist/client-v2/950.8991b849cd7c1351.js +10 -0
- package/dist/client-v2/index.js +10 -0
- package/dist/externalVersion.js +19 -8
- package/dist/index.js +9 -0
- package/dist/locale/en-US.json +10 -10
- package/dist/locale/zh-CN.json +10 -10
- package/dist/server/collections/ai-api-config.js +9 -0
- package/dist/server/collections/ai-api-role-permissions.js +9 -0
- package/dist/server/index.js +9 -0
- package/dist/server/middleware/rate-limit.js +9 -0
- package/dist/server/middleware/role-permission.js +9 -0
- package/dist/server/plugin.js +14 -0
- package/dist/server/resource/ai-api-config.js +9 -0
- package/dist/server/routes/agent-completions.js +21 -4
- package/dist/server/routes/auth.js +11 -12
- package/dist/server/routes/chat-completions.js +16 -4
- package/dist/server/routes/completions.js +16 -4
- package/dist/server/routes/embeddings.js +10 -3
- package/dist/server/routes/models.js +11 -8
- package/dist/server/routes/router.js +20 -4
- package/dist/server/utils/openai-format.js +9 -0
- package/dist/server/utils/rate-limiter.js +9 -0
- package/dist/server/utils/resolve-service.js +9 -0
- package/dist/swagger.js +10 -4
- package/package.json +21 -3
- package/src/client/AiApiConfigPage.tsx +309 -0
- package/src/client/client.d.ts +258 -0
- package/src/client/components/AiApiRolePermissions.tsx +169 -0
- package/{dist/client/models/index.d.ts → src/client/index.tsx} +10 -10
- package/src/client/locale.ts +21 -0
- package/src/client/models/index.ts +12 -0
- package/src/client/plugin.tsx +48 -0
- package/src/client-v2/plugin.tsx +24 -0
- package/{dist/client/locale.d.ts → src/index.ts} +11 -10
- package/src/locale/en-US.json +10 -0
- package/src/locale/zh-CN.json +10 -0
- package/src/server/collections/.gitkeep +0 -0
- package/src/server/collections/ai-api-config.ts +51 -0
- package/src/server/collections/ai-api-role-permissions.ts +41 -0
- package/src/server/index.ts +10 -0
- package/src/server/middleware/rate-limit.ts +70 -0
- package/src/server/middleware/role-permission.ts +66 -0
- package/src/server/plugin.ts +89 -0
- package/src/server/resource/ai-api-config.ts +74 -0
- package/src/server/routes/agent-completions.ts +428 -0
- package/src/server/routes/auth.ts +111 -0
- package/src/server/routes/chat-completions.ts +318 -0
- package/src/server/routes/completions.ts +299 -0
- package/src/server/routes/embeddings.ts +191 -0
- package/src/server/routes/models.ts +195 -0
- package/src/server/routes/router.ts +283 -0
- package/src/server/utils/openai-format.ts +142 -0
- package/src/server/utils/rate-limiter.ts +83 -0
- package/src/server/utils/resolve-service.ts +82 -0
- package/src/swagger.ts +325 -0
- package/dist/client/2c126424a58bcb27.js +0 -1
- package/dist/client/824c2f7487ee05fd.js +0 -1
- package/dist/client/AiApiConfigPage.d.ts +0 -3
- package/dist/client/components/AiApiRolePermissions.d.ts +0 -8
- package/dist/client/plugin.d.ts +0 -6
- package/dist/index.d.ts +0 -2
- package/dist/server/collections/ai-api-config.d.ts +0 -2
- package/dist/server/collections/ai-api-role-permissions.d.ts +0 -2
- package/dist/server/index.d.ts +0 -1
- package/dist/server/middleware/rate-limit.d.ts +0 -18
- package/dist/server/middleware/role-permission.d.ts +0 -21
- package/dist/server/plugin.d.ts +0 -18
- package/dist/server/resource/ai-api-config.d.ts +0 -10
- package/dist/server/routes/agent-completions.d.ts +0 -34
- package/dist/server/routes/auth.d.ts +0 -8
- package/dist/server/routes/chat-completions.d.ts +0 -9
- package/dist/server/routes/completions.d.ts +0 -10
- package/dist/server/routes/embeddings.d.ts +0 -22
- package/dist/server/routes/models.d.ts +0 -21
- package/dist/server/routes/router.d.ts +0 -25
- package/dist/server/utils/openai-format.d.ts +0 -99
- package/dist/server/utils/rate-limiter.d.ts +0 -35
- package/dist/server/utils/resolve-service.d.ts +0 -19
- package/dist/swagger.d.ts +0 -472
- package/plugin-ai-api-1.0.1.tgz +0 -0
- package/plugin-ai-api-1.0.2.tgz +0 -0
- /package/{dist/client/index.d.ts → src/client-v2/index.tsx} +0 -0
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
var __defProp = Object.defineProperty;
|
|
2
11
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
12
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -34,10 +43,7 @@ async function handleListModels(ctx, plugin) {
|
|
|
34
43
|
const config = await getPluginConfig(ctx);
|
|
35
44
|
const filter = {};
|
|
36
45
|
if ((_a = config == null ? void 0 : config.enabledLlmServices) == null ? void 0 : _a.length) {
|
|
37
|
-
filter.$or = [
|
|
38
|
-
{ name: { $in: config.enabledLlmServices } },
|
|
39
|
-
{ title: { $in: config.enabledLlmServices } }
|
|
40
|
-
];
|
|
46
|
+
filter.$or = [{ name: { $in: config.enabledLlmServices } }, { title: { $in: config.enabledLlmServices } }];
|
|
41
47
|
}
|
|
42
48
|
const services = await ctx.db.getRepository("llmServices").find({
|
|
43
49
|
filter,
|
|
@@ -77,10 +83,7 @@ async function handleGetModel(ctx, modelId, plugin) {
|
|
|
77
83
|
const config = await getPluginConfig(ctx);
|
|
78
84
|
const filter = {};
|
|
79
85
|
if ((_a = config == null ? void 0 : config.enabledLlmServices) == null ? void 0 : _a.length) {
|
|
80
|
-
filter.$or = [
|
|
81
|
-
{ name: { $in: config.enabledLlmServices } },
|
|
82
|
-
{ title: { $in: config.enabledLlmServices } }
|
|
83
|
-
];
|
|
86
|
+
filter.$or = [{ name: { $in: config.enabledLlmServices } }, { title: { $in: config.enabledLlmServices } }];
|
|
84
87
|
}
|
|
85
88
|
const services = await ctx.db.getRepository("llmServices").find({
|
|
86
89
|
filter,
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
var __create = Object.create;
|
|
2
11
|
var __defProp = Object.defineProperty;
|
|
3
12
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -179,18 +188,25 @@ function getRawBody(ctx) {
|
|
|
179
188
|
});
|
|
180
189
|
}
|
|
181
190
|
async function resolveMode(ctx) {
|
|
182
|
-
var _a;
|
|
191
|
+
var _a, _b, _c, _d, _e;
|
|
183
192
|
const headerMode = (_a = ctx.get("X-AI-Mode")) == null ? void 0 : _a.toLowerCase();
|
|
184
193
|
if (headerMode === "agent" || headerMode === "llm") {
|
|
194
|
+
(_b = ctx.app.logger) == null ? void 0 : _b.info(`[ai-api] Mode resolved from header: ${headerMode}`);
|
|
185
195
|
return headerMode;
|
|
186
196
|
}
|
|
187
197
|
try {
|
|
188
198
|
const config = await ctx.db.getRepository("aiApiConfig").findOne();
|
|
189
|
-
if (
|
|
190
|
-
|
|
199
|
+
if (config) {
|
|
200
|
+
const dbMode = config.get("mode") || config.mode;
|
|
201
|
+
if (dbMode === "agent" || dbMode === "llm") {
|
|
202
|
+
(_c = ctx.app.logger) == null ? void 0 : _c.info(`[ai-api] Mode resolved from DB config: ${dbMode}`);
|
|
203
|
+
return dbMode;
|
|
204
|
+
}
|
|
191
205
|
}
|
|
192
|
-
} catch {
|
|
206
|
+
} catch (err) {
|
|
207
|
+
(_d = ctx.app.logger) == null ? void 0 : _d.error("[ai-api] Failed to get mode from config:", err);
|
|
193
208
|
}
|
|
209
|
+
(_e = ctx.app.logger) == null ? void 0 : _e.info(`[ai-api] Mode fallback to default: llm`);
|
|
194
210
|
return "llm";
|
|
195
211
|
}
|
|
196
212
|
function logRequest(ctx, requestId, model, status, durationMs) {
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
var __create = Object.create;
|
|
2
11
|
var __defProp = Object.defineProperty;
|
|
3
12
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
var __defProp = Object.defineProperty;
|
|
2
11
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
12
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
var __defProp = Object.defineProperty;
|
|
2
11
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
12
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
package/dist/swagger.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
var __defProp = Object.defineProperty;
|
|
2
11
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
12
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -202,10 +211,7 @@ var swagger_default = {
|
|
|
202
211
|
properties: {
|
|
203
212
|
model: { type: "string", example: "openai/text-embedding-ada-002" },
|
|
204
213
|
input: {
|
|
205
|
-
oneOf: [
|
|
206
|
-
{ type: "string" },
|
|
207
|
-
{ type: "array", items: { type: "string" } }
|
|
208
|
-
]
|
|
214
|
+
oneOf: [{ type: "string" }, { type: "array", items: { type: "string" } }]
|
|
209
215
|
}
|
|
210
216
|
},
|
|
211
217
|
required: ["model", "input"]
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plugin-ai-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"main": "dist/server/index.js",
|
|
5
5
|
"dependencies": {},
|
|
6
6
|
"peerDependencies": {
|
|
@@ -9,6 +9,24 @@
|
|
|
9
9
|
"@nocobase/database": "2.x",
|
|
10
10
|
"@nocobase/plugin-acl": "2.x",
|
|
11
11
|
"@nocobase/plugin-ai": "2.x",
|
|
12
|
-
"@nocobase/plugin-api-keys": "2.x"
|
|
13
|
-
|
|
12
|
+
"@nocobase/plugin-api-keys": "2.x",
|
|
13
|
+
"@nocobase/client-v2": "2.x",
|
|
14
|
+
"@nocobase/flow-engine": "2.x"
|
|
15
|
+
},
|
|
16
|
+
"nocobase": {
|
|
17
|
+
"supportedVersions": [
|
|
18
|
+
"2.x"
|
|
19
|
+
],
|
|
20
|
+
"editionLevel": 0
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"src",
|
|
25
|
+
"client.js",
|
|
26
|
+
"client-v2.js",
|
|
27
|
+
"server.js",
|
|
28
|
+
"client.d.ts",
|
|
29
|
+
"client-v2.d.ts",
|
|
30
|
+
"server.d.ts"
|
|
31
|
+
]
|
|
14
32
|
}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import React, { useEffect, useState } from 'react';
|
|
11
|
+
import { Card, Form, Select, InputNumber, Button, message, Typography, Space, Alert, Divider, Spin, Radio } from 'antd';
|
|
12
|
+
import { useAPIClient } from '@nocobase/client';
|
|
13
|
+
|
|
14
|
+
const { Title, Text, Paragraph } = Typography;
|
|
15
|
+
|
|
16
|
+
interface AiApiConfig {
|
|
17
|
+
mode: string;
|
|
18
|
+
defaultAiEmployee: string;
|
|
19
|
+
defaultLlmService: string;
|
|
20
|
+
enabledLlmServices: string[];
|
|
21
|
+
rateLimitPerMinute: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface AiEmployee {
|
|
25
|
+
username: string;
|
|
26
|
+
nickname: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface LlmService {
|
|
30
|
+
name: string;
|
|
31
|
+
title: string;
|
|
32
|
+
provider: string;
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function AiApiConfigPage() {
|
|
37
|
+
const api = useAPIClient();
|
|
38
|
+
const [form] = Form.useForm();
|
|
39
|
+
const [loading, setLoading] = useState(true);
|
|
40
|
+
const [saving, setSaving] = useState(false);
|
|
41
|
+
const [employees, setEmployees] = useState<AiEmployee[]>([]);
|
|
42
|
+
const [services, setServices] = useState<LlmService[]>([]);
|
|
43
|
+
const [baseUrl, setBaseUrl] = useState('');
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
loadData();
|
|
47
|
+
setBaseUrl(`${window.location.origin}/api/ai-llm/v1`);
|
|
48
|
+
}, []);
|
|
49
|
+
|
|
50
|
+
const loadData = async () => {
|
|
51
|
+
setLoading(true);
|
|
52
|
+
try {
|
|
53
|
+
// Load config
|
|
54
|
+
const configRes = await api.request({ url: 'aiApiConfig:get' });
|
|
55
|
+
const config = configRes?.data?.data;
|
|
56
|
+
if (config) {
|
|
57
|
+
form.setFieldsValue({
|
|
58
|
+
mode: config.mode || 'llm',
|
|
59
|
+
defaultAiEmployee: config.defaultAiEmployee || undefined,
|
|
60
|
+
defaultLlmService: config.defaultLlmService || undefined,
|
|
61
|
+
enabledLlmServices: config.enabledLlmServices || [],
|
|
62
|
+
rateLimitPerMinute: config.rateLimitPerMinute || 60,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Load AI employees
|
|
67
|
+
const empRes = await api.request({
|
|
68
|
+
url: 'aiEmployees:list',
|
|
69
|
+
params: { paginate: false },
|
|
70
|
+
});
|
|
71
|
+
setEmployees(
|
|
72
|
+
(empRes?.data?.data || []).map((e: any) => ({
|
|
73
|
+
username: e.username,
|
|
74
|
+
nickname: e.nickname || e.username,
|
|
75
|
+
})),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Load LLM services
|
|
79
|
+
const svcRes = await api.request({
|
|
80
|
+
url: 'ai:listLLMServices',
|
|
81
|
+
});
|
|
82
|
+
setServices(
|
|
83
|
+
(svcRes?.data?.data || []).map((s: any) => ({
|
|
84
|
+
name: s.name,
|
|
85
|
+
title: s.title || s.name,
|
|
86
|
+
provider: s.provider,
|
|
87
|
+
enabled: s.enabled !== false,
|
|
88
|
+
})),
|
|
89
|
+
);
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.error('Failed to load config:', err);
|
|
92
|
+
} finally {
|
|
93
|
+
setLoading(false);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const handleSave = async () => {
|
|
98
|
+
setSaving(true);
|
|
99
|
+
try {
|
|
100
|
+
const values = form.getFieldsValue();
|
|
101
|
+
await api.request({
|
|
102
|
+
url: 'aiApiConfig:save',
|
|
103
|
+
method: 'post',
|
|
104
|
+
data: values,
|
|
105
|
+
});
|
|
106
|
+
message.success('Configuration saved');
|
|
107
|
+
} catch (err) {
|
|
108
|
+
message.error('Failed to save configuration');
|
|
109
|
+
} finally {
|
|
110
|
+
setSaving(false);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
if (loading) {
|
|
115
|
+
return (
|
|
116
|
+
<div style={{ display: 'flex', justifyContent: 'center', padding: 60 }}>
|
|
117
|
+
<Spin size="large" />
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<div style={{ maxWidth: 800, margin: '0 auto', padding: '24px 0' }}>
|
|
124
|
+
<Title level={3}>AI API Gateway Configuration</Title>
|
|
125
|
+
<Paragraph type="secondary">
|
|
126
|
+
Configure the OpenAI-compatible API endpoint. External applications can connect using the base URL and a
|
|
127
|
+
NocoBase API key.
|
|
128
|
+
</Paragraph>
|
|
129
|
+
|
|
130
|
+
<Card style={{ marginBottom: 24 }}>
|
|
131
|
+
<Alert
|
|
132
|
+
type="info"
|
|
133
|
+
showIcon
|
|
134
|
+
message="API Endpoint"
|
|
135
|
+
description={
|
|
136
|
+
<Space direction="vertical" size={4}>
|
|
137
|
+
<Text>
|
|
138
|
+
Base URL:{' '}
|
|
139
|
+
<Text code copyable>
|
|
140
|
+
{baseUrl}
|
|
141
|
+
</Text>
|
|
142
|
+
</Text>
|
|
143
|
+
<Text type="secondary">
|
|
144
|
+
Use this as the base URL in any OpenAI-compatible client (Cursor, Continue.dev, n8n, etc.)
|
|
145
|
+
</Text>
|
|
146
|
+
</Space>
|
|
147
|
+
}
|
|
148
|
+
style={{ marginBottom: 16 }}
|
|
149
|
+
/>
|
|
150
|
+
|
|
151
|
+
<Alert
|
|
152
|
+
type="warning"
|
|
153
|
+
showIcon
|
|
154
|
+
message="Authentication"
|
|
155
|
+
description={
|
|
156
|
+
<Text>
|
|
157
|
+
Clients must include a NocoBase API key as a Bearer token:
|
|
158
|
+
<br />
|
|
159
|
+
<Text code>Authorization: Bearer {'<your-nocobase-api-key>'}</Text>
|
|
160
|
+
<br />
|
|
161
|
+
<Text type="secondary">API keys can be created in Settings → API keys.</Text>
|
|
162
|
+
</Text>
|
|
163
|
+
}
|
|
164
|
+
/>
|
|
165
|
+
</Card>
|
|
166
|
+
|
|
167
|
+
<Card title="Configuration">
|
|
168
|
+
<Form form={form} layout="vertical" onFinish={handleSave} initialValues={{ mode: 'llm' }}>
|
|
169
|
+
<Form.Item
|
|
170
|
+
name="mode"
|
|
171
|
+
label="API Mode"
|
|
172
|
+
tooltip="LLM Proxy: Direct access to the LLM model. Agent: Full AI Employee with tools, knowledge base, and agent capabilities."
|
|
173
|
+
>
|
|
174
|
+
<Radio.Group>
|
|
175
|
+
<Radio.Button value="llm">LLM Proxy</Radio.Button>
|
|
176
|
+
<Radio.Button value="agent">AI Employee Agent</Radio.Button>
|
|
177
|
+
</Radio.Group>
|
|
178
|
+
</Form.Item>
|
|
179
|
+
|
|
180
|
+
<Form.Item
|
|
181
|
+
name="defaultAiEmployee"
|
|
182
|
+
label="Default AI Employee"
|
|
183
|
+
tooltip="The AI Employee whose system prompt will be injected into chat completions (when client doesn't provide a system message)"
|
|
184
|
+
>
|
|
185
|
+
<Select
|
|
186
|
+
allowClear
|
|
187
|
+
placeholder="Select an AI Employee (optional)"
|
|
188
|
+
options={employees.map((e) => ({
|
|
189
|
+
label: `${e.nickname} (${e.username})`,
|
|
190
|
+
value: e.username,
|
|
191
|
+
}))}
|
|
192
|
+
/>
|
|
193
|
+
</Form.Item>
|
|
194
|
+
|
|
195
|
+
<Form.Item
|
|
196
|
+
name="defaultLlmService"
|
|
197
|
+
label="Default LLM Service"
|
|
198
|
+
tooltip="The LLM service used when clients send only a model name (e.g. 'gpt-4o') without a service prefix. This is the main service that powers the API."
|
|
199
|
+
rules={[{ required: true, message: 'Please select a default LLM service' }]}
|
|
200
|
+
>
|
|
201
|
+
<Select
|
|
202
|
+
allowClear
|
|
203
|
+
placeholder="Select an LLM Service"
|
|
204
|
+
options={services.map((s) => ({
|
|
205
|
+
label: `${s.title} (${s.provider})`,
|
|
206
|
+
value: s.name,
|
|
207
|
+
}))}
|
|
208
|
+
/>
|
|
209
|
+
</Form.Item>
|
|
210
|
+
|
|
211
|
+
<Form.Item
|
|
212
|
+
name="enabledLlmServices"
|
|
213
|
+
label="Enabled LLM Services"
|
|
214
|
+
tooltip="Only these services will be exposed via the API. Leave empty to expose all enabled services."
|
|
215
|
+
>
|
|
216
|
+
<Select
|
|
217
|
+
mode="multiple"
|
|
218
|
+
allowClear
|
|
219
|
+
placeholder="All enabled services (default)"
|
|
220
|
+
options={services.map((s) => ({
|
|
221
|
+
label: `${s.title} (${s.provider})`,
|
|
222
|
+
value: s.name,
|
|
223
|
+
}))}
|
|
224
|
+
/>
|
|
225
|
+
</Form.Item>
|
|
226
|
+
|
|
227
|
+
<Form.Item
|
|
228
|
+
name="rateLimitPerMinute"
|
|
229
|
+
label="Rate Limit (requests/minute)"
|
|
230
|
+
tooltip="Maximum API requests per user per minute. Set 0 for unlimited."
|
|
231
|
+
>
|
|
232
|
+
<InputNumber min={0} max={10000} style={{ width: 200 }} />
|
|
233
|
+
</Form.Item>
|
|
234
|
+
|
|
235
|
+
<Form.Item>
|
|
236
|
+
<Button type="primary" htmlType="submit" loading={saving}>
|
|
237
|
+
Save Configuration
|
|
238
|
+
</Button>
|
|
239
|
+
</Form.Item>
|
|
240
|
+
</Form>
|
|
241
|
+
</Card>
|
|
242
|
+
|
|
243
|
+
<Card title="Quick Start" style={{ marginTop: 24 }}>
|
|
244
|
+
<Title level={5}>cURL Example</Title>
|
|
245
|
+
<Paragraph>
|
|
246
|
+
<pre
|
|
247
|
+
style={{
|
|
248
|
+
background: '#1a1a2e',
|
|
249
|
+
color: '#e0e0e0',
|
|
250
|
+
padding: 16,
|
|
251
|
+
borderRadius: 8,
|
|
252
|
+
fontSize: 13,
|
|
253
|
+
overflow: 'auto',
|
|
254
|
+
}}
|
|
255
|
+
>{`curl ${baseUrl}/chat/completions \\
|
|
256
|
+
-H "Authorization: Bearer <your-api-key>" \\
|
|
257
|
+
-H "Content-Type: application/json" \\
|
|
258
|
+
-d '{
|
|
259
|
+
"model": "<service-name>/<model-id>",
|
|
260
|
+
"messages": [
|
|
261
|
+
{"role": "user", "content": "Hello!"}
|
|
262
|
+
]
|
|
263
|
+
}'`}</pre>
|
|
264
|
+
</Paragraph>
|
|
265
|
+
|
|
266
|
+
<Title level={5}>Python (OpenAI SDK)</Title>
|
|
267
|
+
<Paragraph>
|
|
268
|
+
<pre
|
|
269
|
+
style={{
|
|
270
|
+
background: '#1a1a2e',
|
|
271
|
+
color: '#e0e0e0',
|
|
272
|
+
padding: 16,
|
|
273
|
+
borderRadius: 8,
|
|
274
|
+
fontSize: 13,
|
|
275
|
+
overflow: 'auto',
|
|
276
|
+
}}
|
|
277
|
+
>{`from openai import OpenAI
|
|
278
|
+
|
|
279
|
+
client = OpenAI(
|
|
280
|
+
base_url="${baseUrl}",
|
|
281
|
+
api_key="<your-nocobase-api-key>"
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
response = client.chat.completions.create(
|
|
285
|
+
model="<service-name>/<model-id>",
|
|
286
|
+
messages=[{"role": "user", "content": "Hello!"}]
|
|
287
|
+
)`}</pre>
|
|
288
|
+
</Paragraph>
|
|
289
|
+
|
|
290
|
+
<Title level={5}>List Available Models</Title>
|
|
291
|
+
<Paragraph>
|
|
292
|
+
<pre
|
|
293
|
+
style={{
|
|
294
|
+
background: '#1a1a2e',
|
|
295
|
+
color: '#e0e0e0',
|
|
296
|
+
padding: 16,
|
|
297
|
+
borderRadius: 8,
|
|
298
|
+
fontSize: 13,
|
|
299
|
+
overflow: 'auto',
|
|
300
|
+
}}
|
|
301
|
+
>{`curl ${baseUrl}/models \\
|
|
302
|
+
-H "Authorization: Bearer <your-api-key>"`}</pre>
|
|
303
|
+
</Paragraph>
|
|
304
|
+
</Card>
|
|
305
|
+
</div>
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export default AiApiConfigPage;
|