@shun-js/aibaiban-server 1.1.3 → 1.1.5

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.
@@ -5,7 +5,7 @@
5
5
  "start_url": "/",
6
6
  "display": "standalone",
7
7
  "background_color": "#ffffff",
8
- "theme_color": "#1677ff",
8
+ "theme_color": "#ffffff",
9
9
  "orientation": "any",
10
10
  "icons": [
11
11
  {
@@ -8,7 +8,7 @@
8
8
  <!-- 首页/落地页 - 最高优先级 -->
9
9
  <url>
10
10
  <loc>https://aibaiban.com/</loc>
11
- <lastmod>2026-02-03</lastmod>
11
+ <lastmod>2026-03-16</lastmod>
12
12
  <changefreq>weekly</changefreq>
13
13
  <priority>1.0</priority>
14
14
  </url>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shun-js/aibaiban-server",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
4
4
  "description": "aibaiban.com server",
5
5
  "keywords": [
6
6
  "ai aibaiban"
@@ -37,7 +37,7 @@
37
37
  "qiao-z-nuser": "^6.0.0",
38
38
  "qiao-z-service": "^6.0.0",
39
39
  "qiao-z-sms": "^6.0.0",
40
- "viho-llm": "^1.0.1",
40
+ "viho-llm": "^1.0.6",
41
41
  "zod": "^4.3.6",
42
42
  "zod-to-json-schema": "^3.25.1"
43
43
  },
@@ -45,5 +45,5 @@
45
45
  "access": "public",
46
46
  "registry": "https://registry.npmjs.org/"
47
47
  },
48
- "gitHead": "67a94cc4678fac5914febba1452f71dc16e2f99a"
48
+ "gitHead": "94bf576ed7112fe207b8ed4c4db530db6b8ecc3d"
49
49
  }
@@ -1,10 +1,16 @@
1
- // llm agent
2
- const { callLLMForJSON, callLLM } = require('../util/llm-agent.js');
1
+ // llm
2
+ const { OpenAIAPI, runAgents } = require('viho-llm');
3
3
  const prompts = require('../util/prompt-agent.js');
4
4
 
5
5
  // util
6
6
  const { chatFeishuMsg, errorFeishuMsg } = require('../util/feishu.js');
7
7
 
8
+ // LLM 配置
9
+ const llmConfig = global.QZ_CONFIG.llm;
10
+ const finalLLMConfig = llmConfig[llmConfig.default];
11
+ const llm = OpenAIAPI(finalLLMConfig);
12
+ const modelName = finalLLMConfig.modelName;
13
+
8
14
  /**
9
15
  * drawAgent - 流式 Agent 接口
10
16
  * 流程:router -> classify -> elaborate -> generate
@@ -31,76 +37,125 @@ exports.drawAgent = async (req, res) => {
31
37
  const startTime = Date.now();
32
38
  let stepStart = startTime;
33
39
 
34
- // start
35
- res.streaming(`data: ${JSON.stringify({ step: 'router', status: 'start' })}\n\n`);
36
- req.logger.info(methodName, 'step: router');
37
-
38
- // intent
39
- const intentResult = await callLLMForJSON(prompts.ROUTER_PROMPT.replace('{input}', input), res, 'router');
40
- const intent = intentResult.intent;
41
- const routerTime = Date.now() - stepStart;
42
- req.logger.info(methodName, 'intent', intent, `${routerTime}ms`);
43
- chatFeishuMsg(req, `intent-${intent}`);
44
- res.streaming(`data: ${JSON.stringify({ step: 'router', intent, duration: routerTime })}\n\n`);
45
-
46
- // 非白板请求
47
- if (intent === 'irrelevant') {
48
- res.streaming(
49
- `data: ${JSON.stringify({ step: 'router', result: 'irrelevant', response: prompts.FIXED_REPLY })}\n\n`,
50
- );
51
- res.streamingEnd();
52
- return;
53
- }
54
-
55
- // 2. classify - 分类图表类型
56
- stepStart = Date.now();
57
- res.streaming(`data: ${JSON.stringify({ step: 'classify', status: 'start' })}\n\n`);
58
- req.logger.info(methodName, 'step: classify');
59
- const classifyResult = await callLLMForJSON(prompts.CLASSIFY_PROMPT.replace('{input}', input), res, 'classify');
60
- const diagramType = classifyResult.diagramType;
61
- const classifyTime = Date.now() - stepStart;
62
- req.logger.info(methodName, 'diagramType', diagramType, `${classifyTime}ms`);
63
- chatFeishuMsg(req, `diagramType-${diagramType}`);
64
- res.streaming(`data: ${JSON.stringify({ step: 'classify', diagramType, duration: classifyTime })}\n\n`);
65
-
66
- // 3. elaborate - 细化内容
67
- stepStart = Date.now();
68
- res.streaming(`data: ${JSON.stringify({ step: 'elaborate', status: 'start' })}\n\n`);
69
- req.logger.info(methodName, 'step: elaborate');
70
- const elaboration = await callLLM(
71
- prompts.ELABORATE_PROMPT.replace('{input}', input).replace('{diagramType}', diagramType),
72
- res,
73
- 'elaborate',
74
- );
75
- const elaborateTime = Date.now() - stepStart;
76
- req.logger.info(methodName, 'elaboration', elaboration.slice(0, 100) + '...', `${elaborateTime}ms`);
77
- chatFeishuMsg(req, `elaboration-${elaboration}`);
78
- res.streaming(`data: ${JSON.stringify({ step: 'elaborate', done: true, duration: elaborateTime })}\n\n`);
40
+ // agent 管线共享状态
41
+ let diagramType = '';
42
+ let elaboration = '';
79
43
 
80
- // 4. generate - 生成 Mermaid
81
- stepStart = Date.now();
82
- res.streaming(`data: ${JSON.stringify({ step: 'generate', status: 'start' })}\n\n`);
83
- req.logger.info(methodName, 'step: generate');
84
- const mermaidCode = await callLLM(
85
- prompts.GENERATE_PROMPT.replace('{diagramType}', diagramType).replace('{elaboration}', elaboration),
86
- res,
87
- 'generate',
88
- );
89
- const generateTime = Date.now() - stepStart;
90
- const totalTime = Date.now() - startTime;
91
- req.logger.info(
92
- methodName,
93
- 'mermaidCode',
94
- mermaidCode.slice(0, 100) + '...',
95
- `${generateTime}ms`,
96
- `total: ${totalTime}ms`,
97
- );
98
- chatFeishuMsg(req, `mermaidCode-${mermaidCode}`);
44
+ await runAgents([
45
+ // 1. router - 意图分类
46
+ {
47
+ agentStartCallback: () => {
48
+ stepStart = Date.now();
49
+ res.streaming(`data: ${JSON.stringify({ step: 'router', status: 'start' })}\n\n`);
50
+ req.logger.info(methodName, 'step: router');
51
+ },
52
+ agentRequestOptions: {
53
+ llm,
54
+ modelName,
55
+ messages: [{ role: 'user', content: prompts.ROUTER_PROMPT.replace('{input}', input) }],
56
+ isJson: true,
57
+ },
58
+ agentEndCallback: (result) => {
59
+ const intent = result.intent;
60
+ const duration = Date.now() - stepStart;
61
+ req.logger.info(methodName, 'intent', intent, `${duration}ms`);
62
+ chatFeishuMsg(req, `intent-${intent}`);
63
+ res.streaming(`data: ${JSON.stringify({ step: 'router', intent, duration })}\n\n`);
64
+ return intent === 'irrelevant';
65
+ },
66
+ agentBreakCallback: () => {
67
+ res.streaming(
68
+ `data: ${JSON.stringify({ step: 'router', result: 'irrelevant', response: prompts.FIXED_REPLY })}\n\n`,
69
+ );
70
+ },
71
+ },
72
+ // 2. classify - 分类图表类型
73
+ {
74
+ agentStartCallback: () => {
75
+ stepStart = Date.now();
76
+ res.streaming(`data: ${JSON.stringify({ step: 'classify', status: 'start' })}\n\n`);
77
+ req.logger.info(methodName, 'step: classify');
78
+ },
79
+ agentRequestOptions: {
80
+ llm,
81
+ modelName,
82
+ messages: [{ role: 'user', content: prompts.CLASSIFY_PROMPT.replace('{input}', input) }],
83
+ isJson: true,
84
+ },
85
+ agentEndCallback: (result) => {
86
+ diagramType = result.diagramType;
87
+ const duration = Date.now() - stepStart;
88
+ req.logger.info(methodName, 'diagramType', diagramType, `${duration}ms`);
89
+ chatFeishuMsg(req, `diagramType-${diagramType}`);
90
+ res.streaming(`data: ${JSON.stringify({ step: 'classify', diagramType, duration })}\n\n`);
91
+ },
92
+ },
93
+ // 3. elaborate - 细化内容
94
+ {
95
+ agentStartCallback: () => {
96
+ stepStart = Date.now();
97
+ res.streaming(`data: ${JSON.stringify({ step: 'elaborate', status: 'start' })}\n\n`);
98
+ req.logger.info(methodName, 'step: elaborate');
99
+ },
100
+ agentRequestOptions: {
101
+ llm,
102
+ modelName,
103
+ get messages() {
104
+ return [
105
+ {
106
+ role: 'user',
107
+ content: prompts.ELABORATE_PROMPT.replace('{input}', input).replace('{diagramType}', diagramType),
108
+ },
109
+ ];
110
+ },
111
+ },
112
+ agentEndCallback: (result) => {
113
+ elaboration = result;
114
+ const duration = Date.now() - stepStart;
115
+ req.logger.info(methodName, 'elaboration', elaboration.slice(0, 100) + '...', `${duration}ms`);
116
+ chatFeishuMsg(req, `elaboration-${elaboration}`);
117
+ res.streaming(`data: ${JSON.stringify({ step: 'elaborate', done: true, duration })}\n\n`);
118
+ },
119
+ },
120
+ // 4. generate - 生成 Mermaid
121
+ {
122
+ agentStartCallback: () => {
123
+ stepStart = Date.now();
124
+ res.streaming(`data: ${JSON.stringify({ step: 'generate', status: 'start' })}\n\n`);
125
+ req.logger.info(methodName, 'step: generate');
126
+ },
127
+ agentRequestOptions: {
128
+ llm,
129
+ modelName,
130
+ get messages() {
131
+ return [
132
+ {
133
+ role: 'user',
134
+ content: prompts.GENERATE_PROMPT.replace('{diagramType}', diagramType).replace(
135
+ '{elaboration}',
136
+ elaboration,
137
+ ),
138
+ },
139
+ ];
140
+ },
141
+ },
142
+ agentEndCallback: (result) => {
143
+ const mermaidCode = result;
144
+ const duration = Date.now() - stepStart;
145
+ const totalDuration = Date.now() - startTime;
146
+ req.logger.info(
147
+ methodName,
148
+ 'mermaidCode',
149
+ mermaidCode.slice(0, 100) + '...',
150
+ `${duration}ms`,
151
+ `total: ${totalDuration}ms`,
152
+ );
153
+ chatFeishuMsg(req, `mermaidCode-${mermaidCode}`);
154
+ res.streaming(`data: ${JSON.stringify({ step: 'generate', mermaidCode, duration, totalDuration })}\n\n`);
155
+ },
156
+ },
157
+ ]);
99
158
 
100
- // 返回最终结果
101
- res.streaming(
102
- `data: ${JSON.stringify({ step: 'generate', mermaidCode, duration: generateTime, totalDuration: totalTime })}\n\n`,
103
- );
104
159
  res.streamingEnd();
105
160
  } catch (error) {
106
161
  req.logger.error(methodName, 'error', error);
package/views/index.html CHANGED
@@ -5,30 +5,31 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
 
7
7
  <!-- Primary Meta Tags -->
8
- <title>AI白板 - 在线协作白板工具 | AI生成流程图思维导图架构图</title>
9
- <meta name="title" content="AI白板 - 在线协作白板工具 | AI生成流程图思维导图架构图" />
8
+ <title>AI白板 - 在线协作白板工具 | AI生成流程图时序图类图ER图</title>
9
+ <meta name="title" content="AI白板 - 在线协作白板工具 | AI生成流程图时序图类图ER图" />
10
10
  <meta
11
11
  name="description"
12
- content="AI白板是专业的在线协作白板软件,AI驱动自动生成流程图、思维导图、架构图、UML图。支持多人实时协作、远程办公、团队协同。Miro、FigJam、boardmix优质替代方案,一句话完成专业图表绘制。"
12
+ content="AI白板是专业的在线协作白板软件,AI驱动自动生成流程图、时序图、类图、ER图。支持在线协作、远程办公、团队协同。Miro、FigJam、boardmix优质替代方案,一句话完成专业图表绘制。"
13
13
  />
14
14
  <meta
15
15
  name="keywords"
16
- content="AI白板,在线白板,电子白板,协作白板,白板软件,AI生成流程图,AI思维导图,架构图工具,UML图,多人实时协作,在线协同,远程办公,团队协作,头脑风暴工具,设计协作,可视化工具,Miro替代,FigJam替代,boardmix替代,Excalidraw,ProcessOn,GitMind"
16
+ content="AI白板,在线白板,电子白板,协作白板,白板软件,AI生成流程图,AI时序图,AI类图,AI ER图,在线协同,远程办公,团队协作,头脑风暴工具,设计协作,可视化工具,Miro替代,FigJam替代,boardmix替代,Excalidraw,ProcessOn,GitMind"
17
17
  />
18
18
  <meta name="author" content="Vincent" />
19
19
  <meta name="robots" content="index, follow" />
20
+ <link rel="canonical" href="https://aibaiban.com/" />
20
21
 
21
22
  <!-- Theme Color -->
22
- <meta name="theme-color" content="#1677ff" />
23
+ <meta name="theme-color" content="#ffffff" />
23
24
  <meta name="color-scheme" content="light dark" />
24
25
 
25
26
  <!-- Open Graph / Facebook -->
26
27
  <meta property="og:type" content="website" />
27
28
  <meta property="og:url" content="https://aibaiban.com/" />
28
- <meta property="og:title" content="AI白板 - 在线协作白板工具 | AI生成流程图思维导图" />
29
+ <meta property="og:title" content="AI白板 - 在线协作白板工具 | AI生成流程图时序图类图ER图" />
29
30
  <meta
30
31
  property="og:description"
31
- content="专业的在线协作白板软件,AI自动生成流程图、思维导图、架构图。支持多人实时协作、远程办公。Miro/FigJam优质替代方案。"
32
+ content="专业的在线协作白板软件,AI自动生成流程图、时序图、类图、ER图。支持在线协作、远程办公。Miro/FigJam优质替代方案。"
32
33
  />
33
34
  <meta property="og:image" content="https://static-small.vincentqiao.com/aibaiban/static/og-image.png" />
34
35
  <meta property="og:site_name" content="AI白板" />
@@ -37,15 +38,15 @@
37
38
  <!-- Twitter Card -->
38
39
  <meta name="twitter:card" content="summary_large_image" />
39
40
  <meta name="twitter:url" content="https://aibaiban.com/" />
40
- <meta name="twitter:title" content="AI白板 - 在线协作白板工具 | AI生成流程图思维导图" />
41
+ <meta name="twitter:title" content="AI白板 - 在线协作白板工具 | AI生成流程图时序图类图ER图" />
41
42
  <meta
42
43
  name="twitter:description"
43
- content="专业的在线协作白板软件,AI自动生成流程图、思维导图、架构图。支持多人实时协作、远程办公。"
44
+ content="专业的在线协作白板软件,AI自动生成流程图、时序图、类图、ER图。支持在线协作、远程办公。"
44
45
  />
45
46
  <meta name="twitter:image" content="https://static-small.vincentqiao.com/aibaiban/static/og-image.png" />
46
47
 
47
48
  <!-- Apple Mobile Web App -->
48
- <meta name="apple-mobile-web-app-capable" content="yes" />
49
+ <meta name="mobile-web-app-capable" content="yes" />
49
50
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
50
51
  <meta name="apple-mobile-web-app-title" content="AI白板" />
51
52
 
@@ -59,35 +60,30 @@
59
60
 
60
61
  <!-- Structured Data (JSON-LD) for SEO -->
61
62
  <script type="application/ld+json">
62
- {
63
- "@context": "https://schema.org",
64
- "@type": "SoftwareApplication",
65
- "name": "AI白板",
66
- "applicationCategory": "DesignApplication",
67
- "operatingSystem": "Web",
68
- "offers": {
69
- "@type": "Offer",
70
- "price": "0",
71
- "priceCurrency": "CNY"
63
+ [
64
+ {
65
+ "@context": "https://schema.org",
66
+ "@type": "WebSite",
67
+ "name": "AI白板",
68
+ "url": "https://aibaiban.com"
72
69
  },
73
- "description": "专业的在线协作白板软件,AI驱动自动生成流程图、思维导图、架构图。支持多人实时协作、远程办公、团队协同。",
74
- "url": "https://aibaiban.com",
75
- "image": "https://static-small.vincentqiao.com/aibaiban/static/og-image.png",
76
- "aggregateRating": {
77
- "@type": "AggregateRating",
78
- "ratingValue": "4.8",
79
- "ratingCount": "1000"
80
- },
81
- "featureList": [
82
- "AI生成流程图",
83
- "AI生成思维导图",
84
- "在线协作白板",
85
- "多人实时协同",
86
- "架构图工具",
87
- "UML图生成",
88
- "远程办公支持"
89
- ]
90
- }
70
+ {
71
+ "@context": "https://schema.org",
72
+ "@type": "SoftwareApplication",
73
+ "name": "AI白板",
74
+ "applicationCategory": "DesignApplication",
75
+ "operatingSystem": "Web",
76
+ "offers": {
77
+ "@type": "Offer",
78
+ "price": "0",
79
+ "priceCurrency": "CNY"
80
+ },
81
+ "description": "专业的在线协作白板软件,AI驱动自动生成流程图、时序图、类图、ER图。支持在线协作、远程办公、团队协同。",
82
+ "url": "https://aibaiban.com",
83
+ "image": "https://static-small.vincentqiao.com/aibaiban/static/og-image.png",
84
+ "featureList": ["AI生成流程图", "AI生成时序图", "AI生成类图", "AI生成ER图", "在线协作白板", "远程办公支持"]
85
+ }
86
+ ]
91
87
  </script>
92
88
  <!-- Microsoft Clarity (production only) -->
93
89
  <script type="text/javascript">
@@ -1,63 +0,0 @@
1
- // llm
2
- const { OpenAIAPI } = require('viho-llm');
3
-
4
- /**
5
- * LLM 配置 - 使用 moonshot 平台的 kimi-k2.5
6
- */
7
- const llmConfig = global.QZ_CONFIG.llm;
8
- const finalLLMConfig = llmConfig[llmConfig.default];
9
- const llm = OpenAIAPI(finalLLMConfig);
10
-
11
- /**
12
- * 从文本中提取 JSON
13
- */
14
- function extractJSON(text) {
15
- const cleaned = text.replace(/\{\{/g, '{').replace(/\}\}/g, '}');
16
- try {
17
- return JSON.parse(cleaned);
18
- } catch (e) {
19
- // try next
20
- }
21
- const codeBlock = cleaned.match(/```(?:json)?\s*([\s\S]*?)```/);
22
- if (codeBlock) {
23
- try {
24
- return JSON.parse(codeBlock[1].trim());
25
- } catch (e) {
26
- // try next
27
- }
28
- }
29
- const match = cleaned.match(/(\{[\s\S]*\}|\[[\s\S]*\])/);
30
- if (match) {
31
- try {
32
- return JSON.parse(match[1]);
33
- } catch (e) {
34
- // try next
35
- }
36
- }
37
- throw new Error(`Cannot extract JSON from: ${text.slice(0, 200)}`);
38
- }
39
-
40
- /**
41
- * 调用 LLM 并解析 JSON
42
- */
43
- exports.callLLMForJSON = async (prompt) => {
44
- const response = await llm.chat({
45
- model: finalLLMConfig.modelName,
46
- messages: [{ role: 'user', content: prompt }],
47
- });
48
-
49
- const fullContent = response.content || '';
50
- return extractJSON(fullContent);
51
- };
52
-
53
- /**
54
- * 调用 LLM(普通文本)
55
- */
56
- exports.callLLM = async (prompt) => {
57
- const response = await llm.chat({
58
- model: finalLLMConfig.modelName,
59
- messages: [{ role: 'user', content: prompt }],
60
- });
61
-
62
- return response.content || '';
63
- };
@@ -1,79 +0,0 @@
1
- // path
2
- const path = require('path');
3
- const { readFile } = require('qiao-file');
4
-
5
- // z
6
- const { z } = require('zod');
7
- const { zodToJsonSchema } = require('zod-to-json-schema');
8
-
9
- // llm
10
- const { GeminiVertex } = require('viho-llm');
11
- const gemini = GeminiVertex({
12
- projectId: global.QZ_CONFIG.gemini.projectId,
13
- location: global.QZ_CONFIG.gemini.location,
14
- modelName: global.QZ_CONFIG.gemini.modelName,
15
- });
16
-
17
- // const
18
- const chatConfig = {
19
- responseMimeType: 'application/json',
20
- temperature: 0.2, // 保持较低温度,确保输出稳定
21
- topP: 0.9,
22
- topK: 40,
23
- maxOutputTokens: 8192, // 足够大以支持复杂图表
24
- thinkingConfig: {
25
- thinkingBudget: 0,
26
- includeThoughts: false,
27
- },
28
- };
29
- const safetySettings = [
30
- {
31
- category: 'HARM_CATEGORY_HATE_SPEECH',
32
- threshold: 'BLOCK_ONLY_HIGH',
33
- },
34
- {
35
- category: 'HARM_CATEGORY_DANGEROUS_CONTENT',
36
- threshold: 'BLOCK_ONLY_HIGH',
37
- },
38
- {
39
- category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT',
40
- threshold: 'BLOCK_ONLY_HIGH',
41
- },
42
- {
43
- category: 'HARM_CATEGORY_HARASSMENT',
44
- threshold: 'BLOCK_ONLY_HIGH',
45
- },
46
- ];
47
-
48
- /**
49
- * llmParseIntent
50
- * @param {*} userPrompts
51
- */
52
- let intentSystemPrompt = null;
53
- exports.llmParseIntent = async (userPrompts) => {
54
- // intent system prompt - 支持版本切换
55
- if (!intentSystemPrompt) {
56
- const promptFile = './prompt-intent.md';
57
- intentSystemPrompt = await readFile(path.resolve(__dirname, promptFile));
58
- }
59
-
60
- // chat config - 新增 confidence 字段支持
61
- chatConfig.responseJsonSchema = zodToJsonSchema(
62
- z.object({
63
- intent: z.enum(['DRAW', 'REJECT']).describe('用户意图:DRAW(绘图)或 REJECT(非绘图)'),
64
- reason: z.string().describe('判断理由(一句话说明)'),
65
- confidence: z.number().min(0).max(1).optional().describe('置信度评分(0.0-1.0),可选字段'),
66
- }),
67
- );
68
-
69
- // chat options
70
- const chatOptions = {
71
- contents: userPrompts,
72
- systemInstruction: intentSystemPrompt,
73
- config: chatConfig,
74
- safetySettings: safetySettings,
75
- };
76
-
77
- // go
78
- return await gemini.chat(chatOptions);
79
- };