@baishuyun/chat-backend 0.0.16 → 0.0.17
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/.env.example +4 -1
- package/CHANGELOG.md +9 -0
- package/config/default.ts +8 -0
- package/dist/config/default.js +6 -0
- package/dist/src/app/main.js +2 -0
- package/dist/src/controllers/common/connect.controll.js +20 -0
- package/dist/src/controllers/common/model.js +10 -0
- package/dist/src/controllers/form/build/build.controller.js +19 -21
- package/dist/src/controllers/form/build/model.js +5 -0
- package/dist/src/controllers/form/build/utils.js +30 -0
- package/dist/src/controllers/form/fill/createFieldsFillingResultTransformStream.js +3 -6
- package/dist/src/controllers/form/fill/fill.controller.js +1 -13
- package/dist/src/controllers/form/fill/utils.js +1 -0
- package/dist/src/controllers/report/query/createQueryTransformStream.js +9 -0
- package/dist/src/controllers/report/query/query.controller.js +1 -13
- package/dist/src/routes/common/common.route.js +7 -0
- package/dist/src/utils/createJsonStreamTransformer.js +3 -10
- package/package.json +5 -4
- package/src/app/main.ts +2 -0
- package/src/controllers/common/connect.controll.ts +24 -0
- package/src/controllers/common/model.ts +12 -0
- package/src/controllers/form/build/build.controller.ts +16 -8
- package/src/controllers/form/build/model.ts +6 -0
- package/src/controllers/form/build/utils.ts +43 -0
- package/src/controllers/form/fill/utils.ts +1 -0
- package/src/routes/common/common.route.ts +10 -0
package/.env.example
CHANGED
package/CHANGELOG.md
CHANGED
package/config/default.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { deepseek } from '@ai-sdk/deepseek';
|
|
1
2
|
import { asyncConfig } from 'config/async.js';
|
|
2
3
|
// load async configurations
|
|
3
4
|
const fetchRemoteConfig = async () => {
|
|
@@ -18,6 +19,13 @@ export default {
|
|
|
18
19
|
|
|
19
20
|
apiAuthKey: process.env.COZE_API_KEY,
|
|
20
21
|
|
|
22
|
+
deepseekApiKey: process.env.DS_API_KEY,
|
|
23
|
+
|
|
24
|
+
common: {
|
|
25
|
+
baseUrl: `http://${process.env.AGENT_HOST}/v3/`,
|
|
26
|
+
apiKey: process.env.BOT_API_KEY, // load from env
|
|
27
|
+
},
|
|
28
|
+
|
|
21
29
|
form: {
|
|
22
30
|
build: {
|
|
23
31
|
botId: process.env.BUILD_BOT_ID || '7579927677256073216',
|
package/dist/config/default.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { deepseek } from '@ai-sdk/deepseek';
|
|
1
2
|
import { asyncConfig } from 'config/async.js';
|
|
2
3
|
// load async configurations
|
|
3
4
|
const fetchRemoteConfig = async () => {
|
|
@@ -14,6 +15,11 @@ export default {
|
|
|
14
15
|
agent: {
|
|
15
16
|
host: process.env.AGENT_HOST || '47.99.202.157',
|
|
16
17
|
apiAuthKey: process.env.COZE_API_KEY,
|
|
18
|
+
deepseekApiKey: process.env.DS_API_KEY,
|
|
19
|
+
common: {
|
|
20
|
+
baseUrl: `http://${process.env.AGENT_HOST}/v3/`,
|
|
21
|
+
apiKey: process.env.BOT_API_KEY, // load from env
|
|
22
|
+
},
|
|
17
23
|
form: {
|
|
18
24
|
build: {
|
|
19
25
|
botId: process.env.BUILD_BOT_ID || '7579927677256073216',
|
package/dist/src/app/main.js
CHANGED
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
*/
|
|
4
4
|
// 应用实例
|
|
5
5
|
import app from '../config/hono.config.js';
|
|
6
|
+
import { createCommonRouter } from '../routes/common/common.route.js';
|
|
6
7
|
// 子路由
|
|
7
8
|
import { createFormRouter } from '../routes/form/form.route.js';
|
|
8
9
|
import { createReportRouter } from '../routes/report/report.route.js';
|
|
9
10
|
// 挂载子路由
|
|
10
11
|
app.route('web/api/form', createFormRouter());
|
|
11
12
|
app.route('web/api/report', createReportRouter());
|
|
13
|
+
app.route('web/api/common', createCommonRouter());
|
|
12
14
|
// 基础健康检查
|
|
13
15
|
app.get('/web/api/health', (c) => {
|
|
14
16
|
return c.json({
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { convertToModelMessages, streamText } from 'ai';
|
|
2
|
+
import { createBaseModel } from './model.js';
|
|
3
|
+
export const connectToAgent = async (c) => {
|
|
4
|
+
let requestBody;
|
|
5
|
+
try {
|
|
6
|
+
const json = await c.req.json();
|
|
7
|
+
requestBody = json;
|
|
8
|
+
}
|
|
9
|
+
catch (_) {
|
|
10
|
+
return c.json({ error: 'Invalid JSON' }, 400);
|
|
11
|
+
}
|
|
12
|
+
const botId = requestBody.botId;
|
|
13
|
+
const messages = requestBody.messages;
|
|
14
|
+
const stream = streamText({
|
|
15
|
+
model: createBaseModel(botId),
|
|
16
|
+
messages: convertToModelMessages(messages),
|
|
17
|
+
includeRawChunks: true,
|
|
18
|
+
});
|
|
19
|
+
return stream.toUIMessageStreamResponse();
|
|
20
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createCoze } from '@baishuyun/coze-provider';
|
|
2
|
+
import config from 'config';
|
|
3
|
+
export const createBaseModel = (botId) => {
|
|
4
|
+
const coze = createCoze({
|
|
5
|
+
apiKey: config.get('agent.common.apiKey'),
|
|
6
|
+
baseURL: config.get('agent.common.baseUrl'),
|
|
7
|
+
botId: botId,
|
|
8
|
+
});
|
|
9
|
+
return coze.chat('chat');
|
|
10
|
+
};
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { convertToModelMessages, streamText } from "ai";
|
|
1
|
+
import { convertToModelMessages, streamText, generateText } from "ai";
|
|
2
2
|
import {} from "hono";
|
|
3
3
|
import { createModel } from "./model.js";
|
|
4
4
|
import { createFieldsJsonTransformStream, SuggestionTransformStream, } from "@baishuyun/coze-provider";
|
|
5
|
+
import { logger } from "../../../logger/index.js";
|
|
6
|
+
import config from 'config';
|
|
7
|
+
import { determineUserIntentByInput } from "./utils.js";
|
|
5
8
|
/**
|
|
6
9
|
* 搭建表单
|
|
7
10
|
* @param c
|
|
@@ -16,10 +19,16 @@ export const buildForm = async (c) => {
|
|
|
16
19
|
catch (_) {
|
|
17
20
|
return c.json({ error: "Invalid JSON" }, 400);
|
|
18
21
|
}
|
|
19
|
-
const
|
|
20
|
-
const
|
|
22
|
+
const intent = await determineUserIntentByInput(requestBody.text, requestBody.stage);
|
|
23
|
+
const isBuildStage = intent === "build";
|
|
24
|
+
const formName = requestBody.name;
|
|
25
|
+
const model = createModel([
|
|
26
|
+
() => createFieldsJsonTransformStream(isBuildStage),
|
|
27
|
+
() => new SuggestionTransformStream(isBuildStage),
|
|
28
|
+
]);
|
|
29
|
+
logger.debug("intent: " + intent);
|
|
21
30
|
const allMessages = [...requestBody.messages];
|
|
22
|
-
if (isBuildStage) {
|
|
31
|
+
if (isBuildStage && formName) {
|
|
23
32
|
allMessages.push({
|
|
24
33
|
role: "user",
|
|
25
34
|
parts: [
|
|
@@ -30,11 +39,12 @@ export const buildForm = async (c) => {
|
|
|
30
39
|
],
|
|
31
40
|
});
|
|
32
41
|
}
|
|
42
|
+
// clear empty text parts to avoid unnecessary streaming
|
|
43
|
+
allMessages.forEach((message) => {
|
|
44
|
+
message.parts = message.parts.filter((part) => part.type === "text" && part.text.trim() !== "");
|
|
45
|
+
});
|
|
33
46
|
const stream = streamText({
|
|
34
|
-
model
|
|
35
|
-
() => createFieldsJsonTransformStream(isBuildStage),
|
|
36
|
-
() => new SuggestionTransformStream(isBuildStage),
|
|
37
|
-
]),
|
|
47
|
+
model,
|
|
38
48
|
messages: convertToModelMessages(allMessages),
|
|
39
49
|
includeRawChunks: true,
|
|
40
50
|
headers: {
|
|
@@ -43,17 +53,5 @@ export const buildForm = async (c) => {
|
|
|
43
53
|
"x-user-token": c.req.header("authorization") || "",
|
|
44
54
|
},
|
|
45
55
|
});
|
|
46
|
-
|
|
47
|
-
// Add SSE keep-alive headers to prevent proxy timeouts during streaming
|
|
48
|
-
return new Response(response.body, {
|
|
49
|
-
status: response.status,
|
|
50
|
-
statusText: response.statusText,
|
|
51
|
-
headers: {
|
|
52
|
-
...Object.fromEntries(response.headers),
|
|
53
|
-
'Connection': 'keep-alive',
|
|
54
|
-
'Keep-Alive': 'timeout=300',
|
|
55
|
-
'X-Accel-Buffering': 'no',
|
|
56
|
-
'Cache-Control': 'no-cache, no-transform',
|
|
57
|
-
},
|
|
58
|
-
});
|
|
56
|
+
return stream.toUIMessageStreamResponse();
|
|
59
57
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createFormBuildIntentAgent } from "@baishuyun/agents";
|
|
1
2
|
import { createCoze } from "@baishuyun/coze-provider";
|
|
2
3
|
import config from "config";
|
|
3
4
|
export const createModel = (extraStreamTransformers) => {
|
|
@@ -9,3 +10,7 @@ export const createModel = (extraStreamTransformers) => {
|
|
|
9
10
|
});
|
|
10
11
|
return coze.chat("chat");
|
|
11
12
|
};
|
|
13
|
+
export const createUserIntentAgent = () => {
|
|
14
|
+
const dsApiKey = config.get("agent.deepseekApiKey");
|
|
15
|
+
return createFormBuildIntentAgent(dsApiKey);
|
|
16
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createUserIntentAgent } from "./model.js";
|
|
2
|
+
export const determineUserIntentByInput = async (input, userOriginIntent) => {
|
|
3
|
+
if (userOriginIntent === "design") {
|
|
4
|
+
return "design";
|
|
5
|
+
}
|
|
6
|
+
if (!input || input.trim() === "") {
|
|
7
|
+
return userOriginIntent;
|
|
8
|
+
}
|
|
9
|
+
const agent = createUserIntentAgent();
|
|
10
|
+
const intent = await agent.generate({
|
|
11
|
+
messages: [{
|
|
12
|
+
role: "user",
|
|
13
|
+
content: [{
|
|
14
|
+
type: "text",
|
|
15
|
+
text: input,
|
|
16
|
+
}]
|
|
17
|
+
}]
|
|
18
|
+
});
|
|
19
|
+
const result = intent.response.messages;
|
|
20
|
+
if (!result || result.length === 0) {
|
|
21
|
+
return userOriginIntent;
|
|
22
|
+
}
|
|
23
|
+
const lastMessage = result[result.length - 1];
|
|
24
|
+
if (!lastMessage.content || lastMessage.content.length === 0) {
|
|
25
|
+
return userOriginIntent;
|
|
26
|
+
}
|
|
27
|
+
const lastContent = lastMessage.content[0];
|
|
28
|
+
const intentText = lastContent.text === "build" ? "build" : lastContent.text === "design" ? "design" : userOriginIntent;
|
|
29
|
+
return intentText;
|
|
30
|
+
};
|
|
@@ -54,14 +54,13 @@ export const createFieldsFillingResultTransformer = (enableJsonParser) => {
|
|
|
54
54
|
}
|
|
55
55
|
catch (e) {
|
|
56
56
|
logger.debug('exception in transform while processing filling chunk');
|
|
57
|
-
|
|
57
|
+
controller.error(e);
|
|
58
58
|
enqueueTextDelta('error', {
|
|
59
59
|
type: 'agent-error',
|
|
60
60
|
error: '解析异常,请刷新重试',
|
|
61
61
|
});
|
|
62
62
|
resolveParseCompleted?.();
|
|
63
|
-
//
|
|
64
|
-
controller.terminate();
|
|
63
|
+
controller.terminate(); // 信号通知下游可读流已关闭
|
|
65
64
|
}
|
|
66
65
|
},
|
|
67
66
|
start: (controller) => {
|
|
@@ -107,14 +106,12 @@ export const createFieldsFillingResultTransformer = (enableJsonParser) => {
|
|
|
107
106
|
console.error('JsonWidgetStream: JSON Parsing Error:', err);
|
|
108
107
|
errorLogged = true;
|
|
109
108
|
}
|
|
110
|
-
// Enqueue error message before closing to allow client to receive it
|
|
111
109
|
enqueueTextDelta('error', {
|
|
112
110
|
type: 'agent-error',
|
|
113
111
|
error: '操作超时,请刷新重试',
|
|
114
112
|
});
|
|
115
113
|
resolveParseCompleted?.();
|
|
116
|
-
//
|
|
117
|
-
controller.terminate();
|
|
114
|
+
controller.terminate(); // 信号通知下游可读流已关闭
|
|
118
115
|
};
|
|
119
116
|
parser.onEnd = () => {
|
|
120
117
|
enqueueTextDelta(' ', JSON.stringify({
|
|
@@ -61,19 +61,7 @@ export const fillForm = async (c) => {
|
|
|
61
61
|
'x-user-token': c.req.header('authorization') || '',
|
|
62
62
|
},
|
|
63
63
|
});
|
|
64
|
-
|
|
64
|
+
return stream.toUIMessageStreamResponse({
|
|
65
65
|
originalMessages: messages, // 建议添加,便于消息 ID 管理
|
|
66
66
|
});
|
|
67
|
-
// Add SSE keep-alive headers to prevent proxy timeouts during streaming
|
|
68
|
-
return new Response(response.body, {
|
|
69
|
-
status: response.status,
|
|
70
|
-
statusText: response.statusText,
|
|
71
|
-
headers: {
|
|
72
|
-
...Object.fromEntries(response.headers),
|
|
73
|
-
'Connection': 'keep-alive',
|
|
74
|
-
'Keep-Alive': 'timeout=300',
|
|
75
|
-
'X-Accel-Buffering': 'no',
|
|
76
|
-
'Cache-Control': 'no-cache, no-transform',
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
67
|
};
|
|
@@ -48,10 +48,18 @@ function handleParsedValue(ctx) {
|
|
|
48
48
|
const { parsedInfo, getResult, currentChunkId, deltaChunkEnqueuer: enqueueTextDelta, ctrl } = ctx;
|
|
49
49
|
const { value } = parsedInfo;
|
|
50
50
|
logger.debug('Parsed JSON value: ' + JSON.stringify(value));
|
|
51
|
+
// aggregate 类型 —— name 字段触发,独立处理后直接返回
|
|
52
|
+
if (isTargetElement('$.name', parsedInfo)) {
|
|
53
|
+
handleAggregateName(ctx);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
51
56
|
// Phase 0: 报表标题 —— 初始化结果并发送 text-start, 必须为起始字段
|
|
52
57
|
if (isTargetElement('$.title', parsedInfo)) {
|
|
53
58
|
handleTitle(ctx);
|
|
54
59
|
}
|
|
60
|
+
// Phase 3: aggregate 结果无需后续字段处理
|
|
61
|
+
if (getResult().isAggregate)
|
|
62
|
+
return;
|
|
55
63
|
// Phase 4: 按注册的 handler 分发字段处理
|
|
56
64
|
for (const { path, handler } of fieldHandlers) {
|
|
57
65
|
if (isTargetElement(path, parsedInfo)) {
|
|
@@ -70,6 +78,7 @@ function handleAggregateName(ctx) {
|
|
|
70
78
|
title: value,
|
|
71
79
|
source: 'aggregate',
|
|
72
80
|
type: 'data_table',
|
|
81
|
+
isAggregate: true,
|
|
73
82
|
});
|
|
74
83
|
logger.debug('Parsed aggregate table title: ' + value);
|
|
75
84
|
enqueueTextDelta(`${JSON.stringify(value)},`, { type: 'query-stream-parsed-info', result: JSON.stringify(getResult()) }, currentChunkId + 1, false);
|
|
@@ -36,19 +36,7 @@ export const queryReport = async (c) => {
|
|
|
36
36
|
'x-user-id': Date.now().toString(), // uid,
|
|
37
37
|
},
|
|
38
38
|
});
|
|
39
|
-
|
|
39
|
+
return stream.toUIMessageStreamResponse({
|
|
40
40
|
originalMessages: messages, // 建议添加,便于消息 ID 管理
|
|
41
41
|
});
|
|
42
|
-
// Add SSE keep-alive headers to prevent proxy timeouts during streaming
|
|
43
|
-
return new Response(response.body, {
|
|
44
|
-
status: response.status,
|
|
45
|
-
statusText: response.statusText,
|
|
46
|
-
headers: {
|
|
47
|
-
...Object.fromEntries(response.headers),
|
|
48
|
-
'Connection': 'keep-alive',
|
|
49
|
-
'Keep-Alive': 'timeout=300',
|
|
50
|
-
'X-Accel-Buffering': 'no',
|
|
51
|
-
'Cache-Control': 'no-cache, no-transform',
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
42
|
};
|
|
@@ -83,8 +83,8 @@ class JsonStreamProcessor {
|
|
|
83
83
|
await this.parseCompleted;
|
|
84
84
|
logger.debug('Parser stopped gracefully');
|
|
85
85
|
}
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
if (!this.terminated)
|
|
87
|
+
controller.terminate();
|
|
88
88
|
}
|
|
89
89
|
catch (error) {
|
|
90
90
|
controller.error(`Cleanup error: ${error}`);
|
|
@@ -160,14 +160,7 @@ class JsonStreamProcessor {
|
|
|
160
160
|
terminateStream(controller) {
|
|
161
161
|
this.completeParsing();
|
|
162
162
|
this.terminated = true;
|
|
163
|
-
|
|
164
|
-
// This allows the stream to be properly handled by upstream consumers
|
|
165
|
-
try {
|
|
166
|
-
controller.error(new Error('Stream terminated due to error'));
|
|
167
|
-
}
|
|
168
|
-
catch (e) {
|
|
169
|
-
// Controller may already be closed, ignore
|
|
170
|
-
}
|
|
163
|
+
controller.terminate();
|
|
171
164
|
}
|
|
172
165
|
/** 向下游推送 agent-error 并终止流 */
|
|
173
166
|
enqueueError(controller, error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@baishuyun/chat-backend",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -22,8 +22,9 @@
|
|
|
22
22
|
"parse-sse": "^0.1.0",
|
|
23
23
|
"pino": "^10.1.0",
|
|
24
24
|
"zod": "^4.1.13",
|
|
25
|
-
"@baishuyun/coze-provider": "0.0.
|
|
26
|
-
"@baishuyun/
|
|
25
|
+
"@baishuyun/coze-provider": "0.0.17",
|
|
26
|
+
"@baishuyun/agents": "0.0.17",
|
|
27
|
+
"@baishuyun/types": "1.0.17"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"@types/config": "^3.3.5",
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
"pm2": "^6.0.14",
|
|
35
36
|
"tsx": "^4.7.1",
|
|
36
37
|
"typescript": "^5.8.3",
|
|
37
|
-
"@baishuyun/typescript-config": "0.0.
|
|
38
|
+
"@baishuyun/typescript-config": "0.0.17"
|
|
38
39
|
},
|
|
39
40
|
"scripts": {
|
|
40
41
|
"dev": "cross-env NODE_ENV=development tsx watch src/index.ts",
|
package/src/app/main.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
// 应用实例
|
|
6
6
|
import app from '../config/hono.config.js';
|
|
7
|
+
import { createCommonRouter } from '../routes/common/common.route.js';
|
|
7
8
|
|
|
8
9
|
// 子路由
|
|
9
10
|
import { createFormRouter } from '../routes/form/form.route.js';
|
|
@@ -12,6 +13,7 @@ import { createReportRouter } from '../routes/report/report.route.js';
|
|
|
12
13
|
// 挂载子路由
|
|
13
14
|
app.route('web/api/form', createFormRouter());
|
|
14
15
|
app.route('web/api/report', createReportRouter());
|
|
16
|
+
app.route('web/api/common', createCommonRouter());
|
|
15
17
|
|
|
16
18
|
// 基础健康检查
|
|
17
19
|
app.get('/web/api/health', (c) => {
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { convertToModelMessages, streamText } from 'ai';
|
|
2
|
+
import type { Context } from 'hono';
|
|
3
|
+
import { createBaseModel } from './model.js';
|
|
4
|
+
|
|
5
|
+
export const connectToAgent = async (c: Context) => {
|
|
6
|
+
let requestBody;
|
|
7
|
+
try {
|
|
8
|
+
const json = await c.req.json();
|
|
9
|
+
requestBody = json;
|
|
10
|
+
} catch (_) {
|
|
11
|
+
return c.json({ error: 'Invalid JSON' }, 400);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const botId = requestBody.botId;
|
|
15
|
+
const messages = requestBody.messages;
|
|
16
|
+
|
|
17
|
+
const stream = streamText({
|
|
18
|
+
model: createBaseModel(botId),
|
|
19
|
+
messages: convertToModelMessages(messages),
|
|
20
|
+
includeRawChunks: true,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return stream.toUIMessageStreamResponse();
|
|
24
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createCoze } from '@baishuyun/coze-provider';
|
|
2
|
+
import config from 'config';
|
|
3
|
+
|
|
4
|
+
export const createBaseModel = (botId: string) => {
|
|
5
|
+
const coze = createCoze({
|
|
6
|
+
apiKey: config.get<string>('agent.common.apiKey'),
|
|
7
|
+
baseURL: config.get<string>('agent.common.baseUrl'),
|
|
8
|
+
botId: botId,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
return coze.chat('chat');
|
|
12
|
+
};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { convertToModelMessages, streamText, type TextUIPart } from "ai";
|
|
1
|
+
import { convertToModelMessages, streamText, generateText, type TextUIPart } from "ai";
|
|
2
2
|
import { type Context } from "hono";
|
|
3
3
|
import { createModel } from "./model.js";
|
|
4
4
|
import {
|
|
5
5
|
createFieldsJsonTransformStream,
|
|
6
6
|
SuggestionTransformStream,
|
|
7
7
|
} from "@baishuyun/coze-provider";
|
|
8
|
+
import { logger } from "../../../logger/index.js";
|
|
9
|
+
import config from 'config';
|
|
10
|
+
import { determineUserIntentByInput } from "./utils.js";
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
13
|
* 搭建表单
|
|
@@ -21,11 +24,19 @@ export const buildForm = async (c: Context) => {
|
|
|
21
24
|
return c.json({ error: "Invalid JSON" }, 400);
|
|
22
25
|
}
|
|
23
26
|
|
|
24
|
-
const
|
|
25
|
-
|
|
27
|
+
const intent = await determineUserIntentByInput(requestBody.text, requestBody.stage);
|
|
28
|
+
|
|
29
|
+
const isBuildStage = intent === "build";
|
|
30
|
+
const formName = requestBody.name;
|
|
31
|
+
const model = createModel([
|
|
32
|
+
() => createFieldsJsonTransformStream(isBuildStage),
|
|
33
|
+
() => new SuggestionTransformStream(isBuildStage),
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
logger.debug("intent: " + intent);
|
|
26
37
|
|
|
27
38
|
const allMessages = [...requestBody.messages];
|
|
28
|
-
if (isBuildStage) {
|
|
39
|
+
if (isBuildStage && formName) {
|
|
29
40
|
allMessages.push({
|
|
30
41
|
role: "user",
|
|
31
42
|
parts: [
|
|
@@ -45,10 +56,7 @@ export const buildForm = async (c: Context) => {
|
|
|
45
56
|
});
|
|
46
57
|
|
|
47
58
|
const stream = streamText({
|
|
48
|
-
model
|
|
49
|
-
() => createFieldsJsonTransformStream(isBuildStage),
|
|
50
|
-
() => new SuggestionTransformStream(isBuildStage),
|
|
51
|
-
]),
|
|
59
|
+
model,
|
|
52
60
|
messages: convertToModelMessages(allMessages),
|
|
53
61
|
includeRawChunks: true,
|
|
54
62
|
headers: {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LanguageModelV2StreamPart } from "@ai-sdk/provider";
|
|
2
|
+
import { createFormBuildIntentAgent } from "@baishuyun/agents";
|
|
2
3
|
import { createCoze } from "@baishuyun/coze-provider";
|
|
3
4
|
import config from "config";
|
|
4
5
|
|
|
@@ -14,3 +15,8 @@ export const createModel = (
|
|
|
14
15
|
|
|
15
16
|
return coze.chat("chat");
|
|
16
17
|
};
|
|
18
|
+
|
|
19
|
+
export const createUserIntentAgent = () => {
|
|
20
|
+
const dsApiKey = config.get<string>("agent.deepseekApiKey");
|
|
21
|
+
return createFormBuildIntentAgent(dsApiKey);
|
|
22
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createUserIntentAgent } from "./model.js"
|
|
2
|
+
|
|
3
|
+
export const determineUserIntentByInput = async (input: string, userOriginIntent: "build" | "design" | null): Promise<"build" | "design" | null> => {
|
|
4
|
+
if (userOriginIntent === "design") {
|
|
5
|
+
return "design";
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (!input || input.trim() === "") {
|
|
9
|
+
return userOriginIntent;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const agent = createUserIntentAgent();
|
|
13
|
+
|
|
14
|
+
const intent = await agent.generate({
|
|
15
|
+
messages: [{
|
|
16
|
+
role: "user",
|
|
17
|
+
content: [{
|
|
18
|
+
type: "text",
|
|
19
|
+
text: input,
|
|
20
|
+
}]
|
|
21
|
+
}]
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const result = intent.response.messages;
|
|
25
|
+
if (!result || result.length === 0) {
|
|
26
|
+
return userOriginIntent;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const lastMessage = result[result.length - 1];
|
|
30
|
+
|
|
31
|
+
if (!lastMessage.content || lastMessage.content.length === 0) {
|
|
32
|
+
return userOriginIntent;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const lastContent = lastMessage.content[0] as {
|
|
36
|
+
type: "text";
|
|
37
|
+
text: string;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const intentText = lastContent.text === "build" ? "build" : lastContent.text === "design" ? "design" : userOriginIntent;
|
|
41
|
+
|
|
42
|
+
return intentText;
|
|
43
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { connectToAgent } from '../../controllers/common/connect.controll.js';
|
|
3
|
+
|
|
4
|
+
export const createCommonRouter = () => {
|
|
5
|
+
const commonRouter = new Hono();
|
|
6
|
+
|
|
7
|
+
commonRouter.post('/connect', connectToAgent);
|
|
8
|
+
|
|
9
|
+
return commonRouter;
|
|
10
|
+
};
|