intention-coding 0.5.8 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/index.cjs +1127 -754
  2. package/dist/services/change-summarizer/index.d.ts +2 -2
  3. package/dist/services/export-excel/index.d.ts +4 -4
  4. package/dist/services/image-analysis/analyzer.d.ts +2 -11
  5. package/dist/services/image-analysis/analyzer.d.ts.map +1 -1
  6. package/dist/services/image-analysis/index.d.ts +10 -10
  7. package/dist/services/image-analysis/index.d.ts.map +1 -1
  8. package/dist/services/image-recognition-agent/analyzer.d.ts +15 -1
  9. package/dist/services/image-recognition-agent/analyzer.d.ts.map +1 -1
  10. package/dist/services/image-recognition-agent/index.d.ts +2 -1
  11. package/dist/services/image-recognition-agent/index.d.ts.map +1 -1
  12. package/dist/services/image-recognition-agent/processor.d.ts +36 -8
  13. package/dist/services/image-recognition-agent/processor.d.ts.map +1 -1
  14. package/dist/services/image-recognition-agent/types.d.ts +3 -0
  15. package/dist/services/image-recognition-agent/types.d.ts.map +1 -1
  16. package/dist/services/read-excel/index.d.ts +2 -2
  17. package/dist/services/requirement-analyzer/core/document-generator.d.ts +4 -2
  18. package/dist/services/requirement-analyzer/core/document-generator.d.ts.map +1 -1
  19. package/dist/services/requirement-analyzer/core/requirement-analyzer-service.d.ts +1 -0
  20. package/dist/services/requirement-analyzer/core/requirement-analyzer-service.d.ts.map +1 -1
  21. package/dist/services/requirement-analyzer/core/template-selector.d.ts.map +1 -1
  22. package/dist/services/requirement-analyzer/core/types.d.ts +2 -1
  23. package/dist/services/requirement-analyzer/core/types.d.ts.map +1 -1
  24. package/dist/services/requirement-analyzer/index.d.ts +6 -1
  25. package/dist/services/requirement-analyzer/index.d.ts.map +1 -1
  26. package/dist/services/requirement-analyzer/prompt/api-template.d.ts +1 -1
  27. package/dist/services/requirement-analyzer/prompt/api-template.d.ts.map +1 -1
  28. package/dist/services/requirement-analyzer/prompt/html-page-template.d.ts +6 -0
  29. package/dist/services/requirement-analyzer/prompt/html-page-template.d.ts.map +1 -0
  30. package/dist/services/requirement-analyzer/prompt/intelligent-requirement-analysis.d.ts +1 -1
  31. package/dist/services/requirement-analyzer/prompt/intelligent-requirement-analysis.d.ts.map +1 -1
  32. package/dist/services/world2md/index.d.ts +1 -1
  33. package/dist/utils/dify.d.ts.map +1 -1
  34. package/dist/utils/logger.d.ts +1 -1
  35. package/dist/utils/logger.d.ts.map +1 -1
  36. package/dist/utils/openai.d.ts +18 -2
  37. package/dist/utils/openai.d.ts.map +1 -1
  38. package/package.json +1 -2
  39. package/bin/intention-coding.cjs +0 -4
  40. package/dist/services/requirement-analyzer/prompt/app-template.d.ts +0 -2
  41. package/dist/services/requirement-analyzer/prompt/app-template.d.ts.map +0 -1
  42. package/dist/services/requirement-analyzer/prompt/pc-page-template.d.ts +0 -2
  43. package/dist/services/requirement-analyzer/prompt/pc-page-template.d.ts.map +0 -1
  44. package/dist/services/requirement-analyzer/prompt/sdk-template.d.ts +0 -2
  45. package/dist/services/requirement-analyzer/prompt/sdk-template.d.ts.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,5 +1,15 @@
1
1
  "use strict";
2
2
  var __webpack_modules__ = {
3
+ "fs/promises": function(module) {
4
+ module.exports = import("fs/promises").then(function(module) {
5
+ return module;
6
+ });
7
+ },
8
+ path: function(module) {
9
+ module.exports = import("path").then(function(module) {
10
+ return module;
11
+ });
12
+ },
3
13
  "pdf-parse/lib/pdf-parse.js": function(module) {
4
14
  module.exports = import("pdf-parse/lib/pdf-parse.js").then(function(module) {
5
15
  return module;
@@ -60,18 +70,15 @@ var __webpack_exports__ = {};
60
70
  var external_path_default = /*#__PURE__*/ __webpack_require__.n(external_path_namespaceObject);
61
71
  const external_winston_namespaceObject = require("winston");
62
72
  var external_winston_default = /*#__PURE__*/ __webpack_require__.n(external_winston_namespaceObject);
63
- const external_winston_daily_rotate_file_namespaceObject = require("winston-daily-rotate-file");
64
- var external_winston_daily_rotate_file_default = /*#__PURE__*/ __webpack_require__.n(external_winston_daily_rotate_file_namespaceObject);
65
- let logDir;
73
+ const external_os_namespaceObject = require("os");
74
+ var external_os_default = /*#__PURE__*/ __webpack_require__.n(external_os_namespaceObject);
75
+ const isProduction = "production" === process.env.NODE_ENV || !process.env.npm_lifecycle_event;
76
+ const logDir = external_path_default().join(external_os_default().homedir(), ".aico", "logs");
66
77
  try {
67
- if (process.env.LOG_DIR) logDir = process.env.LOG_DIR;
68
- else {
69
- const storageDir = getStorageDir();
70
- logDir = storageDir ? storageDir + '/logs' : './.aico/logs';
71
- }
72
- } catch (error) {
73
- logDir = process.env.TMPDIR || "/tmp/aico-logs";
74
- }
78
+ external_fs_default().mkdirSync(logDir, {
79
+ recursive: true
80
+ });
81
+ } catch {}
75
82
  const levels = {
76
83
  error: 0,
77
84
  warn: 1,
@@ -79,20 +86,6 @@ var __webpack_exports__ = {};
79
86
  debug: 3,
80
87
  verbose: 4
81
88
  };
82
- const colors = {
83
- error: 'red',
84
- warn: 'yellow',
85
- info: 'green',
86
- debug: 'blue',
87
- verbose: 'cyan'
88
- };
89
- external_winston_default().addColors(colors);
90
- const consoleFormat = external_winston_default().format.combine(external_winston_default().format.timestamp({
91
- format: 'YYYY-MM-DD HH:mm:ss'
92
- }), external_winston_default().format.colorize(), external_winston_default().format.printf(({ timestamp, level, message, ...meta })=>{
93
- const metaStr = Object.keys(meta).length ? JSON.stringify(meta, null, 2) : '';
94
- return `${timestamp} [${level}]: ${message} ${metaStr}`;
95
- }));
96
89
  const fileFormat = external_winston_default().format.combine(external_winston_default().format.timestamp(), external_winston_default().format.errors({
97
90
  stack: true
98
91
  }), external_winston_default().format.json());
@@ -103,11 +96,11 @@ var __webpack_exports__ = {};
103
96
  const error = meta.error || meta;
104
97
  const errorInfo = {
105
98
  timestamp,
106
- level: level || 'error',
107
- message: message || 'Uncaught Exception',
108
- stack: stack || error && error.stack || 'No stack trace available',
99
+ level: level || "error",
100
+ message: message || "Uncaught Exception",
101
+ stack: stack || error && error.stack || "No stack trace available",
109
102
  error: {
110
- name: error && error.name || 'Error',
103
+ name: error && error.name || "Error",
111
104
  message: error && error.message || String(error || message),
112
105
  code: error && error.code || meta.code,
113
106
  ...meta
@@ -115,50 +108,48 @@ var __webpack_exports__ = {};
115
108
  };
116
109
  return JSON.stringify(errorInfo, null, 2);
117
110
  }));
118
- const transports = [
119
- new (external_winston_default()).transports.Console({
120
- format: consoleFormat,
121
- level: 'verbose'
122
- })
123
- ];
124
- if (logDir) transports.push(new (external_winston_daily_rotate_file_default())({
125
- filename: external_path_default().join(logDir, 'application-%DATE%.log'),
126
- datePattern: 'YYYY-MM-DD',
127
- zippedArchive: true,
128
- maxSize: '2m',
129
- maxFiles: '1d',
111
+ const transports = [];
112
+ transports.push(new (external_winston_default()).transports.File({
113
+ filename: external_path_default().join(logDir, "error.log"),
114
+ level: "error",
130
115
  format: fileFormat,
131
- level: 'info'
116
+ maxsize: 5242880,
117
+ maxFiles: 1,
118
+ tailable: true
119
+ }));
120
+ if (!isProduction) transports.push(new (external_winston_default()).transports.File({
121
+ filename: external_path_default().join(logDir, "app.log"),
122
+ level: "info",
123
+ format: fileFormat,
124
+ maxsize: 5242880,
125
+ maxFiles: 1,
126
+ tailable: true
132
127
  }));
133
128
  const logger = external_winston_default().createLogger({
134
- level: 'debug',
129
+ level: isProduction ? "error" : "debug",
135
130
  levels,
136
131
  format: external_winston_default().format.combine(external_winston_default().format.errors({
137
132
  stack: true
138
133
  }), external_winston_default().format.splat()),
139
134
  transports,
140
- exceptionHandlers: logDir ? [
141
- new (external_winston_daily_rotate_file_default())({
142
- filename: external_path_default().join(logDir, 'exceptions-%DATE%.log'),
143
- datePattern: 'YYYY-MM-DD',
144
- zippedArchive: true,
145
- maxSize: '1m',
146
- maxFiles: '1d',
147
- format: exceptionFormat
135
+ exceptionHandlers: [
136
+ new (external_winston_default()).transports.File({
137
+ filename: external_path_default().join(logDir, "error.log"),
138
+ format: exceptionFormat,
139
+ maxsize: 5242880,
140
+ maxFiles: 1
148
141
  })
149
- ] : [],
150
- rejectionHandlers: logDir ? [
151
- new (external_winston_daily_rotate_file_default())({
152
- filename: external_path_default().join(logDir, 'rejections-%DATE%.log'),
153
- datePattern: 'YYYY-MM-DD',
154
- zippedArchive: true,
155
- maxSize: '1m',
156
- maxFiles: '1d',
157
- format: exceptionFormat
142
+ ],
143
+ rejectionHandlers: [
144
+ new (external_winston_default()).transports.File({
145
+ filename: external_path_default().join(logDir, "error.log"),
146
+ format: exceptionFormat,
147
+ maxsize: 5242880,
148
+ maxFiles: 1
158
149
  })
159
- ] : []
150
+ ]
160
151
  });
161
- process.on('SIGINT', ()=>{
152
+ process.on("SIGINT", ()=>{
162
153
  logger.end(()=>{
163
154
  logger.info("\u65E5\u5FD7\u5DF2\u5173\u95ED");
164
155
  process.exit(0);
@@ -316,7 +307,6 @@ var __webpack_exports__ = {};
316
307
  var external_mammoth_default = /*#__PURE__*/ __webpack_require__.n(external_mammoth_namespaceObject);
317
308
  const external_html_to_md_namespaceObject = require("html-to-md");
318
309
  var external_html_to_md_default = /*#__PURE__*/ __webpack_require__.n(external_html_to_md_namespaceObject);
319
- const external_os_namespaceObject = require("os");
320
310
  const sanitizeFileName = (input)=>input.replace(/[\\/:*?"<>|\n\r#%&]/g, '').trim().replace(/\s+/g, '_').replace(/_+/g, '_').replace(/^_+|_+$/g, '');
321
311
  function normalizePath(filePath) {
322
312
  if (!filePath || 'string' != typeof filePath) throw new Error("\u6587\u4EF6\u8DEF\u5F84\u4E0D\u80FD\u4E3A\u7A7A");
@@ -4199,6 +4189,207 @@ var __webpack_exports__ = {};
4199
4189
  ErrorCodes["UNSUPPORTED_REQUIREMENT_TYPE"] = "UNSUPPORTED_REQUIREMENT_TYPE";
4200
4190
  return ErrorCodes;
4201
4191
  }({});
4192
+ async function invokeFlow(params, streamCb) {
4193
+ const { appid = "app-ESTcrkOPOmkxdrO0120mE4s1", data, timeout = 1800000 } = params;
4194
+ const controller = new AbortController();
4195
+ const signal = controller.signal;
4196
+ if ("undefined" == typeof ReadableStream) throw new Error("ReadableStream is not supported in this environment");
4197
+ const fetchData = async (retryCount = 0)=>{
4198
+ try {
4199
+ const fetchOptions = {
4200
+ method: "POST",
4201
+ headers: {
4202
+ Authorization: `Bearer ${appid}`,
4203
+ "Content-Type": "application/json"
4204
+ },
4205
+ body: JSON.stringify({
4206
+ inputs: data,
4207
+ response_mode: "streaming",
4208
+ user: "aico-mcp"
4209
+ }),
4210
+ signal
4211
+ };
4212
+ const res = await fetch("http://11.0.166.20:9199/v1/workflows/run", fetchOptions);
4213
+ if (!res.ok) {
4214
+ if (retryCount < 3) {
4215
+ await new Promise((resolve)=>setTimeout(resolve, 1000));
4216
+ return fetchData(retryCount + 1);
4217
+ }
4218
+ const errorResponse = await res.text();
4219
+ throw new Error(`\u{7F51}\u{7EDC}\u{54CD}\u{5E94}\u{5F02}\u{5E38}: ${res.status} ${res.statusText} - ${errorResponse}`);
4220
+ }
4221
+ if (res.ok) if (res.body) {
4222
+ const reader = res.body.getReader();
4223
+ const decoder = new TextDecoder("utf-8");
4224
+ if (streamCb) return void new ReadableStream({
4225
+ start (controller) {
4226
+ let buffer = "";
4227
+ function push() {
4228
+ reader.read().then(({ done, value })=>{
4229
+ if (done) {
4230
+ const lines = buffer.split("\n");
4231
+ for (const line of lines)handleLine(line, controller);
4232
+ if (streamCb) streamCb({
4233
+ isEnd: true
4234
+ });
4235
+ controller.close();
4236
+ return;
4237
+ }
4238
+ const chunkText = decoder.decode(value, {
4239
+ stream: true
4240
+ });
4241
+ buffer += chunkText;
4242
+ const lines = buffer.split("\n");
4243
+ for(let i = 0; i < lines.length - 1; i++)handleLine(lines[i], controller);
4244
+ buffer = lines[lines.length - 1];
4245
+ push();
4246
+ });
4247
+ }
4248
+ function handleLine(line, controller) {
4249
+ line = line.trim();
4250
+ if (line.startsWith("data:")) {
4251
+ const dataStr = line.slice(5).trim();
4252
+ if ("" === dataStr) return;
4253
+ try {
4254
+ const jsonData = JSON.parse(dataStr);
4255
+ if (jsonData.data?.text) {
4256
+ const wrappedData = {
4257
+ content: jsonData.data.text.toString(),
4258
+ controller
4259
+ };
4260
+ if (streamCb) streamCb(wrappedData);
4261
+ }
4262
+ } catch (e) {
4263
+ console.error("\u89E3\u6790JSON\u5931\u8D25:", e);
4264
+ }
4265
+ }
4266
+ }
4267
+ push();
4268
+ }
4269
+ });
4270
+ {
4271
+ let buffer = "";
4272
+ let accumulatedText = "";
4273
+ let isResponseEnded = false;
4274
+ const readAll = async ()=>{
4275
+ const { done, value } = await reader.read();
4276
+ if (done) {
4277
+ if (!isResponseEnded) throw new Error("\u54CD\u5E94\u63D0\u524D\u7ED3\u675F");
4278
+ return accumulatedText;
4279
+ }
4280
+ const chunkText = decoder.decode(value, {
4281
+ stream: true
4282
+ });
4283
+ buffer += chunkText;
4284
+ const lines = buffer.split("\n");
4285
+ for(let i = 0; i < lines.length - 1; i++){
4286
+ const line = lines[i].trim();
4287
+ if (!line.startsWith("data:")) continue;
4288
+ const dataStr = line.slice(5).trim();
4289
+ if ("" !== dataStr) try {
4290
+ const jsonData = JSON.parse(dataStr);
4291
+ switch(jsonData.event){
4292
+ case "message":
4293
+ case "agent_message":
4294
+ case "text_chunk":
4295
+ {
4296
+ const content = "text_chunk" === jsonData.event ? jsonData.data.text : jsonData.answer;
4297
+ accumulatedText += content;
4298
+ break;
4299
+ }
4300
+ case "workflow_finished":
4301
+ if (jsonData.data?.outputs?.text) accumulatedText = jsonData.data.outputs.text;
4302
+ else if (jsonData.data?.outputs) {
4303
+ const outputs = jsonData.data.outputs;
4304
+ const textValue = Object.values(outputs).find((v)=>"string" == typeof v && v.length > 0);
4305
+ if (textValue) accumulatedText = textValue;
4306
+ }
4307
+ isResponseEnded = true;
4308
+ break;
4309
+ case "message_end":
4310
+ isResponseEnded = true;
4311
+ break;
4312
+ case "error":
4313
+ throw new Error(`\u{670D}\u{52A1}\u{5668}\u{9519}\u{8BEF}: ${jsonData.code}, ${jsonData.message}`);
4314
+ default:
4315
+ break;
4316
+ }
4317
+ } catch (e) {
4318
+ throw new Error("\u89E3\u6790JSON\u5931\u8D25: " + e.message);
4319
+ }
4320
+ }
4321
+ buffer = lines[lines.length - 1];
4322
+ return readAll();
4323
+ };
4324
+ return readAll();
4325
+ }
4326
+ } else throw new Error("\u54CD\u5E94\u4F53\u4E3A\u7A7A");
4327
+ {
4328
+ const errorResponse = await res.text();
4329
+ throw new Error(`\u{7F51}\u{7EDC}\u{54CD}\u{5E94}\u{5F02}\u{5E38}: ${res.status} ${res.statusText} - ${errorResponse}`);
4330
+ }
4331
+ } catch (error) {
4332
+ if ("AbortError" === error.name) throw new Error("\u8BF7\u6C42\u5DF2\u88AB\u4E2D\u6B62\uFF0C\u8D85\u65F6");
4333
+ throw error;
4334
+ }
4335
+ };
4336
+ try {
4337
+ const result = await Promise.race([
4338
+ fetchData(),
4339
+ new Promise((_, reject)=>{
4340
+ setTimeout(()=>{
4341
+ controller.abort();
4342
+ reject(new Error("\u8BF7\u6C42\u8D85\u65F6"));
4343
+ }, timeout);
4344
+ })
4345
+ ]);
4346
+ if (streamCb) return;
4347
+ return result;
4348
+ } catch (error) {
4349
+ controller.abort();
4350
+ throw error;
4351
+ }
4352
+ }
4353
+ async function uploadFile(params) {
4354
+ const { appid, filePath, user = "aico-mcp" } = params;
4355
+ try {
4356
+ const fileBuffer = await external_fs_default().promises.readFile(filePath);
4357
+ const fileName = external_path_default().basename(filePath);
4358
+ const fileExtension = external_path_default().extname(filePath).toLowerCase().slice(1);
4359
+ const mimeTypes = {
4360
+ png: "image/png",
4361
+ jpeg: "image/jpeg",
4362
+ jpg: "image/jpeg",
4363
+ webp: "image/webp",
4364
+ gif: "image/gif"
4365
+ };
4366
+ const mimeType = mimeTypes[fileExtension] || "application/octet-stream";
4367
+ const formData = new FormData();
4368
+ formData.append("file", new Blob([
4369
+ fileBuffer.buffer
4370
+ ], {
4371
+ type: mimeType
4372
+ }), fileName);
4373
+ formData.append("user", user);
4374
+ const response = await fetch("http://11.0.166.20:9199/v1/files/upload", {
4375
+ method: "POST",
4376
+ headers: {
4377
+ Authorization: `Bearer ${appid}`
4378
+ },
4379
+ body: formData
4380
+ });
4381
+ if (!response.ok) {
4382
+ const errorText = await response.text();
4383
+ throw new Error(`\u{6587}\u{4EF6}\u{4E0A}\u{4F20}\u{5931}\u{8D25}: ${response.status} ${response.statusText} - ${errorText}`);
4384
+ }
4385
+ const result = await response.json();
4386
+ if (!result.id || !result.name) throw new Error("\u65E0\u6548\u7684\u6587\u4EF6\u4E0A\u4F20\u54CD\u5E94\u683C\u5F0F");
4387
+ return result;
4388
+ } catch (error) {
4389
+ if (error instanceof Error) throw new Error(`\u{6587}\u{4EF6}\u{4E0A}\u{4F20}\u{5931}\u{8D25}: ${error.message}`);
4390
+ throw new Error("\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25: \u672A\u77E5\u9519\u8BEF");
4391
+ }
4392
+ }
4202
4393
  class OpenAIService {
4203
4394
  qwenConfig = {
4204
4395
  apiKey: "sk-95b0bc60b7464bbbafd64edc2f5bab14",
@@ -4220,6 +4411,10 @@ var __webpack_exports__ = {};
4220
4411
  baseUrl: "https://api.lkeap.cloud.tencent.com/v1/chat/completions",
4221
4412
  model: "deepseek-v3.1-terminus"
4222
4413
  };
4414
+ difyConfig = {
4415
+ apiKey: "app-AvlLh0nfN4l9oz1MSW4sEAQ6",
4416
+ baseUrl: "http://11.0.166.20:9199/v1"
4417
+ };
4223
4418
  constructor(){}
4224
4419
  async generateText(params) {
4225
4420
  const { prompt, temperature, system_prompt } = params;
@@ -4576,23 +4771,115 @@ var __webpack_exports__ = {};
4576
4771
  }
4577
4772
  }
4578
4773
  }
4774
+ async analyzeImageWithPath(params) {
4775
+ const { prompt, image_path, system_prompt } = params;
4776
+ logger.info("[OpenAI] analyzeImageWithPath \u88AB\u8C03\u7528", {
4777
+ image_path,
4778
+ prompt_length: prompt.length
4779
+ });
4780
+ try {
4781
+ logger.info("[OpenAI] \u5F00\u59CB\u4E0A\u4F20\u6587\u4EF6\u5230 Dify", {
4782
+ image_path
4783
+ });
4784
+ const uploadResult = await uploadFile({
4785
+ appid: this.difyConfig.apiKey,
4786
+ filePath: image_path,
4787
+ user: "aico-mcp"
4788
+ });
4789
+ logger.info("[OpenAI] \u6587\u4EF6\u4E0A\u4F20\u6210\u529F", {
4790
+ upload_file_id: uploadResult.id
4791
+ });
4792
+ const workflowData = {
4793
+ imagePath: {
4794
+ type: "image",
4795
+ transfer_method: "local_file",
4796
+ upload_file_id: uploadResult.id
4797
+ },
4798
+ context: prompt
4799
+ };
4800
+ logger.info("[OpenAI] \u5F00\u59CB\u8C03\u7528 Dify \u5DE5\u4F5C\u6D41");
4801
+ const workflowResponse = await invokeFlow({
4802
+ appid: this.difyConfig.apiKey,
4803
+ data: workflowData,
4804
+ timeout: 120000
4805
+ });
4806
+ logger.info("[OpenAI] Dify \u5DE5\u4F5C\u6D41\u8C03\u7528\u6210\u529F", {
4807
+ response_type: typeof workflowResponse,
4808
+ response_preview: "string" == typeof workflowResponse ? workflowResponse.substring(0, 200) : JSON.stringify(workflowResponse).substring(0, 500)
4809
+ });
4810
+ let summary = "";
4811
+ if ("string" == typeof workflowResponse && workflowResponse.length > 0) summary = workflowResponse;
4812
+ else if (workflowResponse?.outputs?.text) summary = workflowResponse.outputs.text;
4813
+ else if (workflowResponse?.data?.outputs?.text) summary = workflowResponse.data.outputs.text;
4814
+ else if (workflowResponse?.data?.text) summary = workflowResponse.data.text;
4815
+ else if (workflowResponse?.answer) summary = workflowResponse.answer;
4816
+ else if (workflowResponse?.status === "failed") throw new Error(`Dify\u{5DE5}\u{4F5C}\u{6D41}\u{6267}\u{884C}\u{5931}\u{8D25}: ${workflowResponse.error || "\u672A\u77E5\u9519\u8BEF"}`);
4817
+ if (!summary || 0 === summary.length) {
4818
+ logger.error("[OpenAI] Dify \u54CD\u5E94\u89E3\u6790\u5931\u8D25\uFF0C\u65E0\u6CD5\u63D0\u53D6\u6587\u672C\u5185\u5BB9", {
4819
+ response: JSON.stringify(workflowResponse)
4820
+ });
4821
+ throw new Error("Dify\u5DE5\u4F5C\u6D41\u54CD\u5E94\u4E2D\u672A\u627E\u5230\u6709\u6548\u6587\u672C\u5185\u5BB9");
4822
+ }
4823
+ logger.info("[OpenAI] Dify \u5206\u6790\u5B8C\u6210", {
4824
+ summary_length: summary.length
4825
+ });
4826
+ return summary;
4827
+ } catch (difyError) {
4828
+ logger.error("[OpenAI] Dify \u8C03\u7528\u5931\u8D25\uFF0C\u56DE\u9000\u5230\u5176\u4ED6\u670D\u52A1", {
4829
+ error: difyError instanceof Error ? difyError.message : String(difyError)
4830
+ });
4831
+ const fs = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "fs/promises"));
4832
+ const path = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "path"));
4833
+ const imageBuffer = await fs.readFile(image_path);
4834
+ const base64 = imageBuffer.toString("base64");
4835
+ const ext = path.extname(image_path).toLowerCase();
4836
+ let mimeType = "image/jpeg";
4837
+ switch(ext){
4838
+ case ".png":
4839
+ mimeType = "image/png";
4840
+ break;
4841
+ case ".gif":
4842
+ mimeType = "image/gif";
4843
+ break;
4844
+ case ".webp":
4845
+ mimeType = "image/webp";
4846
+ break;
4847
+ case ".jpg":
4848
+ case ".jpeg":
4849
+ mimeType = "image/jpeg";
4850
+ break;
4851
+ }
4852
+ const image_base64 = `data:${mimeType};base64,${base64}`;
4853
+ return this.analyzeImage({
4854
+ prompt,
4855
+ image_base64,
4856
+ system_prompt
4857
+ });
4858
+ }
4859
+ }
4579
4860
  async analyzeImage(params) {
4580
4861
  const { prompt, image_base64, system_prompt } = params;
4581
- let lastError = null;
4582
4862
  try {
4583
- const response = await fetch(this.glm4vConfig.baseUrl, {
4863
+ const controller = new AbortController();
4864
+ const timeoutId = setTimeout(()=>controller.abort(), 20000);
4865
+ const response = await fetch(this.kimiConfig.baseUrl, {
4584
4866
  method: "POST",
4585
4867
  headers: {
4586
4868
  "Content-Type": "application/json",
4587
- Authorization: `Bearer ${this.glm4vConfig.apiKey}`
4869
+ Authorization: `Bearer ${this.kimiConfig.apiKey}`
4588
4870
  },
4589
4871
  body: JSON.stringify({
4590
- model: this.glm4vConfig.model,
4872
+ model: this.kimiConfig.model,
4591
4873
  messages: [
4592
4874
  ...system_prompt ? [
4593
4875
  {
4594
4876
  role: "system",
4595
- content: system_prompt
4877
+ content: [
4878
+ {
4879
+ type: "text",
4880
+ text: system_prompt
4881
+ }
4882
+ ]
4596
4883
  }
4597
4884
  ] : [],
4598
4885
  {
@@ -4612,36 +4899,34 @@ var __webpack_exports__ = {};
4612
4899
  }
4613
4900
  ],
4614
4901
  stream: false
4615
- })
4902
+ }),
4903
+ signal: controller.signal
4616
4904
  });
4905
+ clearTimeout(timeoutId);
4617
4906
  if (!response.ok) {
4618
4907
  const errorText = await response.text();
4619
- throw new Error(`GLM-4V API error: ${response.status} ${response.statusText} - ${errorText}`);
4908
+ throw new Error(`Kimi Vision API error: ${response.status} ${response.statusText} - ${errorText}`);
4620
4909
  }
4621
4910
  const data = await response.json();
4622
- if (!data.choices || 0 === data.choices.length) throw new Error("No choices returned from GLM-4V API");
4911
+ if (!data.choices || 0 === data.choices.length) throw new Error("No choices returned from Kimi Vision API");
4623
4912
  return data.choices[0].message.content;
4624
- } catch (error) {
4625
- lastError = error;
4913
+ } catch (kimiError) {
4626
4914
  try {
4627
- const response = await fetch(this.kimiConfig.baseUrl, {
4915
+ const controller = new AbortController();
4916
+ const timeoutId = setTimeout(()=>controller.abort(), 15000);
4917
+ const response = await fetch(this.glm4vConfig.baseUrl, {
4628
4918
  method: "POST",
4629
4919
  headers: {
4630
4920
  "Content-Type": "application/json",
4631
- Authorization: `Bearer ${this.kimiConfig.apiKey}`
4921
+ Authorization: `Bearer ${this.glm4vConfig.apiKey}`
4632
4922
  },
4633
4923
  body: JSON.stringify({
4634
- model: this.kimiConfig.model,
4924
+ model: this.glm4vConfig.model,
4635
4925
  messages: [
4636
4926
  ...system_prompt ? [
4637
4927
  {
4638
4928
  role: "system",
4639
- content: [
4640
- {
4641
- type: "text",
4642
- text: system_prompt
4643
- }
4644
- ]
4929
+ content: system_prompt
4645
4930
  }
4646
4931
  ] : [],
4647
4932
  {
@@ -4661,41 +4946,57 @@ var __webpack_exports__ = {};
4661
4946
  }
4662
4947
  ],
4663
4948
  stream: false
4664
- })
4949
+ }),
4950
+ signal: controller.signal
4665
4951
  });
4952
+ clearTimeout(timeoutId);
4666
4953
  if (!response.ok) {
4667
4954
  const errorText = await response.text();
4668
- throw new Error(`Kimi Vision API error: ${response.status} ${response.statusText} - ${errorText}`);
4955
+ throw new Error(`GLM-4V API error: ${response.status} ${response.statusText} - ${errorText}`);
4669
4956
  }
4670
4957
  const data = await response.json();
4671
- if (!data.choices || 0 === data.choices.length) throw new Error("No choices returned from Kimi Vision API");
4958
+ if (!data.choices || 0 === data.choices.length) throw new Error("No choices returned from GLM-4V API");
4672
4959
  return data.choices[0].message.content;
4673
- } catch (kimiError) {
4674
- throw lastError;
4960
+ } catch (glmError) {
4961
+ throw new Error(`All vision services failed. Kimi: ${kimiError instanceof Error ? kimiError.message : String(kimiError)}, GLM-4V: ${glmError instanceof Error ? glmError.message : String(glmError)}`);
4675
4962
  }
4676
4963
  }
4677
4964
  }
4678
4965
  }
4679
4966
  const openAIService = new OpenAIService();
4680
- const intelligentRequirementAnalysisPrompt = `\u{4F60}\u{662F}\u{8F6F}\u{4EF6}\u{9700}\u{6C42}\u{5206}\u{6790}\u{5E08}\u{FF0C}\u{5FEB}\u{901F}\u{8BC6}\u{522B}\u{9700}\u{6C42}\u{7C7B}\u{578B}\u{5E76}\u{7CBE}\u{786E}\u{63D0}\u{53D6}2-5\u{4E2A}\u{6838}\u{5FC3}\u{529F}\u{80FD}\u{70B9}\u{3002}
4967
+ const intelligentRequirementAnalysisPrompt = `\u{4F60}\u{662F}\u{8D44}\u{6DF1}\u{8F6F}\u{4EF6}\u{9700}\u{6C42}\u{5206}\u{6790}\u{5E08}\u{FF0C}\u{8D1F}\u{8D23}\u{6DF1}\u{5EA6}\u{5206}\u{6790}\u{7528}\u{6237}\u{9700}\u{6C42}\u{5E76}\u{63D0}\u{53D6}\u{7ED3}\u{6784}\u{5316}\u{4FE1}\u{606F}\u{FF0C}\u{4E3A}\u{540E}\u{7EED}\u{6587}\u{6863}\u{751F}\u{6210}\u{63D0}\u{4F9B}\u{5B8C}\u{6574}\u{7684}\u{4E0A}\u{4E0B}\u{6587}\u{3002}
4681
4968
 
4682
4969
  **\u{8F93}\u{5165}\u{5185}\u{5BB9}**:
4683
4970
  {inputContent}
4684
4971
 
4685
- ## \u{9700}\u{6C42}\u{7C7B}\u{578B}\u{8BC6}\u{522B}
4972
+ ## \u{5206}\u{6790}\u{4EFB}\u{52A1}
4973
+
4974
+ \u{4F60}\u{9700}\u{8981}\u{5B8C}\u{6210}\u{4EE5}\u{4E0B}\u{5206}\u{6790}\u{4EFB}\u{52A1}\u{FF0C}\u{4E3A}MCP\u{5BA2}\u{6237}\u{7AEF}\u{751F}\u{6210}\u{6280}\u{672F}\u{6587}\u{6863}\u{63D0}\u{4F9B}\u{5145}\u{5206}\u{7684}\u{4E0A}\u{4E0B}\u{6587}\u{FF1A}
4686
4975
 
4687
- **\u{63A5}\u{53E3}**: API\u{3001}REST\u{3001}GraphQL\u{3001}\u{5FAE}\u{670D}\u{52A1}\u{3001}\u{540E}\u{7AEF}\u{670D}\u{52A1} \u{2192} \u{6570}\u{636E}\u{4EA4}\u{4E92}\u{3001}\u{4E1A}\u{52A1}\u{903B}\u{8F91}\u{3001}\u{7CFB}\u{7EDF}\u{96C6}\u{6210}
4688
- **PC\u{9875}\u{9762}**: \u{9875}\u{9762}\u{3001}UI\u{3001}\u{7F51}\u{9875}\u{3001}\u{524D}\u{7AEF}\u{3001}\u{7BA1}\u{7406}\u{540E}\u{53F0} \u{2192} \u{7528}\u{6237}\u{754C}\u{9762}\u{3001}\u{8868}\u{5355}\u{64CD}\u{4F5C}\u{3001}\u{6570}\u{636E}\u{5C55}\u{793A}
4689
- **APP**: \u{79FB}\u{52A8}\u{5E94}\u{7528}\u{3001}iOS\u{3001}Android\u{3001}\u{5C0F}\u{7A0B}\u{5E8F} \u{2192} \u{79FB}\u{52A8}\u{7AEF}\u{529F}\u{80FD}\u{3001}\u{624B}\u{52BF}\u{64CD}\u{4F5C}\u{3001}\u{8BBE}\u{5907}\u{7279}\u{6027}
4690
- **SDK\u{96C6}\u{6210}**: \u{7B2C}\u{4E09}\u{65B9}\u{3001}\u{5BF9}\u{63A5}\u{3001}\u{652F}\u{4ED8}\u{3001}\u{5730}\u{56FE}\u{3001}\u{63A8}\u{9001} \u{2192} \u{5916}\u{90E8}\u{670D}\u{52A1}\u{5BF9}\u{63A5}\u{3001}\u{914D}\u{7F6E}\u{53C2}\u{6570}\u{3001}\u{56DE}\u{8C03}\u{5904}\u{7406}
4691
- **\u{6DF7}\u{5408}**: \u{5305}\u{542B}\u{591A}\u{79CD}\u{7C7B}\u{578B}\u{7279}\u{5F81}
4976
+ ### 1. \u{9700}\u{6C42}\u{7C7B}\u{578B}\u{8BC6}\u{522B}
4692
4977
 
4693
- ## \u{529F}\u{80FD}\u{70B9}\u{63D0}\u{53D6}\u{539F}\u{5219}
4978
+ \u{6839}\u{636E}\u{5173}\u{952E}\u{8BCD}\u{548C}\u{4E1A}\u{52A1}\u{573A}\u{666F}\u{8BC6}\u{522B}\u{9700}\u{6C42}\u{7C7B}\u{578B}\u{FF1A}
4979
+ - **\u{63A5}\u{53E3}(API)**: API\u{3001}REST\u{3001}GraphQL\u{3001}\u{5FAE}\u{670D}\u{52A1}\u{3001}\u{540E}\u{7AEF}\u{670D}\u{52A1}\u{3001}\u{6570}\u{636E}\u{63A5}\u{53E3}
4980
+ - **PC\u{9875}\u{9762}**: \u{9875}\u{9762}\u{3001}UI\u{3001}\u{7F51}\u{9875}\u{3001}\u{524D}\u{7AEF}\u{3001}\u{7BA1}\u{7406}\u{540E}\u{53F0}\u{3001}Web\u{7AEF}
4981
+ - **APP**: \u{79FB}\u{52A8}\u{5E94}\u{7528}\u{3001}iOS\u{3001}Android\u{3001}\u{5C0F}\u{7A0B}\u{5E8F}\u{3001}\u{79FB}\u{52A8}\u{7AEF}
4982
+ - **SDK\u{96C6}\u{6210}**: \u{7B2C}\u{4E09}\u{65B9}\u{3001}\u{5BF9}\u{63A5}\u{3001}\u{652F}\u{4ED8}\u{3001}\u{5730}\u{56FE}\u{3001}\u{63A8}\u{9001}\u{3001}SDK
4694
4983
 
4695
- 1. \u{7CBE}\u{786E}\u{6027}\u{FF1A}\u{53EA}\u{63D0}\u{53D6}\u{6838}\u{5FC3}\u{72EC}\u{7ACB}\u{529F}\u{80FD}\u{70B9}\u{FF08}2-5\u{4E2A}\u{FF09}
4696
- 2. \u{4E1A}\u{52A1}\u{4EF7}\u{503C}\u{FF1A}\u{6BCF}\u{4E2A}\u{529F}\u{80FD}\u{70B9}\u{6709}\u{660E}\u{786E}\u{4E1A}\u{52A1}\u{4EF7}\u{503C}
4697
- 3. \u{6280}\u{672F}\u{5339}\u{914D}\u{FF1A}\u{529F}\u{80FD}\u{70B9}\u{4E0E}\u{9700}\u{6C42}\u{7C7B}\u{578B}\u{9AD8}\u{5EA6}\u{5339}\u{914D}
4698
- 4. \u{907F}\u{514D}\u{8FC7}\u{5EA6}\u{62C6}\u{5206}\u{FF1A}\u{4FDD}\u{6301}\u{529F}\u{80FD}\u{5B8C}\u{6574}\u{6027}
4984
+ ### 2. \u{6DF1}\u{5EA6}\u{9700}\u{6C42}\u{5206}\u{6790}
4985
+
4986
+ \u{5BF9}\u{6BCF}\u{4E2A}\u{529F}\u{80FD}\u{70B9}\u{8FDB}\u{884C}\u{6DF1}\u{5EA6}\u{5206}\u{6790}\u{FF0C}\u{63D0}\u{53D6}\u{FF1A}
4987
+ - **\u{4E1A}\u{52A1}\u{80CC}\u{666F}**: \u{4E3A}\u{4EC0}\u{4E48}\u{9700}\u{8981}\u{8FD9}\u{4E2A}\u{529F}\u{80FD}
4988
+ - **\u{6838}\u{5FC3}\u{6D41}\u{7A0B}**: \u{4E3B}\u{8981}\u{7684}\u{4E1A}\u{52A1}\u{6D41}\u{7A0B}\u{6B65}\u{9AA4}
4989
+ - **\u{6570}\u{636E}\u{5B9E}\u{4F53}**: \u{6D89}\u{53CA}\u{7684}\u{6570}\u{636E}\u{5BF9}\u{8C61}\u{548C}\u{5B57}\u{6BB5}
4990
+ - **\u{4EA4}\u{4E92}\u{903B}\u{8F91}**: \u{7528}\u{6237}\u{64CD}\u{4F5C}\u{548C}\u{7CFB}\u{7EDF}\u{54CD}\u{5E94}
4991
+ - **\u{5F02}\u{5E38}\u{573A}\u{666F}**: \u{53EF}\u{80FD}\u{7684}\u{9519}\u{8BEF}\u{60C5}\u{51B5}\u{548C}\u{5904}\u{7406}\u{65B9}\u{5F0F}
4992
+
4993
+ ### 3. \u{6280}\u{672F}\u{4E0A}\u{4E0B}\u{6587}\u{63D0}\u{53D6}
4994
+
4995
+ \u{4ECE}\u{9879}\u{76EE}\u{4FE1}\u{606F}\u{4E2D}\u{63D0}\u{53D6}\u{FF1A}
4996
+ - \u{6280}\u{672F}\u{6808}\u{548C}\u{6846}\u{67B6}
4997
+ - \u{73B0}\u{6709}\u{7684}\u{4EE3}\u{7801}\u{7ED3}\u{6784}
4998
+ - \u{4F9D}\u{8D56}\u{5173}\u{7CFB}
4999
+ - \u{8BBE}\u{8BA1}\u{89C4}\u{8303}
4699
5000
 
4700
5001
  ## \u{8F93}\u{51FA}\u{683C}\u{5F0F}
4701
5002
 
@@ -4707,14 +5008,36 @@ var __webpack_exports__ = {};
4707
5008
  "requirementType": "\u{63A5}\u{53E3}|PC\u{9875}\u{9762}|APP|SDK\u{96C6}\u{6210}|\u{6DF7}\u{5408}\u{7C7B}\u{578B}",
4708
5009
  "primaryTechnology": "\u{4E3B}\u{8981}\u{6280}\u{672F}\u{6808}\u{63CF}\u{8FF0}",
4709
5010
  "confidence": "high|medium|low",
5011
+ "businessContext": {
5012
+ "background": "\u{4E1A}\u{52A1}\u{80CC}\u{666F}\u{63CF}\u{8FF0}",
5013
+ "objectives": ["\u{4E1A}\u{52A1}\u{76EE}\u{6807}1", "\u{4E1A}\u{52A1}\u{76EE}\u{6807}2"],
5014
+ "stakeholders": ["\u{6D89}\u{53CA}\u{7684}\u{89D2}\u{8272}1", "\u{6D89}\u{53CA}\u{7684}\u{89D2}\u{8272}2"]
5015
+ },
4710
5016
  "requirements": [
4711
5017
  {
4712
5018
  "id": "req_001",
4713
5019
  "title": "\u{529F}\u{80FD}\u{70B9}\u{540D}\u{79F0}",
4714
- "fullContent": "\u{529F}\u{80FD}\u{70B9}\u{7684}\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}",
5020
+ "fullContent": "\u{529F}\u{80FD}\u{70B9}\u{7684}\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{FF0C}\u{5305}\u{542B}\u{5B8C}\u{6574}\u{7684}\u{4E1A}\u{52A1}\u{903B}\u{8F91}",
4715
5021
  "priority": "high|medium|low",
4716
5022
  "complexity": "\u{7B80}\u{5355}|\u{4E2D}\u{7B49}|\u{590D}\u{6742}",
4717
- "type": "\u{63A5}\u{53E3}|PC\u{9875}\u{9762}|APP|SDK\u{96C6}\u{6210}"
5023
+ "type": "\u{63A5}\u{53E3}|PC\u{9875}\u{9762}|APP|SDK\u{96C6}\u{6210}",
5024
+ "businessFlow": {
5025
+ "preconditions": ["\u{524D}\u{7F6E}\u{6761}\u{4EF6}1"],
5026
+ "mainFlow": ["\u{6B65}\u{9AA4}1", "\u{6B65}\u{9AA4}2", "\u{6B65}\u{9AA4}3"],
5027
+ "alternativeFlows": ["\u{66FF}\u{4EE3}\u{6D41}\u{7A0B}1"],
5028
+ "exceptionFlows": ["\u{5F02}\u{5E38}\u{5904}\u{7406}1"]
5029
+ },
5030
+ "dataEntities": [
5031
+ {
5032
+ "name": "\u{5B9E}\u{4F53}\u{540D}\u{79F0}",
5033
+ "fields": [
5034
+ {"name": "\u{5B57}\u{6BB5}\u{540D}", "type": "\u{7C7B}\u{578B}", "required": true, "description": "\u{8BF4}\u{660E}"}
5035
+ ]
5036
+ }
5037
+ ],
5038
+ "interactions": [
5039
+ {"trigger": "\u{89E6}\u{53D1}\u{6761}\u{4EF6}", "action": "\u{7CFB}\u{7EDF}\u{52A8}\u{4F5C}", "response": "\u{54CD}\u{5E94}\u{7ED3}\u{679C}"}
5040
+ ]
4718
5041
  }
4719
5042
  ],
4720
5043
  "templateRecommendation": {
@@ -4722,13 +5045,29 @@ var __webpack_exports__ = {};
4722
5045
  "reason": "\u{9009}\u{62E9}\u{8BE5}\u{6A21}\u{677F}\u{7684}\u{539F}\u{56E0}",
4723
5046
  "additionalTemplates": ["\u{5982}\u{679C}\u{662F}\u{6DF7}\u{5408}\u{7C7B}\u{578B}\u{FF0C}\u{5217}\u{51FA}\u{9700}\u{8981}\u{7684}\u{5176}\u{4ED6}\u{6A21}\u{677F}"]
4724
5047
  },
4725
- "optimizationSuggestion": "\u{9488}\u{5BF9}\u{529F}\u{80FD}\u{70B9}\u{6570}\u{91CF}\u{548C}\u{7C7B}\u{578B}\u{7684}\u{4F18}\u{5316}\u{5EFA}\u{8BAE}"
5048
+ "technicalContext": {
5049
+ "suggestedTechStack": ["\u{5EFA}\u{8BAE}\u{7684}\u{6280}\u{672F}\u{6808}"],
5050
+ "integrationPoints": ["\u{9700}\u{8981}\u{96C6}\u{6210}\u{7684}\u{7CFB}\u{7EDF}\u{6216}\u{670D}\u{52A1}"],
5051
+ "securityRequirements": ["\u{5B89}\u{5168}\u{8981}\u{6C42}"],
5052
+ "performanceRequirements": ["\u{6027}\u{80FD}\u{8981}\u{6C42}"]
5053
+ },
5054
+ "documentationHints": {
5055
+ "keySequenceDiagrams": ["\u{9700}\u{8981}\u{7ED8}\u{5236}\u{7684}\u{65F6}\u{5E8F}\u{56FE}\u{573A}\u{666F}"],
5056
+ "keyERDiagrams": ["\u{9700}\u{8981}\u{7ED8}\u{5236}\u{7684}ER\u{56FE}\u{5B9E}\u{4F53}"],
5057
+ "keyTables": ["\u{9700}\u{8981}\u{8BE6}\u{7EC6}\u{8BF4}\u{660E}\u{7684}\u{8868}\u{683C}"]
5058
+ }
4726
5059
  }
4727
5060
  \`\`\`
4728
5061
 
5062
+ ## \u{5206}\u{6790}\u{539F}\u{5219}
4729
5063
 
5064
+ 1. **\u{6DF1}\u{5EA6}\u{4F18}\u{4E8E}\u{5E7F}\u{5EA6}**: \u{5BF9}\u{6BCF}\u{4E2A}\u{529F}\u{80FD}\u{70B9}\u{8FDB}\u{884C}\u{6DF1}\u{5165}\u{5206}\u{6790}\u{FF0C}\u{800C}\u{4E0D}\u{662F}\u{7B80}\u{5355}\u{7F57}\u{5217}
5065
+ 2. **\u{4E1A}\u{52A1}\u{9A71}\u{52A8}**: \u{4ECE}\u{4E1A}\u{52A1}\u{4EF7}\u{503C}\u{89D2}\u{5EA6}\u{7406}\u{89E3}\u{9700}\u{6C42}\u{FF0C}\u{800C}\u{4E0D}\u{4EC5}\u{662F}\u{6280}\u{672F}\u{5B9E}\u{73B0}
5066
+ 3. **\u{4E0A}\u{4E0B}\u{6587}\u{5B8C}\u{6574}**: \u{63D0}\u{4F9B}\u{8DB3}\u{591F}\u{7684}\u{4E0A}\u{4E0B}\u{6587}\u{4FE1}\u{606F}\u{FF0C}\u{8BA9}\u{540E}\u{7EED}\u{6587}\u{6863}\u{751F}\u{6210}\u{6709}\u{636E}\u{53EF}\u{4F9D}
5067
+ 4. **\u{7ED3}\u{6784}\u{5316}\u{8F93}\u{51FA}**: \u{6240}\u{6709}\u{4FE1}\u{606F}\u{90FD}\u{4EE5}\u{7ED3}\u{6784}\u{5316}\u{65B9}\u{5F0F}\u{8F93}\u{51FA}\u{FF0C}\u{4FBF}\u{4E8E}\u{6A21}\u{677F}\u{586B}\u{5145}
5068
+ 5. **\u{63A7}\u{5236}\u{6570}\u{91CF}**: \u{6838}\u{5FC3}\u{529F}\u{80FD}\u{70B9}\u{63A7}\u{5236}\u{5728}2-5\u{4E2A}\u{FF0C}\u{907F}\u{514D}\u{8FC7}\u{5EA6}\u{62C6}\u{5206}
4730
5069
 
4731
- **\u{8981}\u{6C42}**: \u{907F}\u{514D}\u{8FC7}\u{5EA6}\u{62C6}\u{5206}\u{FF0C}\u{7CBE}\u{786E}\u{5339}\u{914D}\u{9700}\u{6C42}\u{7C7B}\u{578B}\u{FF0C}\u{63A7}\u{5236}2-5\u{4E2A}\u{6838}\u{5FC3}\u{529F}\u{80FD}\u{70B9}\u{FF0C}\u{4F18}\u{5148}\u{5355}\u{4E00}\u{6280}\u{672F}\u{6A21}\u{677F}\u{3002}`;
5070
+ **\u{8981}\u{6C42}**: \u{8F93}\u{51FA}\u{5FC5}\u{987B}\u{662F}\u{6709}\u{6548}\u{7684}JSON\u{683C}\u{5F0F}\u{FF0C}\u{6BCF}\u{4E2A}\u{5B57}\u{6BB5}\u{90FD}\u{8981}\u{6709}\u{5B9E}\u{9645}\u{5185}\u{5BB9}\u{FF0C}\u{4E0D}\u{8981}\u{4F7F}\u{7528}\u{5360}\u{4F4D}\u{7B26}\u{3002}`;
4732
5071
  class IntelligentAnalyzer {
4733
5072
  async analyzeRequirements(inputContent, projectInfo, customPrompt) {
4734
5073
  try {
@@ -5490,9 +5829,9 @@ Scenario Outline: UI\u{7EC4}\u{4EF6}\u{4EA4}\u{4E92}\u{5904}\u{7406}\u{6D41}\u{7
5490
5829
 
5491
5830
  **\u{8981}\u{6C42}**: \u{8F93}\u{51FA}\u{5B8C}\u{6574}\u{6587}\u{6863}\u{FF0C}\u{6BCF}\u{7AE0}\u{8282}\u{6709}\u{5B9E}\u{8D28}\u{5185}\u{5BB9}\u{FF0C}\u{8868}\u{683C}\u{586B}\u{5199}\u{5177}\u{4F53}\u{4FE1}\u{606F}\u{FF0C}\u{57FA}\u{4E8E}\u{539F}\u{59CB}\u{5185}\u{5BB9}\u{5177}\u{4F53}\u{5206}\u{6790}\u{3002}\`;
5492
5831
  `;
5493
- const pcPageTemplatePrompt = `\u{4F60}\u{662F}\u{524D}\u{7AEF}\u{6280}\u{672F}\u{6587}\u{6863}\u{4E13}\u{5BB6}\u{3002}\u{57FA}\u{4E8E}\u{8F93}\u{5165}\u{5185}\u{5BB9}\u{751F}\u{6210}\u{5B8C}\u{6574}\u{7684}PC\u{9875}\u{9762}\u{6280}\u{672F}\u{9700}\u{6C42}\u{6587}\u{6863}\u{FF08}Markdown\u{683C}\u{5F0F}\u{FF0C}3000\u{5B57}\u{4EE5}\u{4E0A}\u{FF09}\u{3002}
5832
+ const htmlPageTemplatePrompt = `\u{4F60}\u{662F}\u{524D}\u{7AEF}\u{6280}\u{672F}\u{6587}\u{6863}\u{4E13}\u{5BB6}\u{3002}\u{57FA}\u{4E8E}\u{8F93}\u{5165}\u{5185}\u{5BB9}\u{751F}\u{6210}\u{5B8C}\u{6574}\u{7684}HTML\u{9875}\u{9762}\u{6280}\u{672F}\u{9700}\u{6C42}\u{6587}\u{6863}\u{FF08}Markdown\u{683C}\u{5F0F}\u{FF0C}3000\u{5B57}\u{4EE5}\u{4E0A}\u{FF09}\u{3002}
5494
5833
 
5495
- **\u{8F93}\u{5165}**: \u{529F}\u{80FD}\u{540D}\u{79F0}={featureName}, \u{4E1A}\u{52A1}\u{9886}\u{57DF}={businessDomain}, \u{751F}\u{6210}\u{65F6}\u{5E8F}\u{56FE}={generateSequenceDiagram}
5834
+ **\u{8F93}\u{5165}**: \u{529F}\u{80FD}\u{540D}\u{79F0}={featureName}, \u{4E1A}\u{52A1}\u{9886}\u{57DF}={businessDomain}, \u{9875}\u{9762}\u{7C7B}\u{578B}={pageType}, \u{9875}\u{9762}\u{98CE}\u{683C}={pageStyle}
5496
5835
 
5497
5836
  **\u{539F}\u{59CB}\u{9700}\u{6C42}**:
5498
5837
  \`\`\`
@@ -5502,11 +5841,12 @@ Scenario Outline: UI\u{7EC4}\u{4EF6}\u{4EA4}\u{4E92}\u{5904}\u{7406}\u{6D41}\u{7
5502
5841
  ## \u{6587}\u{6863}\u{7ED3}\u{6784}\u{8981}\u{6C42}
5503
5842
  \u{8BF7}\u{4E25}\u{683C}\u{6309}\u{7167}\u{4EE5}\u{4E0B}\u{7ED3}\u{6784}\u{8F93}\u{51FA}\u{5B8C}\u{6574}\u{7684}\u{9700}\u{6C42}\u{6587}\u{6863}\u{FF0C}\u{6BCF}\u{4E2A}\u{7AE0}\u{8282}\u{90FD}\u{8981}\u{6709}\u{8BE6}\u{5B9E}\u{7684}\u{5185}\u{5BB9}\u{FF1A}
5504
5843
 
5505
- # {featureName} - PC\u{9875}\u{9762}\u{6280}\u{672F}\u{9700}\u{6C42}\u{6587}\u{6863}
5844
+ # {featureName} - HTML\u{9875}\u{9762}\u{6280}\u{672F}\u{9700}\u{6C42}\u{6587}\u{6863}
5506
5845
 
5507
5846
  > **\u{751F}\u{6210}\u{65F6}\u{95F4}**: {currentTime}
5508
5847
  > **\u{4E1A}\u{52A1}\u{9886}\u{57DF}**: {businessDomain}
5509
- > **\u{9875}\u{9762}\u{7C7B}\u{578B}**: PC\u{7AEF}Web\u{9875}\u{9762}
5848
+ > **\u{9875}\u{9762}\u{7C7B}\u{578B}**: {pageType}\u{FF08}pc/mobile/responsive\u{FF09}
5849
+ > **\u{9875}\u{9762}\u{98CE}\u{683C}**: TailwindCSS \u{7B80}\u{7EA6}\u{98CE}\u{683C}
5510
5850
 
5511
5851
  ---
5512
5852
 
@@ -5518,6 +5858,8 @@ Scenario Outline: UI\u{7EC4}\u{4EF6}\u{4EA4}\u{4E92}\u{5904}\u{7406}\u{6D41}\u{7
5518
5858
 
5519
5859
  **\u{6D89}\u{53CA}\u{89D2}\u{8272}**: [\u{5217}\u{51FA}\u{6240}\u{6709}\u{76F8}\u{5173}\u{7528}\u{6237}\u{89D2}\u{8272}]
5520
5860
 
5861
+ **\u{76EE}\u{6807}\u{8BBE}\u{5907}**: [\u{6839}\u{636E}pageType\u{63CF}\u{8FF0}\u{76EE}\u{6807}\u{8BBE}\u{5907}\u{FF0C}\u{5982}PC\u{6D4F}\u{89C8}\u{5668}\u{3001}\u{79FB}\u{52A8}\u{7AEF}\u{6D4F}\u{89C8}\u{5668}\u{3001}\u{6216}\u{4E24}\u{8005}\u{517C}\u{987E}]
5862
+
5521
5863
  ## 2. {featureName}\u{529F}\u{80FD}\u{8BBE}\u{8BA1}\u{8BF4}\u{660E}
5522
5864
 
5523
5865
  | | | | | |
@@ -5527,14 +5869,17 @@ Scenario Outline: UI\u{7EC4}\u{4EF6}\u{4EA4}\u{4E92}\u{5904}\u{7406}\u{6D41}\u{7
5527
5869
  |**\u{529F}\u{80FD}\u{8BBE}\u{8BA1}\u{7F16}\u{53F7}**|FD001|**\u{7CFB}\u{7EDF}\u{529F}\u{80FD}\u{540D}\u{79F0}**|{featureName}|
5528
5870
  |**\u{524D}\u{7F6E}\u{6761}\u{4EF6}**|[\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{8BBF}\u{95EE}\u{7684}\u{524D}\u{7F6E}\u{6761}\u{4EF6}]|
5529
5871
  |**\u{89D2}\u{8272}\u{FF08}\u{5C97}\u{4F4D}\u{FF09}**|[\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{7528}\u{6237}\u{89D2}\u{8272}\u{53CA}\u{5176}\u{6743}\u{9650}]|
5530
- |**\u{5165}\u{53E3}\u{6E20}\u{9053}**|[\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{8BBF}\u{95EE}\u{5165}\u{53E3}\u{FF0C}\u{5982}\u{83DC}\u{5355}\u{3001}\u{94FE}\u{63A5}\u{7B49}]|
5872
+ |**\u{5165}\u{53E3}\u{6E20}\u{9053}**|[\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{8BBF}\u{95EE}\u{5165}\u{53E3}\u{FF0C}\u{5982}\u{83DC}\u{5355}\u{3001}\u{94FE}\u{63A5}\u{3001}APP\u{5185}\u{5D4C}\u{7B49}]|
5531
5873
  |**\u{529F}\u{80FD}\u{63CF}\u{8FF0}**|[\u{8BE6}\u{7EC6}\u{7684}\u{529F}\u{80FD}\u{63CF}\u{8FF0}]|
5532
5874
  |**\u{8C03}\u{7528}\u{80FD}\u{529B}\u{57DF}/\u{4E2D}\u{5FC3}**|[\u{5982}\u{9002}\u{7528}\u{7684}\u{540E}\u{7AEF}API\u{63A5}\u{53E3}]|
5533
5875
 
5534
5876
  ## 3. \u{9875}\u{9762}\u{5E03}\u{5C40}\u{8BBE}\u{8BA1}
5535
5877
 
5536
5878
  ### 3.1 \u{6574}\u{4F53}\u{5E03}\u{5C40}\u{7ED3}\u{6784}
5537
- [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{7684}\u{6574}\u{4F53}\u{5E03}\u{5C40}\u{7ED3}\u{6784}\u{FF0C}\u{5305}\u{62EC}\u{5934}\u{90E8}\u{3001}\u{4E3B}\u{4F53}\u{3001}\u{4FA7}\u{8FB9}\u{680F}\u{3001}\u{5E95}\u{90E8}\u{7B49}\u{533A}\u{57DF}\u{7684}\u{5212}\u{5206}\u{548C}\u{529F}\u{80FD}]
5879
+ [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{7684}\u{6574}\u{4F53}\u{5E03}\u{5C40}\u{7ED3}\u{6784}]
5880
+ - **PC\u{7AEF}\u{5E03}\u{5C40}**: [\u{5982}\u{9002}\u{7528}\u{FF0C}\u{63CF}\u{8FF0}PC\u{7AEF}\u{7684}\u{5934}\u{90E8}\u{3001}\u{4E3B}\u{4F53}\u{3001}\u{4FA7}\u{8FB9}\u{680F}\u{3001}\u{5E95}\u{90E8}\u{7B49}\u{533A}\u{57DF}]
5881
+ - **\u{79FB}\u{52A8}\u{7AEF}\u{5E03}\u{5C40}**: [\u{5982}\u{9002}\u{7528}\u{FF0C}\u{63CF}\u{8FF0}\u{79FB}\u{52A8}\u{7AEF}\u{7684}\u{9876}\u{90E8}\u{5BFC}\u{822A}\u{3001}\u{5185}\u{5BB9}\u{533A}\u{3001}\u{5E95}\u{90E8}\u{5BFC}\u{822A}\u{7B49}\u{533A}\u{57DF}]
5882
+ - **\u{54CD}\u{5E94}\u{5F0F}\u{65AD}\u{70B9}**: [\u{5982}\u{9002}\u{7528}\u{FF0C}\u{63CF}\u{8FF0}\u{4E0D}\u{540C}\u{5C4F}\u{5E55}\u{5C3A}\u{5BF8}\u{4E0B}\u{7684}\u{5E03}\u{5C40}\u{53D8}\u{5316}]
5538
5883
 
5539
5884
  ### 3.2 \u{9875}\u{9762}\u{533A}\u{57DF}\u{5212}\u{5206}
5540
5885
  [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{5404}\u{4E2A}\u{529F}\u{80FD}\u{533A}\u{57DF}\u{7684}\u{5E03}\u{5C40}\u{FF0C}\u{4F7F}\u{7528}\u{6587}\u{5B57}\u{6216}ASCII\u{56FE}\u{793A}\u{63CF}\u{8FF0}\u{533A}\u{57DF}\u{4F4D}\u{7F6E}\u{5173}\u{7CFB}]
@@ -5542,13 +5887,34 @@ Scenario Outline: UI\u{7EC4}\u{4EF6}\u{4EA4}\u{4E92}\u{5904}\u{7406}\u{6D41}\u{7
5542
5887
  ### 3.3 \u{9875}\u{9762}\u{6D41}\u{7EBF}\u{8BBE}\u{8BA1}
5543
5888
  [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{7528}\u{6237}\u{5728}\u{9875}\u{9762}\u{4E2D}\u{7684}\u{89C6}\u{89C9}\u{6D41}\u{7EBF}\u{548C}\u{64CD}\u{4F5C}\u{8DEF}\u{5F84}\u{8BBE}\u{8BA1}]
5544
5889
 
5890
+ ### 3.4 \u{54CD}\u{5E94}\u{5F0F}\u{9002}\u{914D}\u{7B56}\u{7565}
5891
+ [\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{5728}\u{4E0D}\u{540C}\u{8BBE}\u{5907}\u{4E0A}\u{7684}\u{9002}\u{914D}\u{7B56}\u{7565}]
5892
+ - **\u{65AD}\u{70B9}\u{8BBE}\u{7F6E}**: sm(640px), md(768px), lg(1024px), xl(1280px)
5893
+ - **\u{5E03}\u{5C40}\u{53D8}\u{5316}**: [\u{63CF}\u{8FF0}\u{5404}\u{65AD}\u{70B9}\u{4E0B}\u{7684}\u{5E03}\u{5C40}\u{8C03}\u{6574}]
5894
+ - **\u{5143}\u{7D20}\u{9690}\u{85CF}/\u{663E}\u{793A}**: [\u{63CF}\u{8FF0}\u{54EA}\u{4E9B}\u{5143}\u{7D20}\u{5728}\u{4E0D}\u{540C}\u{8BBE}\u{5907}\u{4E0A}\u{663E}\u{793A}\u{6216}\u{9690}\u{85CF}]
5895
+
5545
5896
  ## 4. \u{6837}\u{5F0F}\u{89C4}\u{8303}\u{8BF4}\u{660E}
5546
5897
 
5547
5898
  ### 4.1 \u{8272}\u{5F69}\u{89C4}\u{8303}
5548
5899
  [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{4F7F}\u{7528}\u{7684}\u{4E3B}\u{8272}\u{8C03}\u{3001}\u{8F85}\u{52A9}\u{8272}\u{3001}\u{72B6}\u{6001}\u{8272}\u{7B49}\u{914D}\u{8272}\u{65B9}\u{6848}]
5900
+ \`\`\`css
5901
+ :root {
5902
+ --bg: #ffffff;
5903
+ --bg-secondary: #f8f9fa;
5904
+ --border: #e5e5e5;
5905
+ --text: #111111;
5906
+ --text-muted: #666666;
5907
+ --accent: #000000;
5908
+ }
5909
+ \`\`\`
5910
+
5911
+ ### 4.2 \u{5B57}\u{4F53}\u{89C4}\u{8303}
5912
+ [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{5B57}\u{4F53}\u{65CF}\u{3001}\u{5B57}\u{53F7}\u{3001}\u{884C}\u{9AD8}\u{7B49}\u{6392}\u{7248}\u{89C4}\u{8303}]
5549
5913
 
5914
+ ### 4.3 \u{95F4}\u{8DDD}\u{89C4}\u{8303}
5915
+ [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{5143}\u{7D20}\u{7684}\u{95F4}\u{8DDD}\u{89C4}\u{8303}\u{FF0C}\u{4F7F}\u{7528}TailwindCSS\u{7684}\u{95F4}\u{8DDD}\u{7CFB}\u{7EDF}]
5550
5916
 
5551
- ### 4.2 \u{54C1}\u{724C}\u{89C6}\u{89C9}\u{89C4}\u{8303}
5917
+ ### 4.4 \u{54C1}\u{724C}\u{89C6}\u{89C9}\u{89C4}\u{8303}
5552
5918
  [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{54C1}\u{724C}\u{89C6}\u{89C9}\u{5143}\u{7D20}\u{5728}\u{9875}\u{9762}\u{4E2D}\u{7684}\u{5E94}\u{7528}\u{89C4}\u{8303}\u{FF0C}\u{5982}Logo\u{3001}\u{56FE}\u{6807}\u{7B49}]
5553
5919
 
5554
5920
  ## 5. \u{4EA4}\u{4E92}\u{903B}\u{8F91}\u{8BF4}\u{660E}
@@ -5565,11 +5931,14 @@ Scenario Outline: UI\u{7EC4}\u{4EF6}\u{4EA4}\u{4E92}\u{5904}\u{7406}\u{6D41}\u{7
5565
5931
  ### 5.4 \u{8868}\u{5355}\u{9A8C}\u{8BC1}\u{89C4}\u{5219}
5566
5932
  [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{4E2D}\u{8868}\u{5355}\u{5143}\u{7D20}\u{7684}\u{9A8C}\u{8BC1}\u{89C4}\u{5219}\u{548C}\u{9519}\u{8BEF}\u{63D0}\u{793A}]
5567
5933
 
5568
- ### 5.5 \u{4E8B}\u{4EF6}\u{5904}\u{7406}\u{673A}\u{5236}
5569
- [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{4E2D}\u{5404}\u{79CD}\u{7528}\u{6237}\u{4E8B}\u{4EF6}\u{7684}\u{5904}\u{7406}\u{673A}\u{5236}\u{FF0C}\u{5982}\u{70B9}\u{51FB}\u{3001}\u{60AC}\u{505C}\u{3001}\u{952E}\u{76D8}\u{64CD}\u{4F5C}\u{7B49}]
5934
+ ### 5.5 \u{89E6}\u{6478}/\u{624B}\u{52BF}\u{4EA4}\u{4E92}
5935
+ [\u{5982}\u{9002}\u{7528}\u{4E8E}\u{79FB}\u{52A8}\u{7AEF}\u{FF0C}\u{63CF}\u{8FF0}\u{89E6}\u{6478}\u{548C}\u{624B}\u{52BF}\u{4EA4}\u{4E92}\u{8BBE}\u{8BA1}]
5936
+ - **\u{6ED1}\u{52A8}\u{64CD}\u{4F5C}**: [\u{63CF}\u{8FF0}\u{6ED1}\u{52A8}\u{76F8}\u{5173}\u{7684}\u{4EA4}\u{4E92}]
5937
+ - **\u{957F}\u{6309}\u{64CD}\u{4F5C}**: [\u{63CF}\u{8FF0}\u{957F}\u{6309}\u{76F8}\u{5173}\u{7684}\u{4EA4}\u{4E92}]
5938
+ - **\u{4E0B}\u{62C9}\u{5237}\u{65B0}**: [\u{63CF}\u{8FF0}\u{4E0B}\u{62C9}\u{5237}\u{65B0}\u{7684}\u{4EA4}\u{4E92}]
5570
5939
 
5571
- ### 5.6 \u{6570}\u{636E}\u{66F4}\u{65B0}\u{673A}\u{5236}
5572
- [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{4E2D}\u{6570}\u{636E}\u{66F4}\u{65B0}\u{7684}\u{89E6}\u{53D1}\u{6761}\u{4EF6}\u{548C}\u{5904}\u{7406}\u{903B}\u{8F91}]
5940
+ ### 5.6 \u{4E8B}\u{4EF6}\u{5904}\u{7406}\u{673A}\u{5236}
5941
+ [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{4E2D}\u{5404}\u{79CD}\u{7528}\u{6237}\u{4E8B}\u{4EF6}\u{7684}\u{5904}\u{7406}\u{673A}\u{5236}]
5573
5942
 
5574
5943
  ### 5.7 \u{9519}\u{8BEF}\u{5904}\u{7406}\u{4E0E}\u{6062}\u{590D}
5575
5944
  [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{4E2D}\u{9519}\u{8BEF}\u{60C5}\u{51B5}\u{7684}\u{5904}\u{7406}\u{548C}\u{7528}\u{6237}\u{5F15}\u{5BFC}\u{6062}\u{590D}\u{673A}\u{5236}]
@@ -5579,13 +5948,10 @@ Scenario Outline: UI\u{7EC4}\u{4EF6}\u{4EA4}\u{4E92}\u{5904}\u{7406}\u{6D41}\u{7
5579
5948
  ### 6.1 \u{4E3B}\u{8981}\u{6570}\u{636E}\u{5B9E}\u{4F53}
5580
5949
  [\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{6D89}\u{53CA}\u{7684}\u{4E3B}\u{8981}\u{6570}\u{636E}\u{5B9E}\u{4F53}]
5581
5950
 
5582
- \u{5B9E}\u{4F53}\u{4E00}
5583
- | | | | | |
5951
+ | **\u{5B57}\u{6BB5}\u{540D}\u{79F0}** | **\u{6570}\u{636E}\u{7C7B}\u{578B}** | **\u{957F}\u{5EA6}** | **\u{5FC5}\u{586B}** | **\u{8BF4}\u{660E}** |
5584
5952
  |---|---|---|---|---|
5585
- |**\u{5B57}\u{6BB5}\u{540D}\u{79F0}**|**\u{6570}\u{636E}\u{7C7B}\u{578B}**|**\u{957F}\u{5EA6}**|**\u{5FC5}\u{586B}**|**\u{8BF4}\u{660E}**|
5586
5953
  |[\u{5B57}\u{6BB5}1]|[\u{7C7B}\u{578B}]|[\u{957F}\u{5EA6}]|[\u{662F}/\u{5426}]|[\u{8BE6}\u{7EC6}\u{8BF4}\u{660E}]|
5587
5954
  |[\u{5B57}\u{6BB5}2]|[\u{7C7B}\u{578B}]|[\u{957F}\u{5EA6}]|[\u{662F}/\u{5426}]|[\u{8BE6}\u{7EC6}\u{8BF4}\u{660E}]|
5588
- |[\u{6DFB}\u{52A0}\u{66F4}\u{591A}\u{76F8}\u{5173}\u{5B57}\u{6BB5}...]|||
5589
5955
 
5590
5956
  ### 6.2 \u{8868}\u{5355}\u{5B57}\u{6BB5}\u{8BF4}\u{660E}
5591
5957
  [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{9875}\u{9762}\u{8868}\u{5355}\u{4E2D}\u{5404}\u{5B57}\u{6BB5}\u{7684}\u{542B}\u{4E49}\u{3001}\u{683C}\u{5F0F}\u{8981}\u{6C42}\u{3001}\u{9A8C}\u{8BC1}\u{89C4}\u{5219}\u{7B49}]
@@ -5595,12 +5961,10 @@ Scenario Outline: UI\u{7EC4}\u{4EF6}\u{4EA4}\u{4E92}\u{5904}\u{7406}\u{6D41}\u{7
5595
5961
 
5596
5962
  ## 7. \u{754C}\u{9762}\u{64CD}\u{4F5C}\u{8BF4}\u{660E}
5597
5963
 
5598
- | | | |
5964
+ | **\u{5E8F}\u{53F7}** | **\u{4E1A}\u{52A1}\u{64CD}\u{4F5C}** | **\u{8BF4}\u{660E}** |
5599
5965
  |---|---|---|
5600
- |**\u{5E8F}\u{53F7}**|**\u{4E1A}\u{52A1}\u{64CD}\u{4F5C}**|**\u{8BF4}\u{660E}**|
5601
5966
  |1|[\u{64CD}\u{4F5C}1]|[\u{8BE6}\u{7EC6}\u{8BF4}\u{660E}\u{64CD}\u{4F5C}\u{89E6}\u{53D1}\u{6761}\u{4EF6}\u{3001}\u{6267}\u{884C}\u{8FC7}\u{7A0B}\u{548C}\u{7ED3}\u{679C}]|
5602
5967
  |2|[\u{64CD}\u{4F5C}2]|[\u{8BE6}\u{7EC6}\u{8BF4}\u{660E}\u{64CD}\u{4F5C}\u{89E6}\u{53D1}\u{6761}\u{4EF6}\u{3001}\u{6267}\u{884C}\u{8FC7}\u{7A0B}\u{548C}\u{7ED3}\u{679C}]|
5603
- |[\u{6DFB}\u{52A0}\u{66F4}\u{591A}\u{64CD}\u{4F5C}...]|
5604
5968
 
5605
5969
  ## 8. \u{7EC4}\u{4EF6}\u{7ED3}\u{6784}\u{8BBE}\u{8BA1}
5606
5970
 
@@ -5622,21 +5986,32 @@ Scenario Outline: UI\u{7EC4}\u{4EF6}\u{4EA4}\u{4E92}\u{5904}\u{7406}\u{6D41}\u{7
5622
5986
 
5623
5987
  \`\`\`mermaid
5624
5988
  sequenceDiagram
5989
+ participant User as \u{7528}\u{6237}
5990
+ participant Page as \u{9875}\u{9762}
5991
+ participant API as \u{540E}\u{7AEF}API
5992
+ User->>Page: \u{8BBF}\u{95EE}\u{9875}\u{9762}
5993
+ Page->>API: \u{8BF7}\u{6C42}\u{6570}\u{636E}
5994
+ API-->>Page: \u{8FD4}\u{56DE}\u{6570}\u{636E}
5995
+ Page-->>User: \u{5C55}\u{793A}\u{5185}\u{5BB9}
5625
5996
  \`\`\`
5626
5997
 
5627
- ### 9.2 \u{8FB9}\u{7F18}\u{60C5}\u{51B5}\u{6D41}\u{7A0B}\u{FF08}\u{5E76}\u{53D1}\u{3001}\u{8D85}\u{65F6}\u{7B49}\u{FF09}
5998
+ ### 9.2 \u{8FB9}\u{7F18}\u{60C5}\u{51B5}\u{6D41}\u{7A0B}\u{FF08}\u{9519}\u{8BEF}\u{5904}\u{7406}\u{3001}\u{8D85}\u{65F6}\u{7B49}\u{FF09}
5628
5999
 
5629
- #### 9.2.1 \u{6027}\u{80FD}\u{4F18}\u{5316}\u{8981}\u{6C42}
5630
6000
  \`\`\`mermaid
5631
6001
  sequenceDiagram
6002
+ participant User as \u{7528}\u{6237}
6003
+ participant Page as \u{9875}\u{9762}
6004
+ participant API as \u{540E}\u{7AEF}API
6005
+ User->>Page: \u{63D0}\u{4EA4}\u{8868}\u{5355}
6006
+ Page->>API: \u{53D1}\u{9001}\u{8BF7}\u{6C42}
6007
+ API-->>Page: \u{8FD4}\u{56DE}\u{9519}\u{8BEF}
6008
+ Page-->>User: \u{663E}\u{793A}\u{9519}\u{8BEF}\u{63D0}\u{793A}
5632
6009
  \`\`\`
5633
6010
 
5634
-
5635
6011
  ## 10. \u{4E1A}\u{52A1}\u{72B6}\u{6001}\u{63CF}\u{8FF0}
5636
6012
 
5637
- | | | |
6013
+ | **\u{72B6}\u{6001}\u{7F16}\u{53F7}** | **\u{72B6}\u{6001}\u{540D}\u{79F0}** | **\u{63CF}\u{8FF0}** |
5638
6014
  |---|---|---|
5639
- |**\u{72B6}\u{6001}\u{7F16}\u{53F7}**|**\u{72B6}\u{6001}\u{540D}\u{79F0}**|**\u{63CF}\u{8FF0}**|
5640
6015
  |01|\u{5F85}\u{52A0}\u{8F7D}|\u{9875}\u{9762}\u{521D}\u{59CB}\u{5316}\u{72B6}\u{6001}|
5641
6016
  |02|\u{52A0}\u{8F7D}\u{4E2D}|\u{6570}\u{636E}\u{52A0}\u{8F7D}\u{72B6}\u{6001}|
5642
6017
  |03|\u{6B63}\u{5E38}\u{663E}\u{793A}|\u{9875}\u{9762}\u{6B63}\u{5E38}\u{663E}\u{793A}\u{72B6}\u{6001}|
@@ -5647,174 +6022,19 @@ sequenceDiagram
5647
6022
  |08|\u{63D0}\u{4EA4}\u{4E2D}|\u{8868}\u{5355}\u{63D0}\u{4EA4}\u{5904}\u{7406}\u{4E2D}\u{72B6}\u{6001}|
5648
6023
  |09|\u{63D0}\u{4EA4}\u{6210}\u{529F}|\u{8868}\u{5355}\u{63D0}\u{4EA4}\u{6210}\u{529F}\u{72B6}\u{6001}|
5649
6024
  |10|\u{63D0}\u{4EA4}\u{5931}\u{8D25}|\u{8868}\u{5355}\u{63D0}\u{4EA4}\u{5931}\u{8D25}\u{72B6}\u{6001}|
5650
- |[\u{6DFB}\u{52A0}\u{66F4}\u{591A}\u{72B6}\u{6001}...]||
5651
6025
 
5652
6026
  ## 11. \u{7528}\u{6237}\u{6545}\u{4E8B}
5653
6027
 
5654
6028
  ### 11.1 \u{6545}\u{4E8B}1
5655
6029
  [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{6545}\u{4E8B}\u{7684}\u{5185}\u{5BB9}\u{FF0C}\u{5305}\u{62EC}\u{4EFB}\u{52A1}\u{5B9A}\u{4E49}\u{3001}\u{4E1A}\u{52A1}\u{903B}\u{8F91}\u{63CF}\u{8FF0}\u{3001}\u{6280}\u{672F}\u{65B9}\u{6848}\u{5B9E}\u{73B0}\u{7B49}]
6030
+
5656
6031
  ### 11.2 \u{6545}\u{4E8B}2
5657
6032
  [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{6545}\u{4E8B}\u{7684}\u{5185}\u{5BB9}\u{FF0C}\u{5305}\u{62EC}\u{4EFB}\u{52A1}\u{5B9A}\u{4E49}\u{3001}\u{4E1A}\u{52A1}\u{903B}\u{8F91}\u{63CF}\u{8FF0}\u{3001}\u{6280}\u{672F}\u{65B9}\u{6848}\u{5B9E}\u{73B0}\u{7B49}]
5658
- ...
5659
- ### 11.3 \u{66F4}\u{591A}\u{6545}\u{4E8B}
5660
- [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}\u{66F4}\u{591A}\u{6545}\u{4E8B}\u{7684}\u{5185}\u{5BB9}\u{FF0C}\u{5305}\u{62EC}\u{4EFB}\u{52A1}\u{5B9A}\u{4E49}\u{3001}\u{4E1A}\u{52A1}\u{903B}\u{8F91}\u{63CF}\u{8FF0}\u{3001}\u{6280}\u{672F}\u{65B9}\u{6848}\u{5B9E}\u{73B0}\u{7B49}]
5661
- >
5662
-
5663
-
5664
- ---
5665
-
5666
- **\u{8981}\u{6C42}**: \u{8F93}\u{51FA}\u{5B8C}\u{6574}\u{6587}\u{6863}\u{FF0C}\u{6BCF}\u{7AE0}\u{8282}\u{6709}\u{5B9E}\u{8D28}\u{5185}\u{5BB9}\u{FF0C}\u{8868}\u{683C}\u{586B}\u{5199}\u{5177}\u{4F53}\u{4FE1}\u{606F}\u{FF0C}\u{91CD}\u{70B9}\u{5173}\u{6CE8}\u{9875}\u{9762}\u{5E03}\u{5C40}\u{3001}\u{6837}\u{5F0F}\u{3001}\u{4EA4}\u{4E92}\u{903B}\u{8F91}\u{3002}`;
5667
- const appTemplatePrompt = `\u{4F60}\u{662F}\u{79FB}\u{52A8}\u{7AEF}\u{6280}\u{672F}\u{6587}\u{6863}\u{4E13}\u{5BB6}\u{3002}\u{57FA}\u{4E8E}\u{8F93}\u{5165}\u{5185}\u{5BB9}\u{751F}\u{6210}\u{5B8C}\u{6574}\u{7684}APP\u{6280}\u{672F}\u{9700}\u{6C42}\u{6587}\u{6863}\u{FF08}Markdown\u{683C}\u{5F0F}\u{FF0C}1500\u{5B57}\u{4EE5}\u{4E0A}\u{FF09}\u{3002}
5668
-
5669
- **\u{8F93}\u{5165}**: \u{529F}\u{80FD}\u{540D}\u{79F0}={featureName}, \u{4E1A}\u{52A1}\u{9886}\u{57DF}={businessDomain}
5670
-
5671
- **\u{539F}\u{59CB}\u{9700}\u{6C42}**:
5672
- \`\`\`
5673
- {inputContent}
5674
- \`\`\`
5675
-
5676
- ## \u{6587}\u{6863}\u{7ED3}\u{6784}\u{8981}\u{6C42}
5677
- \u{8BF7}\u{4E25}\u{683C}\u{6309}\u{7167}\u{4EE5}\u{4E0B}\u{7ED3}\u{6784}\u{8F93}\u{51FA}\u{5B8C}\u{6574}\u{7684}\u{9700}\u{6C42}\u{6587}\u{6863}\u{FF0C}\u{6BCF}\u{4E2A}\u{7AE0}\u{8282}\u{90FD}\u{8981}\u{6709}\u{8BE6}\u{5B9E}\u{7684}\u{5185}\u{5BB9}\u{FF1A}
5678
-
5679
- # {featureName} - APP\u{6280}\u{672F}\u{9700}\u{6C42}\u{6587}\u{6863}
5680
-
5681
- > **\u{751F}\u{6210}\u{65F6}\u{95F4}**: {currentTime}
5682
- > **\u{4E1A}\u{52A1}\u{9886}\u{57DF}**: {businessDomain}
5683
- > **\u{5E94}\u{7528}\u{7C7B}\u{578B}**: \u{79FB}\u{52A8}\u{7AEF}\u{5E94}\u{7528}\u{7A0B}\u{5E8F}
5684
-
5685
- ---
5686
-
5687
- ## 1. \u{9700}\u{6C42}\u{6982}\u{8FF0}
5688
-
5689
- **\u{4E1A}\u{52A1}\u{80CC}\u{666F}**: [\u{63CF}\u{8FF0}APP\u{529F}\u{80FD}\u{80CC}\u{666F}\u{3001}\u{4E1A}\u{52A1}\u{9700}\u{6C42}\u{548C}\u{76EE}\u{6807}]
5690
-
5691
- **\u{6838}\u{5FC3}\u{529F}\u{80FD}**: [\u{5217}\u{51FA}APP\u{7684}\u{4E3B}\u{8981}\u{529F}\u{80FD}\u{70B9}]
5692
-
5693
- ## 2. \u{754C}\u{9762}\u{8BBE}\u{8BA1}
5694
-
5695
- ### 2.1 \u{9875}\u{9762}\u{5E03}\u{5C40}
5696
- [\u{63CF}\u{8FF0}\u{4E3B}\u{8981}\u{9875}\u{9762}\u{7684}\u{5E03}\u{5C40}\u{7ED3}\u{6784}\u{548C}\u{754C}\u{9762}\u{5143}\u{7D20}]
5697
-
5698
- ### 2.2 \u{7528}\u{6237}\u{754C}\u{9762}
5699
- [\u{63CF}\u{8FF0}APP\u{7684}\u{7528}\u{6237}\u{754C}\u{9762}\u{8BBE}\u{8BA1}\u{548C}\u{4EA4}\u{4E92}\u{5143}\u{7D20}]
5700
-
5701
- ## 3. \u{4EA4}\u{4E92}\u{903B}\u{8F91}
5702
-
5703
- ### 3.1 \u{7528}\u{6237}\u{64CD}\u{4F5C}\u{6D41}\u{7A0B}
5704
- [\u{63CF}\u{8FF0}\u{4E3B}\u{8981}\u{7684}\u{7528}\u{6237}\u{64CD}\u{4F5C}\u{6D41}\u{7A0B}\u{548C}\u{5BFC}\u{822A}\u{8DEF}\u{5F84}]
5705
-
5706
- ### 3.2 \u{4EA4}\u{4E92}\u{89C4}\u{5219}
5707
- [\u{63CF}\u{8FF0}APP\u{4E2D}\u{7684}\u{4E3B}\u{8981}\u{4EA4}\u{4E92}\u{89C4}\u{5219}\u{548C}\u{54CD}\u{5E94}\u{673A}\u{5236}]
5708
-
5709
- ## 4. \u{6570}\u{636E}\u{5904}\u{7406}
5710
-
5711
- ### 4.1 \u{6570}\u{636E}\u{5C55}\u{793A}
5712
- [\u{63CF}\u{8FF0}APP\u{4E2D}\u{6570}\u{636E}\u{7684}\u{5C55}\u{793A}\u{65B9}\u{5F0F}\u{548C}\u{683C}\u{5F0F}]
5713
-
5714
- ### 4.2 \u{6570}\u{636E}\u{4EA4}\u{4E92}
5715
- [\u{63CF}\u{8FF0}APP\u{4E0E}\u{540E}\u{7AEF}\u{7684}\u{6570}\u{636E}\u{4EA4}\u{4E92}\u{65B9}\u{5F0F}]
5716
-
5717
- ## 5. \u{529F}\u{80FD}\u{6A21}\u{5757}
5718
-
5719
- ### 5.1 \u{6838}\u{5FC3}\u{6A21}\u{5757}
5720
- [\u{63CF}\u{8FF0}APP\u{7684}\u{6838}\u{5FC3}\u{529F}\u{80FD}\u{6A21}\u{5757}]
5721
-
5722
- ### 5.2 \u{4E1A}\u{52A1}\u{903B}\u{8F91}
5723
- [\u{63CF}\u{8FF0}\u{5404}\u{6A21}\u{5757}\u{7684}\u{4E1A}\u{52A1}\u{903B}\u{8F91}\u{548C}\u{5904}\u{7406}\u{6D41}\u{7A0B}]
5724
-
5725
- ## 6. \u{4E1A}\u{52A1}\u{6D41}\u{7A0B}
5726
-
5727
- [\u{4F7F}\u{7528}\u{7B80}\u{5355}\u{7684}mermaid\u{6D41}\u{7A0B}\u{56FE}\u{63CF}\u{8FF0}\u{4E3B}\u{8981}\u{4E1A}\u{52A1}\u{6D41}\u{7A0B}]
5728
-
5729
- \`\`\`mermaid
5730
- graph TD
5731
- A[\u{5F00}\u{59CB}] --> B[\u{5904}\u{7406}]
5732
- B --> C[\u{7ED3}\u{675F}]
5733
- \`\`\`
5734
-
5735
- ---
5736
-
5737
- **\u{8981}\u{6C42}**: \u{8F93}\u{51FA}\u{5B8C}\u{6574}\u{6587}\u{6863}\u{FF0C}\u{6BCF}\u{7AE0}\u{8282}\u{6709}\u{5B9E}\u{8D28}\u{5185}\u{5BB9}\u{FF0C}\u{91CD}\u{70B9}\u{5173}\u{6CE8}\u{754C}\u{9762}\u{8BBE}\u{8BA1}\u{3001}\u{4EA4}\u{4E92}\u{903B}\u{8F91}\u{548C}\u{6570}\u{636E}\u{5904}\u{7406}\u{3002}`;
5738
- const sdkTemplatePrompt = `\u{4F60}\u{662F}\u{540E}\u{7AEF}\u{6280}\u{672F}\u{6587}\u{6863}\u{4E13}\u{5BB6}\u{3002}\u{57FA}\u{4E8E}\u{8F93}\u{5165}\u{5185}\u{5BB9}\u{751F}\u{6210}\u{5B8C}\u{6574}\u{7684}\u{4E09}\u{65B9}SDK\u{96C6}\u{6210}\u{6280}\u{672F}\u{9700}\u{6C42}\u{6587}\u{6863}\u{FF08}Markdown\u{683C}\u{5F0F}\u{FF0C}1500\u{5B57}\u{4EE5}\u{4E0A}\u{FF09}\u{3002}
5739
-
5740
- **\u{8F93}\u{5165}**: \u{529F}\u{80FD}\u{540D}\u{79F0}={featureName}, \u{4E1A}\u{52A1}\u{9886}\u{57DF}={businessDomain}
5741
-
5742
- **\u{539F}\u{59CB}\u{9700}\u{6C42}**:
5743
- \`\`\`
5744
- {inputContent}
5745
- \`\`\`
5746
-
5747
- ## \u{6587}\u{6863}\u{7ED3}\u{6784}\u{8981}\u{6C42}
5748
- \u{8BF7}\u{4E25}\u{683C}\u{6309}\u{7167}\u{4EE5}\u{4E0B}\u{7ED3}\u{6784}\u{8F93}\u{51FA}\u{5B8C}\u{6574}\u{7684}\u{9700}\u{6C42}\u{6587}\u{6863}\u{FF0C}\u{6BCF}\u{4E2A}\u{7AE0}\u{8282}\u{90FD}\u{8981}\u{6709}\u{8BE6}\u{5B9E}\u{7684}\u{5185}\u{5BB9}\u{FF1A}
5749
-
5750
- # {featureName} - \u{4E09}\u{65B9}SDK\u{96C6}\u{6210}\u{6280}\u{672F}\u{9700}\u{6C42}\u{6587}\u{6863}
5751
-
5752
- > **\u{751F}\u{6210}\u{65F6}\u{95F4}**: {currentTime}
5753
- > **\u{4E1A}\u{52A1}\u{9886}\u{57DF}**: {businessDomain}
5754
- > **\u{96C6}\u{6210}\u{7C7B}\u{578B}**: \u{4E09}\u{65B9}SDK\u{96C6}\u{6210}
5755
6033
 
5756
6034
  ---
5757
6035
 
5758
- ## 1. \u{9700}\u{6C42}\u{6982}\u{8FF0}
5759
-
5760
- **\u{4E1A}\u{52A1}\u{80CC}\u{666F}**: [\u{63CF}\u{8FF0}SDK\u{96C6}\u{6210}\u{7684}\u{80CC}\u{666F}\u{3001}\u{4E1A}\u{52A1}\u{9700}\u{6C42}\u{548C}\u{76EE}\u{6807}]
5761
-
5762
- **\u{6838}\u{5FC3}\u{529F}\u{80FD}**: [\u{5217}\u{51FA}SDK\u{96C6}\u{6210}\u{7684}\u{4E3B}\u{8981}\u{529F}\u{80FD}\u{70B9}]
5763
-
5764
- ## 2. SDK\u{96C6}\u{6210}\u{8BBE}\u{8BA1}
5765
-
5766
- ### 2.1 \u{63A5}\u{5165}\u{6D41}\u{7A0B}
5767
- [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}SDK\u{63A5}\u{5165}\u{7684}\u{51C6}\u{5907}\u{5DE5}\u{4F5C}\u{548C}\u{914D}\u{7F6E}\u{6D41}\u{7A0B}]
5768
-
5769
- ### 2.2 \u{521D}\u{59CB}\u{5316}\u{914D}\u{7F6E}
5770
- [\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}SDK\u{7684}\u{521D}\u{59CB}\u{5316}\u{914D}\u{7F6E}\u{8FC7}\u{7A0B}]
5771
-
5772
- ## 3. \u{63A5}\u{53E3}\u{8C03}\u{7528}\u{8BF4}\u{660E}
5773
-
5774
- ### 3.1 \u{4E3B}\u{8981}API\u{63A5}\u{53E3}
5775
- [\u{5217}\u{51FA}SDK\u{63D0}\u{4F9B}\u{7684}\u{4E3B}\u{8981}API\u{63A5}\u{53E3}]
5776
-
5777
- ### 3.2 \u{63A5}\u{53E3}\u{8C03}\u{7528}\u{793A}\u{4F8B}
5778
- [\u{63D0}\u{4F9B}\u{8BE6}\u{7EC6}\u{7684}\u{63A5}\u{53E3}\u{8C03}\u{7528}\u{793A}\u{4F8B}\u{4EE3}\u{7801}]
5779
-
5780
- ### 3.3 \u{53C2}\u{6570}\u{8BF4}\u{660E}
5781
- [\u{8BE6}\u{7EC6}\u{8BF4}\u{660E}\u{5404}\u{63A5}\u{53E3}\u{7684}\u{8BF7}\u{6C42}\u{53C2}\u{6570}\u{548C}\u{54CD}\u{5E94}\u{6570}\u{636E}\u{7ED3}\u{6784}]
5782
-
5783
- |\u{53C2}\u{6570}\u{540D}\u{79F0}|\u{7C7B}\u{578B}|\u{662F}\u{5426}\u{5FC5}\u{586B}|\u{8BF4}\u{660E}|
5784
- |------|------|------|------|
5785
- |[\u{53C2}\u{6570}1]|[string/number\u{7B49}]|[\u{662F}/\u{5426}]|[\u{8BE6}\u{7EC6}\u{8BF4}\u{660E}]|
5786
- |[\u{53C2}\u{6570}2]|[string/number\u{7B49}]|[\u{662F}/\u{5426}]|[\u{8BE6}\u{7EC6}\u{8BF4}\u{660E}]|
5787
-
5788
- ## 4. \u{4EA4}\u{4E92}\u{903B}\u{8F91}
5789
-
5790
- ### 4.1 \u{8C03}\u{7528}\u{65F6}\u{5E8F}
5791
- [\u{63CF}\u{8FF0}SDK\u{8C03}\u{7528}\u{7684}\u{65F6}\u{5E8F}\u{903B}\u{8F91}]
5792
-
5793
- ### 4.2 \u{9519}\u{8BEF}\u{5904}\u{7406}
5794
- [\u{63CF}\u{8FF0}SDK\u{8C03}\u{7528}\u{5F02}\u{5E38}\u{7684}\u{5904}\u{7406}\u{903B}\u{8F91}]
5795
-
5796
- ## 5. \u{5B89}\u{5168}\u{4E0E}\u{6027}\u{80FD}
5797
-
5798
- ### 5.1 \u{5B89}\u{5168}\u{6027}\u{8003}\u{8651}
5799
- [\u{63CF}\u{8FF0}\u{6570}\u{636E}\u{52A0}\u{5BC6}\u{3001}\u{8BBF}\u{95EE}\u{63A7}\u{5236}\u{7B49}\u{5B89}\u{5168}\u{8981}\u{6C42}]
5800
-
5801
- ### 5.2 \u{6027}\u{80FD}\u{4F18}\u{5316}
5802
- [\u{63CF}\u{8FF0}SDK\u{8C03}\u{7528}\u{7684}\u{6027}\u{80FD}\u{8981}\u{6C42}\u{548C}\u{4F18}\u{5316}\u{7B56}\u{7565}]
5803
-
5804
- ## 6. \u{4E1A}\u{52A1}\u{6D41}\u{7A0B}
5805
-
5806
- [\u{4F7F}\u{7528}\u{7B80}\u{5355}\u{7684}mermaid\u{6D41}\u{7A0B}\u{56FE}\u{63CF}\u{8FF0}\u{4E3B}\u{8981}\u{4E1A}\u{52A1}\u{6D41}\u{7A0B}]
5807
-
5808
- \`\`\`mermaid
5809
- graph TD
5810
- A[\u{5F00}\u{59CB}] --> B[\u{5904}\u{7406}]
5811
- B --> C[\u{7ED3}\u{675F}]
5812
- \`\`\`
5813
-
5814
- ---
5815
-
5816
- **\u{8981}\u{6C42}**: \u{8F93}\u{51FA}\u{5B8C}\u{6574}\u{6587}\u{6863}\u{FF0C}\u{6BCF}\u{7AE0}\u{8282}\u{6709}\u{5B9E}\u{8D28}\u{5185}\u{5BB9}\u{FF0C}\u{8868}\u{683C}\u{586B}\u{5199}\u{5177}\u{4F53}\u{4FE1}\u{606F}\u{FF0C}\u{91CD}\u{70B9}\u{5173}\u{6CE8}SDK\u{63A5}\u{5165}\u{6D41}\u{7A0B}\u{3001}\u{63A5}\u{53E3}\u{8C03}\u{7528}\u{548C}\u{6570}\u{636E}\u{7ED3}\u{6784}\u{3002}`;
5817
- const apiTemplatePrompt = `\u{4F60}\u{662F}\u{540E}\u{7AEF}\u{6280}\u{672F}\u{6587}\u{6863}\u{4E13}\u{5BB6}\u{3002}\u{57FA}\u{4E8E}\u{8F93}\u{5165}\u{5185}\u{5BB9}\u{751F}\u{6210}\u{5B8C}\u{6574}\u{7684}API\u{63A5}\u{53E3}\u{6280}\u{672F}\u{9700}\u{6C42}\u{6587}\u{6863}\u{FF08}Markdown\u{683C}\u{5F0F}\u{FF0C}3000\u{5B57}\u{4EE5}\u{4E0A}\u{FF09}\u{3002}
6036
+ **\u{8981}\u{6C42}**: \u{8F93}\u{51FA}\u{5B8C}\u{6574}\u{6587}\u{6863}\u{FF0C}\u{6BCF}\u{7AE0}\u{8282}\u{6709}\u{5B9E}\u{8D28}\u{5185}\u{5BB9}\u{FF0C}\u{8868}\u{683C}\u{586B}\u{5199}\u{5177}\u{4F53}\u{4FE1}\u{606F}\u{FF0C}\u{91CD}\u{70B9}\u{5173}\u{6CE8}\u{9875}\u{9762}\u{5E03}\u{5C40}\u{3001}\u{6837}\u{5F0F}\u{3001}\u{4EA4}\u{4E92}\u{903B}\u{8F91}\u{3002}\u{6839}\u{636E}pageType\u{8C03}\u{6574}\u{5185}\u{5BB9}\u{4FA7}\u{91CD}\u{70B9}\u{3002}`;
6037
+ const api_template_apiTemplatePrompt = `\u{4F60}\u{662F}\u{540E}\u{7AEF}\u{6280}\u{672F}\u{6587}\u{6863}\u{4E13}\u{5BB6}\u{3002}\u{57FA}\u{4E8E}\u{8F93}\u{5165}\u{5185}\u{5BB9}\u{751F}\u{6210}\u{5B8C}\u{6574}\u{7684}API\u{63A5}\u{53E3}\u{6280}\u{672F}\u{9700}\u{6C42}\u{6587}\u{6863}\u{FF08}Markdown\u{683C}\u{5F0F}\u{FF0C}3000\u{5B57}\u{4EE5}\u{4E0A}\u{FF09}\u{3002}
5818
6038
 
5819
6039
  **\u{8F93}\u{5165}**: \u{529F}\u{80FD}\u{540D}\u{79F0}={featureName}, \u{4E1A}\u{52A1}\u{9886}\u{57DF}={businessDomain}, \u{751F}\u{6210}\u{65F6}\u{5E8F}\u{56FE}={generateSequenceDiagram}
5820
6040
 
@@ -5858,11 +6078,61 @@ graph TD
5858
6078
  ## 3. \u{6570}\u{636E}\u{5EFA}\u{6A21}
5859
6079
  ## 3.1 ER\u{903B}\u{8F91}\u{56FE}\u{8BBE}\u{8BA1}
5860
6080
 
5861
- [\u{63CF}\u{8FF0}\u{6570}\u{636E}\u{5E93}\u{8868}\u{FF08}\u{8981}\u{5305}\u{542B}\u{6570}\u{636E}\u{5E93}\u{4E2D}\u{6587}\u{548C}\u{82F1}\u{6587}\u{540D}\u{79F0}\u{FF0C}\u{6570}\u{636E}\u{5E93}\u{8868}\u{5B57}\u{6BB5}\u{FF09}\u{4E4B}\u{95F4}\u{7684}\u{5173}\u{7CFB}\u{548C}ER\u{56FE}\u{8BBE}\u{8BA1}]
6081
+ \u{57FA}\u{4E8E}\u{9700}\u{6C42}\u{5206}\u{6790}\u{FF0C}\u{8BBE}\u{8BA1}\u{4EE5}\u{4E0B}\u{6570}\u{636E}\u{5E93}\u{8868}\u{5173}\u{7CFB}\u{FF1A}
6082
+ - \u{7528}\u{6237}\u{8868} (users): \u{5B58}\u{50A8}\u{7528}\u{6237}\u{57FA}\u{672C}\u{4FE1}\u{606F}\u{FF0C}\u{5982}\u{7528}\u{6237}\u{540D}\u{3001}\u{90AE}\u{7BB1}\u{3001}\u{5BC6}\u{7801}\u{7B49}
6083
+ - \u{8BA2}\u{5355}\u{8868} (orders): \u{5B58}\u{50A8}\u{8BA2}\u{5355}\u{4FE1}\u{606F}\u{FF0C}\u{4E0E}\u{7528}\u{6237}\u{8868}\u{4E00}\u{5BF9}\u{591A}\u{5173}\u{7CFB}
6084
+ - \u{4EA7}\u{54C1}\u{8868} (products): \u{5B58}\u{50A8}\u{4EA7}\u{54C1}\u{4FE1}\u{606F}\u{FF0C}\u{4E0E}\u{8BA2}\u{5355}\u{8868}\u{591A}\u{5BF9}\u{591A}\u{5173}\u{7CFB}\u{FF08}\u{901A}\u{8FC7}\u{8BA2}\u{5355}\u{9879}\u{8868}\u{5173}\u{8054}\u{FF09}
6085
+
6086
+ \u{8BF7}\u{6839}\u{636E}\u{5177}\u{4F53}\u{9700}\u{6C42}\u{8BBE}\u{8BA1}\u{6570}\u{636E}\u{5E93}\u{8868}\u{7ED3}\u{6784}\u{FF0C}\u{5305}\u{62EC}\u{FF1A}
6087
+ 1. \u{8868}\u{7684}\u{4E2D}\u{82F1}\u{6587}\u{540D}\u{79F0}
6088
+ 2. \u{8868}\u{5B57}\u{6BB5}\u{5B9A}\u{4E49}\u{FF08}\u{5B57}\u{6BB5}\u{540D}\u{3001}\u{7C7B}\u{578B}\u{3001}\u{7EA6}\u{675F}\u{6761}\u{4EF6}\u{FF09}
6089
+ 3. \u{8868}\u{4E4B}\u{95F4}\u{7684}\u{5173}\u{7CFB}\u{FF08}\u{4E00}\u{5BF9}\u{4E00}\u{3001}\u{4E00}\u{5BF9}\u{591A}\u{3001}\u{591A}\u{5BF9}\u{591A}\u{FF09}
6090
+ 4. \u{4E3B}\u{952E}\u{548C}\u{5916}\u{952E}\u{7EA6}\u{675F}
6091
+
5862
6092
  \`\`\`mermaid
6093
+ erDiagram
6094
+ users ||--o{ orders : "\u{62E5}\u{6709}"
6095
+ orders ||--o{ order_items : "\u{5305}\u{542B}"
6096
+ products ||--o{ order_items : "\u{88AB}\u{8D2D}\u{4E70}"
6097
+ users {
6098
+ int id PK
6099
+ string username
6100
+ string email
6101
+ string password_hash
6102
+ datetime created_at
6103
+ datetime updated_at
6104
+ }
6105
+ orders {
6106
+ int id PK
6107
+ int user_id FK
6108
+ decimal total_amount
6109
+ string status
6110
+ datetime order_date
6111
+ datetime created_at
6112
+ }
6113
+ products {
6114
+ int id PK
6115
+ string name
6116
+ string description
6117
+ decimal price
6118
+ int stock_quantity
6119
+ datetime created_at
6120
+ }
6121
+ order_items {
6122
+ int id PK
6123
+ int order_id FK
6124
+ int product_id FK
6125
+ int quantity
6126
+ decimal unit_price
6127
+ decimal subtotal
6128
+ }
5863
6129
  \`\`\`
5864
6130
 
5865
- [\u{63CF}\u{8FF0}\u{5BF9}\u{8C61}\u{4E4B}\u{95F4}\u{7684}\u{5173}\u{7CFB}]
6131
+ **\u{6570}\u{636E}\u{5E93}\u{8868}\u{5173}\u{7CFB}\u{8BF4}\u{660E}\u{FF1A}**
6132
+ - **\u{7528}\u{6237}-\u{8BA2}\u{5355}\u{5173}\u{7CFB}**: \u{4E00}\u{5BF9}\u{591A}\u{5173}\u{7CFB}\u{FF0C}\u{4E00}\u{4E2A}\u{7528}\u{6237}\u{53EF}\u{4EE5}\u{62E5}\u{6709}\u{591A}\u{4E2A}\u{8BA2}\u{5355}
6133
+ - **\u{8BA2}\u{5355}-\u{8BA2}\u{5355}\u{9879}\u{5173}\u{7CFB}**: \u{4E00}\u{5BF9}\u{591A}\u{5173}\u{7CFB}\u{FF0C}\u{4E00}\u{4E2A}\u{8BA2}\u{5355}\u{53EF}\u{4EE5}\u{5305}\u{542B}\u{591A}\u{4E2A}\u{8BA2}\u{5355}\u{9879}
6134
+ - **\u{4EA7}\u{54C1}-\u{8BA2}\u{5355}\u{9879}\u{5173}\u{7CFB}**: \u{4E00}\u{5BF9}\u{591A}\u{5173}\u{7CFB}\u{FF0C}\u{4E00}\u{4E2A}\u{4EA7}\u{54C1}\u{53EF}\u{4EE5}\u{88AB}\u{591A}\u{4E2A}\u{8BA2}\u{5355}\u{9879}\u{8D2D}\u{4E70}
6135
+ - **\u{8BA2}\u{5355}\u{9879}\u{8868}**: \u{4F5C}\u{4E3A}\u{4E2D}\u{95F4}\u{8868}\u{FF0C}\u{5B9E}\u{73B0}\u{8BA2}\u{5355}\u{548C}\u{4EA7}\u{54C1}\u{7684}\u{591A}\u{5BF9}\u{591A}\u{5173}\u{7CFB}
5866
6136
 
5867
6137
  ## 4. \u{6570}\u{636E}\u{8868}\u{5B9E}\u{4F53}\u{8BBE}\u{8BA1}
5868
6138
 
@@ -5957,36 +6227,28 @@ Scenario Outline: \u{7528}\u{6237}\u{901A}\u{8FC7}API\u{67E5}\u{8BE2}\u{8BA2}\u{
5957
6227
  class TemplateSelector {
5958
6228
  templateMap = new Map([
5959
6229
  [
5960
- "PC\u9875\u9762",
5961
- pcPageTemplatePrompt
5962
- ],
5963
- [
5964
- "APP",
5965
- appTemplatePrompt
6230
+ "HTML",
6231
+ htmlPageTemplatePrompt
5966
6232
  ],
5967
6233
  [
5968
- "SDK\u96C6\u6210",
5969
- sdkTemplatePrompt
6234
+ "html",
6235
+ htmlPageTemplatePrompt
5970
6236
  ],
5971
6237
  [
5972
- "\u63A5\u53E3",
5973
- apiTemplatePrompt
6238
+ "API",
6239
+ api_template_apiTemplatePrompt
5974
6240
  ],
5975
6241
  [
5976
6242
  "api",
5977
- apiTemplatePrompt
5978
- ],
5979
- [
5980
- "pc",
5981
- pcPageTemplatePrompt
6243
+ api_template_apiTemplatePrompt
5982
6244
  ],
5983
6245
  [
5984
- "app",
5985
- appTemplatePrompt
6246
+ "\u63A5\u53E3",
6247
+ api_template_apiTemplatePrompt
5986
6248
  ],
5987
6249
  [
5988
- "sdk",
5989
- sdkTemplatePrompt
6250
+ "\u9875\u9762",
6251
+ htmlPageTemplatePrompt
5990
6252
  ]
5991
6253
  ]);
5992
6254
  selectTemplate(requirementType) {
@@ -6031,33 +6293,18 @@ Scenario Outline: \u{7528}\u{6237}\u{901A}\u{8FC7}API\u{67E5}\u{8BE2}\u{8BA2}\u{
6031
6293
  "ui",
6032
6294
  "\u7F51\u9875",
6033
6295
  "\u6D4F\u89C8\u5668",
6034
- "\u524D\u7AEF"
6035
- ])) return {
6036
- type: "PC\u9875\u9762",
6037
- template: pcPageTemplatePrompt
6038
- };
6039
- if (this.containsAny(lowerType, [
6296
+ "\u524D\u7AEF",
6297
+ "html",
6040
6298
  "app",
6041
6299
  "\u79FB\u52A8",
6042
6300
  "ios",
6043
6301
  "android",
6044
6302
  "\u5C0F\u7A0B\u5E8F",
6045
- "\u79FB\u52A8\u7AEF"
6046
- ])) return {
6047
- type: "APP",
6048
- template: appTemplatePrompt
6049
- };
6050
- if (this.containsAny(lowerType, [
6051
- "sdk",
6052
- "\u7B2C\u4E09\u65B9",
6053
- "\u96C6\u6210",
6054
- "\u5BF9\u63A5",
6055
- "\u652F\u4ED8",
6056
- "\u5730\u56FE",
6057
- "\u63A8\u9001"
6303
+ "\u79FB\u52A8\u7AEF",
6304
+ "\u54CD\u5E94\u5F0F"
6058
6305
  ])) return {
6059
- type: "SDK\u96C6\u6210",
6060
- template: sdkTemplatePrompt
6306
+ type: "HTML",
6307
+ template: htmlPageTemplatePrompt
6061
6308
  };
6062
6309
  if (this.containsAny(lowerType, [
6063
6310
  "\u63A5\u53E3",
@@ -6069,7 +6316,7 @@ Scenario Outline: \u{7528}\u{6237}\u{901A}\u{8FC7}API\u{67E5}\u{8BE2}\u{8BA2}\u{
6069
6316
  "\u670D\u52A1\u7AEF"
6070
6317
  ])) return {
6071
6318
  type: "\u63A5\u53E3",
6072
- template: apiTemplatePrompt
6319
+ template: api_template_apiTemplatePrompt
6073
6320
  };
6074
6321
  return null;
6075
6322
  }
@@ -6145,7 +6392,7 @@ Scenario Outline: \u{7528}\u{6237}\u{901A}\u{8FC7}API\u{67E5}\u{8BE2}\u{8BA2}\u{
6145
6392
  cleanedCount
6146
6393
  });
6147
6394
  }
6148
- async generateUnifiedDocument(analysis, projectInfo, featureName, sourceInfo, customPrompt, currentProjectPath) {
6395
+ async generateUnifiedDocument(analysis, projectInfo, featureName, sourceInfo, customPrompt, currentProjectPath, pageStyle, pageType) {
6149
6396
  try {
6150
6397
  logger.info("\u51C6\u5907\u751F\u6210\u7EDF\u4E00\u6280\u672F\u6587\u6863\u4EFB\u52A1", {
6151
6398
  featureName,
@@ -6153,7 +6400,10 @@ Scenario Outline: \u{7528}\u{6237}\u{901A}\u{8FC7}API\u{67E5}\u{8BE2}\u{8BA2}\u{
6153
6400
  featureCount: analysis.requirements.length,
6154
6401
  currentProjectPath
6155
6402
  });
6156
- const requirementTypes = this.parseRequirementTypes(analysis.requirementType);
6403
+ const requirementTypes = [
6404
+ "API",
6405
+ "HTML"
6406
+ ];
6157
6407
  const generationTasks = await Promise.all(requirementTypes.map(async (reqType)=>{
6158
6408
  logger.info("\u51C6\u5907\u62A5\u544A\u751F\u6210\u4EFB\u52A1", {
6159
6409
  requirementType: reqType,
@@ -6177,13 +6427,19 @@ Scenario Outline: \u{7528}\u{6237}\u{901A}\u{8FC7}API\u{67E5}\u{8BE2}\u{8BA2}\u{
6177
6427
  prompt: promptData.prompt,
6178
6428
  systemPrompt: promptData.systemPrompt,
6179
6429
  templateContent: promptData.templateContent,
6180
- templateVariables: "templateVariables" in promptData ? promptData.templateVariables : {
6430
+ templateVariables: "templateVariables" in promptData ? {
6431
+ ...promptData.templateVariables,
6432
+ pageStyle,
6433
+ pageType: pageType || "responsive"
6434
+ } : {
6181
6435
  featureName: featureName,
6182
6436
  inputContent: this.buildUnifiedContent(analysis, projectInfo, featureName, sourceInfo),
6183
6437
  currentTime: new Date().toISOString(),
6184
6438
  businessDomain: this.mapRequirementTypeToBusinessDomain(reqType),
6185
6439
  generateSequenceDiagram: "true",
6186
- customPrompt
6440
+ customPrompt,
6441
+ pageStyle,
6442
+ pageType: pageType || "responsive"
6187
6443
  },
6188
6444
  existingContent: "existingContent" in promptData ? promptData.existingContent : void 0
6189
6445
  };
@@ -6256,18 +6512,72 @@ Scenario Outline: \u{7528}\u{6237}\u{901A}\u{8FC7}API\u{67E5}\u{8BE2}\u{8BA2}\u{
6256
6512
  }
6257
6513
  buildUnifiedContent(analysis, projectInfo, featureName, sourceInfo) {
6258
6514
  const featuresToProcess = analysis.featureDependencies?.mergedFeatures || analysis.requirements;
6515
+ const enrichedContext = analysis.enrichedContext || {};
6516
+ const businessContext = analysis.businessContext || {};
6517
+ const technicalContext = analysis.technicalContext || {};
6518
+ const documentationHints = analysis.documentationHints || {};
6259
6519
  const combinedFeatureContent = featuresToProcess.map((feature, index)=>{
6260
6520
  const featureTitle = "title" in feature ? feature.title : feature.featureName;
6261
6521
  const featureContent = "fullContent" in feature ? feature.fullContent : feature.description;
6262
- return `## \u{529F}\u{80FD}\u{70B9}${index + 1}\u{FF1A}${featureTitle}\n\n${featureContent}`;
6263
- }).join("\n\n");
6522
+ const businessFlow = feature.businessFlow || {};
6523
+ const dataEntities = feature.dataEntities || [];
6524
+ const interactions = feature.interactions || [];
6525
+ let content = `## \u{529F}\u{80FD}\u{70B9}${index + 1}\u{FF1A}${featureTitle}\n\n${featureContent}`;
6526
+ if (businessFlow.mainFlow?.length > 0) {
6527
+ content += `
6528
+
6529
+ ### \u{4E1A}\u{52A1}\u{6D41}\u{7A0B}
6530
+ `;
6531
+ if (businessFlow.preconditions?.length > 0) content += `**\u{524D}\u{7F6E}\u{6761}\u{4EF6}**: ${businessFlow.preconditions.join("\u3001")}\n`;
6532
+ content += `**\u{4E3B}\u{6D41}\u{7A0B}**:
6533
+ ${businessFlow.mainFlow.map((step, i)=>`${i + 1}. ${step}`).join("\n")}\n`;
6534
+ if (businessFlow.exceptionFlows?.length > 0) content += `**\u{5F02}\u{5E38}\u{5904}\u{7406}**: ${businessFlow.exceptionFlows.join("\u3001")}\n`;
6535
+ }
6536
+ if (dataEntities.length > 0) {
6537
+ content += `
6538
+
6539
+ ### \u{6570}\u{636E}\u{5B9E}\u{4F53}
6540
+ `;
6541
+ dataEntities.forEach((entity)=>{
6542
+ content += `**${entity.name}**:\n`;
6543
+ if (entity.fields?.length > 0) {
6544
+ content += `| \u{5B57}\u{6BB5}\u{540D} | \u{7C7B}\u{578B} | \u{5FC5}\u{586B} | \u{8BF4}\u{660E} |
6545
+ |---|---|---|---|
6546
+ `;
6547
+ entity.fields.forEach((field)=>{
6548
+ content += `| ${field.name} | ${field.type} | ${field.required ? "\u662F" : "\u5426"} | ${field.description} |\n`;
6549
+ });
6550
+ }
6551
+ });
6552
+ }
6553
+ if (interactions.length > 0) {
6554
+ content += `
6555
+
6556
+ ### \u{4EA4}\u{4E92}\u{903B}\u{8F91}
6557
+ `;
6558
+ interactions.forEach((interaction)=>{
6559
+ content += `- **\u{89E6}\u{53D1}**: ${interaction.trigger} \u{2192} **\u{52A8}\u{4F5C}**: ${interaction.action} \u{2192} **\u{54CD}\u{5E94}**: ${interaction.response}\n`;
6560
+ });
6561
+ }
6562
+ return content;
6563
+ }).join("\n\n---\n\n");
6264
6564
  return `# ${featureName} - \u{7EDF}\u{4E00}\u{9700}\u{6C42}\u{5206}\u{6790}
6265
6565
 
6266
6566
  ## \u{9879}\u{76EE}\u{57FA}\u{672C}\u{4FE1}\u{606F}
6267
6567
  - **\u{9879}\u{76EE}\u{7C7B}\u{578B}**: ${projectInfo?.projectType || "\u901A\u7528\u9879\u76EE"}
6268
- - **\u{4E3B}\u{8981}\u{6280}\u{672F}\u{6808}**: ${projectInfo?.techStack?.join(", ") || "\u5F85\u786E\u5B9A"}
6568
+ - **\u{4E3B}\u{8981}\u{6280}\u{672F}\u{6808}**: ${projectInfo?.techStack?.join(", ") || enrichedContext.techStack?.join(", ") || "\u5F85\u786E\u5B9A"}
6269
6569
  - **\u{5F00}\u{53D1}\u{6846}\u{67B6}**: ${projectInfo?.frameworks?.join(", ") || "\u5F85\u786E\u5B9A"}
6270
6570
  - **\u{7F16}\u{7A0B}\u{8BED}\u{8A00}**: ${projectInfo?.language || "\u5F85\u786E\u5B9A"}
6571
+ - **\u{4E1A}\u{52A1}\u{9886}\u{57DF}**: ${enrichedContext.businessDomain || "\u901A\u7528"}
6572
+
6573
+ ## \u{4E1A}\u{52A1}\u{80CC}\u{666F}
6574
+ ${businessContext.background || "\u57FA\u4E8E\u7528\u6237\u9700\u6C42\u8FDB\u884C\u529F\u80FD\u5F00\u53D1"}
6575
+
6576
+ ### \u{4E1A}\u{52A1}\u{76EE}\u{6807}
6577
+ ${businessContext.objectives?.map((obj)=>`- ${obj}`).join("\n") || "- \u6EE1\u8DB3\u7528\u6237\u9700\u6C42\n- \u63D0\u5347\u7CFB\u7EDF\u529F\u80FD"}
6578
+
6579
+ ### \u{6D89}\u{53CA}\u{89D2}\u{8272}
6580
+ ${businessContext.stakeholders?.map((role)=>`- ${role}`).join("\n") || "- \u7CFB\u7EDF\u7528\u6237\n- \u7CFB\u7EDF\u7BA1\u7406\u5458"}
6271
6581
 
6272
6582
  ## \u{9700}\u{6C42}\u{7C7B}\u{578B}\u{5206}\u{6790}
6273
6583
  - **\u{8BC6}\u{522B}\u{7C7B}\u{578B}**: ${analysis.requirementType}
@@ -6275,6 +6585,17 @@ Scenario Outline: \u{7528}\u{6237}\u{901A}\u{8FC7}API\u{67E5}\u{8BE2}\u{8BA2}\u{
6275
6585
  - **\u{529F}\u{80FD}\u{70B9}\u{6570}\u{91CF}**: ${featuresToProcess.length}\u{4E2A}
6276
6586
  - **\u{7F6E}\u{4FE1}\u{5EA6}**: ${analysis.confidence || "medium"}
6277
6587
 
6588
+ ## \u{6280}\u{672F}\u{4E0A}\u{4E0B}\u{6587}
6589
+ - **\u{5EFA}\u{8BAE}\u{6280}\u{672F}\u{6808}**: ${technicalContext.suggestedTechStack?.join(", ") || "\u6839\u636E\u9879\u76EE\u73B0\u6709\u6280\u672F\u6808"}
6590
+ - **\u{96C6}\u{6210}\u{70B9}**: ${technicalContext.integrationPoints?.join(", ") || "\u65E0"}
6591
+ - **\u{5B89}\u{5168}\u{8981}\u{6C42}**: ${technicalContext.securityRequirements?.join(", ") || "\u6807\u51C6\u5B89\u5168\u89C4\u8303"}
6592
+ - **\u{6027}\u{80FD}\u{8981}\u{6C42}**: ${technicalContext.performanceRequirements?.join(", ") || "\u6807\u51C6\u6027\u80FD\u8981\u6C42"}
6593
+
6594
+ ## \u{6587}\u{6863}\u{751F}\u{6210}\u{63D0}\u{793A}
6595
+ - **\u{9700}\u{8981}\u{7684}\u{65F6}\u{5E8F}\u{56FE}**: ${documentationHints.keySequenceDiagrams?.join(", ") || "\u4E3B\u6D41\u7A0B\u65F6\u5E8F\u56FE"}
6596
+ - **\u{9700}\u{8981}\u{7684}ER\u{56FE}**: ${documentationHints.keyERDiagrams?.join(", ") || "\u6838\u5FC3\u6570\u636E\u5B9E\u4F53"}
6597
+ - **\u{9700}\u{8981}\u{7684}\u{8868}\u{683C}**: ${documentationHints.keyTables?.join(", ") || "\u5B57\u6BB5\u8BF4\u660E\u8868\u3001\u63A5\u53E3\u53C2\u6570\u8868"}
6598
+
6278
6599
  ## \u{529F}\u{80FD}\u{70B9}\u{8BE6}\u{7EC6}\u{63CF}\u{8FF0}
6279
6600
 
6280
6601
  ${combinedFeatureContent}
@@ -6650,6 +6971,7 @@ ${existingContent}
6650
6971
  currentTime: new Date().toISOString(),
6651
6972
  businessDomain,
6652
6973
  generateSequenceDiagram: "true",
6974
+ generateERDiagram: "true",
6653
6975
  customPrompt
6654
6976
  };
6655
6977
  let prompt = template;
@@ -6673,6 +6995,7 @@ ${customPrompt}`;
6673
6995
  currentTime: new Date().toISOString(),
6674
6996
  businessDomain,
6675
6997
  generateSequenceDiagram: "true",
6998
+ generateERDiagram: "true",
6676
6999
  customPrompt,
6677
7000
  existingContent
6678
7001
  };
@@ -6715,7 +7038,7 @@ ${customPrompt}` : ""}
6715
7038
  }
6716
7039
  buildDocumentPrompt(template, content, title, projectInfo, customPrompt, requirementType) {
6717
7040
  const businessDomain = this.mapRequirementTypeToBusinessDomain(requirementType);
6718
- let prompt = template.replace(/\{featureName\}/g, title).replace(/\{inputContent\}/g, content).replace(/\{currentTime\}/g, new Date().toISOString()).replace(/\{businessDomain\}/g, businessDomain).replace(/\{generateSequenceDiagram\}/g, "true");
7041
+ let prompt = template.replace(/\{featureName\}/g, title).replace(/\{inputContent\}/g, content).replace(/\{currentTime\}/g, new Date().toISOString()).replace(/\{businessDomain\}/g, businessDomain).replace(/\{generateSequenceDiagram\}/g, "true").replace(/\{generateERDiagram\}/g, "true");
6719
7042
  if (customPrompt) prompt += `
6720
7043
 
6721
7044
  ## \u{81EA}\u{5B9A}\u{4E49}\u{8981}\u{6C42}
@@ -6809,6 +7132,9 @@ ${customPrompt}` : ""}
6809
7132
  if (!document.includes(title)) logger.warn("\u751F\u6210\u7684\u6587\u6863\u53EF\u80FD\u4E0E\u9700\u6C42\u6807\u9898\u4E0D\u5339\u914D", {
6810
7133
  title
6811
7134
  });
7135
+ if (document.includes("## 3.1 ER\u903B\u8F91\u56FE\u8BBE\u8BA1") && !document.includes("erDiagram") && !document.includes("entity")) logger.warn("\u751F\u6210\u7684\u6587\u6863\u53EF\u80FD\u7F3A\u5C11ER\u56FE\u5185\u5BB9", {
7136
+ title
7137
+ });
6812
7138
  }
6813
7139
  buildAnalysisResult(analysis, projectInfo, outputPath, sourceInfo, isUpdate = false, generatedFiles, analysisInfos) {
6814
7140
  const featuresToProcess = analysis.featureDependencies?.mergedFeatures || analysis.requirements;
@@ -6955,14 +7281,14 @@ ${generationTasks?.map((task, i)=>`
6955
7281
  async analyzeRequirements(params) {
6956
7282
  try {
6957
7283
  logger.info("\u5F00\u59CB\u9700\u6C42\u5206\u6790\u6D41\u7A0B", {
6958
- requirementType: params.requirement_type,
6959
- projectPath: params.current_project_path
7284
+ projectPath: params.current_project_path,
7285
+ hasPageStyle: !!params.page_style
6960
7286
  });
6961
- const { requirementContent, projectInfo } = this.parseRequirementAnalysis(params.requirement_analysis);
7287
+ const { requirementContent, projectInfo, enrichedContext } = this.parseRequirementAnalysis(params.requirement_analysis);
6962
7288
  const requirementAnalysis = await this.intelligentAnalyzer.analyzeRequirements(requirementContent, projectInfo, void 0);
6963
- const finalRequirementType = params.requirement_type || requirementAnalysis.requirementType;
6964
- requirementAnalysis.requirementType = finalRequirementType;
6965
- return await this.documentGenerator.generateUnifiedDocument(requirementAnalysis, projectInfo, this.extractFeatureName(requirementContent), "requirement-identifier\u5206\u6790\u7ED3\u679C", void 0, params.current_project_path);
7289
+ requirementAnalysis.requirementType = "PC+API";
7290
+ requirementAnalysis.enrichedContext = enrichedContext;
7291
+ return await this.documentGenerator.generateUnifiedDocument(requirementAnalysis, projectInfo, this.extractFeatureName(requirementContent), "requirement-identifier\u5206\u6790\u7ED3\u679C", void 0, params.current_project_path, params.page_style, params.page_type);
6966
7292
  } catch (error) {
6967
7293
  if (error instanceof RequirementAnalysisError) throw error;
6968
7294
  logger.error("\u9700\u6C42\u5206\u6790\u6D41\u7A0B\u5931\u8D25", {
@@ -6978,15 +7304,32 @@ ${generationTasks?.map((task, i)=>`
6978
7304
  parseRequirementAnalysis(analysisResult) {
6979
7305
  try {
6980
7306
  const parsed = JSON.parse(analysisResult);
7307
+ const enrichedContext = {
7308
+ originalRequirement: parsed.requirement_description || parsed.data?.guidance || "",
7309
+ techStack: parsed.project_context?.techStack || [],
7310
+ codeStructure: parsed.project_context?.codeStructure || {},
7311
+ businessDomain: parsed.project_context?.businessDomain || "\u901A\u7528",
7312
+ relatedFiles: parsed.project_context?.relatedFiles || [],
7313
+ dependencies: parsed.project_context?.dependencies || []
7314
+ };
6981
7315
  return {
6982
7316
  requirementContent: parsed.requirement_description || parsed.data?.guidance || analysisResult,
6983
- projectInfo: parsed.project_context || this.getDefaultProjectInfo()
7317
+ projectInfo: parsed.project_context || this.getDefaultProjectInfo(),
7318
+ enrichedContext
6984
7319
  };
6985
7320
  } catch {
6986
7321
  logger.info("\u4F7F\u7528\u6587\u672C\u683C\u5F0F\u7684\u9700\u6C42\u5206\u6790\u7ED3\u679C");
6987
7322
  return {
6988
7323
  requirementContent: analysisResult,
6989
- projectInfo: this.getDefaultProjectInfo()
7324
+ projectInfo: this.getDefaultProjectInfo(),
7325
+ enrichedContext: {
7326
+ originalRequirement: analysisResult,
7327
+ techStack: [],
7328
+ codeStructure: {},
7329
+ businessDomain: "\u901A\u7528",
7330
+ relatedFiles: [],
7331
+ dependencies: []
7332
+ }
6990
7333
  };
6991
7334
  }
6992
7335
  }
@@ -7115,23 +7458,177 @@ ${generationTasks?.map((task, i)=>`
7115
7458
  };
7116
7459
  }
7117
7460
  }
7461
+ const DEFAULT_PAGE_STYLE = `<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
7462
+ <style>
7463
+ :root {
7464
+ --bg: #ffffff;
7465
+ --bg-secondary: #f8f9fa;
7466
+ --border: #e5e5e5;
7467
+ --text: #111111;
7468
+ --text-muted: #666666;
7469
+ --accent: #000000;
7470
+ }
7471
+ </style>`;
7472
+ const API_SECTIONS = [
7473
+ {
7474
+ id: "header",
7475
+ title: "\u6587\u6863\u5934\u90E8",
7476
+ prompt: "\u751F\u6210\u6587\u6863\u6807\u9898\u3001\u751F\u6210\u65F6\u95F4\u3001\u4E1A\u52A1\u9886\u57DF\u7B49\u5934\u90E8\u4FE1\u606F"
7477
+ },
7478
+ {
7479
+ id: "background",
7480
+ title: "\u9700\u6C42\u80CC\u666F",
7481
+ prompt: "\u751F\u6210\u9700\u6C42\u80CC\u666F\u3001\u5173\u952E\u529F\u80FD\u3001\u6D89\u53CA\u89D2\u8272"
7482
+ },
7483
+ {
7484
+ id: "design",
7485
+ title: "\u529F\u80FD\u8BBE\u8BA1\u8BF4\u660E",
7486
+ prompt: "\u751F\u6210\u529F\u80FD\u8BBE\u8BA1\u8BF4\u660E\u8868\u683C\uFF0C\u5305\u542B\u6D41\u7A0B\u7F16\u53F7\u3001\u524D\u7F6E\u6761\u4EF6\u3001\u89D2\u8272\u7B49"
7487
+ },
7488
+ {
7489
+ id: "dataModel",
7490
+ title: "\u6570\u636E\u5EFA\u6A21",
7491
+ prompt: "\u751F\u6210ER\u903B\u8F91\u56FE\u8BBE\u8BA1\uFF08\u4F7F\u7528mermaid erDiagram\uFF09\u548C\u6570\u636E\u8868\u5B9E\u4F53\u8BBE\u8BA1"
7492
+ },
7493
+ {
7494
+ id: "apiDesign",
7495
+ title: "API\u63A5\u53E3\u8BBE\u8BA1",
7496
+ prompt: "\u751F\u6210API\u63A5\u53E3\u5217\u8868\u3001\u8BF7\u6C42\u53C2\u6570\u3001\u54CD\u5E94\u53C2\u6570\u3001\u9519\u8BEF\u7801\u7B49"
7497
+ },
7498
+ {
7499
+ id: "sequence",
7500
+ title: "\u4E1A\u52A1\u65F6\u5E8F\u56FE",
7501
+ prompt: "\u751F\u6210\u4E1A\u52A1\u5BF9\u8C61\u65F6\u5E8F\u56FE\uFF08\u4F7F\u7528mermaid sequenceDiagram\uFF09"
7502
+ },
7503
+ {
7504
+ id: "status",
7505
+ title: "\u4E1A\u52A1\u72B6\u6001",
7506
+ prompt: "\u751F\u6210\u4E1A\u52A1\u72B6\u6001\u63CF\u8FF0\u8868\u683C"
7507
+ },
7508
+ {
7509
+ id: "pseudocode",
7510
+ title: "\u4F2A\u4EE3\u7801\u793A\u4F8B",
7511
+ prompt: "\u751F\u6210\u6838\u5FC3\u4E1A\u52A1\u903B\u8F91\u7684\u4F2A\u4EE3\u7801\u793A\u4F8B"
7512
+ }
7513
+ ];
7514
+ class ConcurrencyLimiter {
7515
+ maxConcurrent;
7516
+ running = 0;
7517
+ queue = [];
7518
+ constructor(maxConcurrent){
7519
+ this.maxConcurrent = maxConcurrent;
7520
+ }
7521
+ async run(fn) {
7522
+ while(this.running >= this.maxConcurrent)await new Promise((resolve)=>this.queue.push(resolve));
7523
+ this.running++;
7524
+ try {
7525
+ return await fn();
7526
+ } finally{
7527
+ this.running--;
7528
+ const next = this.queue.shift();
7529
+ if (next) next();
7530
+ }
7531
+ }
7532
+ }
7533
+ const apiLimiter = new ConcurrencyLimiter(18);
7534
+ async function generateApiSection(sectionDef, templateVariables) {
7535
+ return apiLimiter.run(async ()=>{
7536
+ try {
7537
+ const prompt = `\u{4F60}\u{662F}\u{6280}\u{672F}\u{6587}\u{6863}\u{4E13}\u{5BB6}\u{3002}\u{8BF7}\u{4E3A}"${templateVariables.featureName}"\u{7684}API\u{6587}\u{6863}\u{751F}\u{6210}"${sectionDef.title}"\u{7AE0}\u{8282}\u{3002}
7538
+
7539
+ ## \u{4EFB}\u{52A1}
7540
+ ${sectionDef.prompt}
7541
+
7542
+ ## \u{9700}\u{6C42}\u{4FE1}\u{606F}
7543
+ - \u{529F}\u{80FD}\u{540D}\u{79F0}: ${templateVariables.featureName}
7544
+ - \u{4E1A}\u{52A1}\u{9886}\u{57DF}: ${templateVariables.businessDomain}
7545
+ - \u{9700}\u{6C42}\u{8BE6}\u{60C5}: ${templateVariables.inputContent?.substring(0, 1500) || ''}
7546
+
7547
+ ## \u{8981}\u{6C42}
7548
+ - \u{5185}\u{5BB9}\u{8BE6}\u{5B9E}\u{5177}\u{4F53}\u{FF0C}\u{4E0D}\u{4F7F}\u{7528}\u{5360}\u{4F4D}\u{7B26}
7549
+ - \u{4F7F}\u{7528}\u{6B63}\u{786E}\u{7684}Markdown\u{683C}\u{5F0F}
7550
+ - \u{5982}\u{9700}\u{56FE}\u{8868}\u{4F7F}\u{7528}mermaid\u{8BED}\u{6CD5}
7551
+ - \u{8868}\u{683C}\u{586B}\u{5199}\u{5177}\u{4F53}\u{4FE1}\u{606F}
7552
+
7553
+ \u{76F4}\u{63A5}\u{8F93}\u{51FA}\u{8BE5}\u{7AE0}\u{8282}\u{7684}Markdown\u{5185}\u{5BB9}\u{FF08}\u{5305}\u{542B}\u{7AE0}\u{8282}\u{6807}\u{9898}\u{FF09}\u{3002}`;
7554
+ const content = await openAIService.generateText({
7555
+ prompt,
7556
+ system_prompt: "\u4F60\u662F\u6280\u672F\u6587\u6863\u4E13\u5BB6\uFF0C\u8F93\u51FA\u7B80\u6D01\u4E13\u4E1A\u7684\u6587\u6863\u7AE0\u8282\u3002",
7557
+ temperature: 0.7
7558
+ });
7559
+ return {
7560
+ id: sectionDef.id,
7561
+ title: sectionDef.title,
7562
+ content,
7563
+ success: true
7564
+ };
7565
+ } catch (error) {
7566
+ return {
7567
+ id: sectionDef.id,
7568
+ title: sectionDef.title,
7569
+ content: "",
7570
+ success: false,
7571
+ error: error.message
7572
+ };
7573
+ }
7574
+ });
7575
+ }
7576
+ async function generateInteractiveHtml(templateVariables) {
7577
+ const { featureName, businessDomain, pageType, pageStyle, inputContent } = templateVariables;
7578
+ const prompt = `\u{4F60}\u{662F}\u{4E00}\u{4F4D}\u{4E13}\u{4E1A}\u{7684}\u{524D}\u{7AEF}\u{5F00}\u{53D1}\u{4E13}\u{5BB6}\u{3002}\u{8BF7}\u{6839}\u{636E}\u{4EE5}\u{4E0B}\u{9700}\u{6C42}\u{751F}\u{6210}\u{4E00}\u{4E2A}\u{5B8C}\u{6574}\u{7684}\u{3001}\u{53EF}\u{4EA4}\u{4E92}\u{7684}HTML\u{9875}\u{9762}\u{3002}
7579
+
7580
+ ## \u{9700}\u{6C42}\u{4FE1}\u{606F}
7581
+ - \u{529F}\u{80FD}\u{540D}\u{79F0}: ${featureName}
7582
+ - \u{4E1A}\u{52A1}\u{9886}\u{57DF}: ${businessDomain}
7583
+ - \u{9875}\u{9762}\u{7C7B}\u{578B}: ${pageType || 'responsive'}
7584
+ - \u{9700}\u{6C42}\u{8BE6}\u{60C5}:
7585
+ ${inputContent || ''}
7586
+
7587
+ ## \u{9875}\u{9762}\u{98CE}\u{683C}\u{8981}\u{6C42}
7588
+ \u{5728}<head>\u{4E2D}\u{5305}\u{542B}\u{4EE5}\u{4E0B}\u{6837}\u{5F0F}\u{914D}\u{7F6E}\u{FF1A}
7589
+ ${pageStyle}
7590
+
7591
+ ## \u{6280}\u{672F}\u{8981}\u{6C42}
7592
+ 1. \u{751F}\u{6210}\u{5B8C}\u{6574}\u{7684}HTML\u{6587}\u{4EF6}\u{FF0C}\u{5305}\u{542B}<!DOCTYPE html>\u{3001}<html>\u{3001}<head>\u{3001}<body>
7593
+ 2. \u{4F7F}\u{7528}TailwindCSS\u{8FDB}\u{884C}\u{6837}\u{5F0F}\u{8BBE}\u{8BA1}\u{FF0C}\u{4F7F}\u{7528}CSS\u{53D8}\u{91CF}\u{5B9E}\u{73B0}\u{4E3B}\u{9898}\u{8272}
7594
+ 3. \u{9875}\u{9762}\u{5FC5}\u{987B}\u{662F}${'mobile' === pageType ? "\u79FB\u52A8\u7AEF\u4F18\u5148" : 'pc' === pageType ? "PC\u7AEF" : "\u54CD\u5E94\u5F0F"}\u{5E03}\u{5C40}
7595
+ 4. \u{5305}\u{542B}\u{5B8C}\u{6574}\u{7684}\u{8868}\u{5355}\u{9A8C}\u{8BC1}\u{548C}\u{4EA4}\u{4E92}\u{903B}\u{8F91}\u{FF08}\u{4F7F}\u{7528}\u{539F}\u{751F}JavaScript\u{FF09}
7596
+ 5. \u{5305}\u{542B}\u{52A0}\u{8F7D}\u{72B6}\u{6001}\u{3001}\u{6210}\u{529F}/\u{5931}\u{8D25}\u{63D0}\u{793A}
7597
+ 6. \u{8868}\u{5355}\u{63D0}\u{4EA4}\u{4F7F}\u{7528}console.log\u{6A21}\u{62DF}\u{FF0C}\u{5E76}\u{663E}\u{793A}\u{63D0}\u{4EA4}\u{7ED3}\u{679C}
7598
+ 7. \u{6240}\u{6709}\u{6587}\u{672C}\u{4F7F}\u{7528}\u{4E2D}\u{6587}
7599
+ 8. \u{8BBE}\u{8BA1}\u{7F8E}\u{89C2}\u{3001}\u{73B0}\u{4EE3}\u{3001}\u{7B80}\u{6D01}
7600
+
7601
+ ## \u{8F93}\u{51FA}\u{8981}\u{6C42}
7602
+ \u{76F4}\u{63A5}\u{8F93}\u{51FA}\u{5B8C}\u{6574}\u{7684}HTML\u{4EE3}\u{7801}\u{FF0C}\u{4E0D}\u{8981}\u{5305}\u{542B}\u{4EFB}\u{4F55}\u{89E3}\u{91CA}\u{6216}markdown\u{6807}\u{8BB0}\u{3002}`;
7603
+ const html = await openAIService.generateText({
7604
+ prompt,
7605
+ system_prompt: "\u4F60\u662F\u4E00\u4F4D\u8D44\u6DF1\u7684\u524D\u7AEF\u5F00\u53D1\u4E13\u5BB6\uFF0C\u64C5\u957F\u4F7F\u7528TailwindCSS\u521B\u5EFA\u7F8E\u89C2\u3001\u53EF\u4EA4\u4E92\u7684\u9875\u9762\u3002\u53EA\u8F93\u51FAHTML\u4EE3\u7801\uFF0C\u4E0D\u8981\u5305\u542B\u4EFB\u4F55\u5176\u4ED6\u5185\u5BB9\u3002",
7606
+ temperature: 0.7
7607
+ });
7608
+ let cleanHtml = html.trim();
7609
+ if (cleanHtml.startsWith("```html")) cleanHtml = cleanHtml.slice(7);
7610
+ else if (cleanHtml.startsWith("```")) cleanHtml = cleanHtml.slice(3);
7611
+ if (cleanHtml.endsWith("```")) cleanHtml = cleanHtml.slice(0, -3);
7612
+ return cleanHtml.trim();
7613
+ }
7118
7614
  const requirementAnalyzerTool = {
7119
- name: "\u9700\u6C42\u62A5\u544A\u751F\u6210\u667A\u80FD\u4F53",
7120
- description: "\u667A\u80FD\u5206\u6790\u9700\u6C42\u5E76\u751F\u6210\u7EDF\u4E00\u7684\u6280\u672F\u6587\u6863\uFF0C\u652F\u6301\u9879\u76EE\u60C5\u51B5\u611F\u77E5\u548C\u7CBE\u786E\u6A21\u677F\u5339\u914D",
7615
+ name: "requirement-analyzer-report",
7616
+ description: `\u{667A}\u{80FD}\u{5206}\u{6790}\u{9700}\u{6C42}\u{5E76}\u{751F}\u{6210}API\u{6587}\u{6863}\u{548C}HTML\u{9875}\u{9762}\u{8BBE}\u{8BA1}\u{6587}\u{6863}\u{3002}\u{652F}\u{6301}PC\u{7AEF}\u{3001}\u{79FB}\u{52A8}\u{7AEF}\u{7B49}\u{591A}\u{79CD}\u{9875}\u{9762}\u{7C7B}\u{578B}\u{3002}`,
7121
7617
  inputSchema: {
7122
7618
  requirement_analysis: stringType().describe("requirement-identifier\u751F\u6210\u7684\u9700\u6C42\u5206\u6790\u7ED3\u679C\uFF08\u5305\u542B\u5F53\u524D\u9700\u6C42\u4E0E\u9879\u76EE\u60C5\u51B5\u7684\u5B8C\u6574\u5206\u6790\uFF09"),
7123
7619
  current_project_path: stringType().describe("\u5F53\u524D\u9879\u76EE\u8DEF\u5F84\uFF08\u5FC5\u586B\uFF09\uFF0C\u9700\u6C42\u62A5\u544A\u5C06\u751F\u6210\u5230\u8BE5\u8DEF\u5F84\u4E0B\u7684.aico/design\u76EE\u5F55"),
7124
- requirement_type: enumType([
7125
- "PC+API",
7126
- "APP+API",
7127
- "SDK+API",
7128
- "APP+SDK",
7129
- "PC+APP+API"
7130
- ]).default("PC+API").describe("需求类型(必填):\n- PC+API: 页面+接口(会生成PC报告和API报告)\n- APP+API: 移动端+接口(会生成APP报告和API报告)\n- SDK+API: SDK集成+接口\n- APP+SDK: 移动端+SDK集成\n- PC+APP+API: 全平台(会生成PC、APP、API三份报告)\n根据需求内容选择合适的类型,如果需求提到「接口和页面」,应该使用 PC+API")
7620
+ page_style: stringType().optional().describe("HTML\u9875\u9762\u98CE\u683C\u6837\u5F0F\uFF08\u53EF\u9009\uFF09\uFF0C\u9ED8\u8BA4\u4F7F\u7528 TailwindCSS \u7B80\u7EA6\u98CE\u683C\u3002\u53EF\u81EA\u5B9A\u4E49 CSS \u53D8\u91CF\u548C\u6837\u5F0F\u3002"),
7621
+ page_type: enumType([
7622
+ "pc",
7623
+ "mobile",
7624
+ "responsive"
7625
+ ]).default("responsive").describe("页面类型(可选):\n- pc: PC端页面\n- mobile: 移动端页面\n- responsive: 响应式页面(默认,同时支持PC和移动端)")
7131
7626
  },
7132
7627
  handler: async (args)=>{
7133
7628
  try {
7134
- const { requirement_analysis, current_project_path, requirement_type } = args;
7629
+ const { requirement_analysis, current_project_path, page_style, page_type } = args;
7630
+ const finalPageStyle = page_style || DEFAULT_PAGE_STYLE;
7631
+ const finalPageType = page_type || "responsive";
7135
7632
  if (!requirement_analysis || !current_project_path) return {
7136
7633
  content: [
7137
7634
  {
@@ -7149,20 +7646,131 @@ ${generationTasks?.map((task, i)=>`
7149
7646
  const serviceResult = await service.analyzeRequirements({
7150
7647
  requirement_analysis,
7151
7648
  current_project_path,
7152
- requirement_type: requirement_type || "PC+API"
7649
+ page_style: finalPageStyle,
7650
+ page_type: finalPageType
7651
+ });
7652
+ const generationTasks = serviceResult.generationTasks || [];
7653
+ if (0 === generationTasks.length) return {
7654
+ content: [
7655
+ {
7656
+ type: "text",
7657
+ text: JSON.stringify({
7658
+ success: false,
7659
+ message: "\u6CA1\u6709\u751F\u6210\u4EFB\u52A1",
7660
+ data: null
7661
+ })
7662
+ }
7663
+ ],
7664
+ isError: true
7665
+ };
7666
+ logger.info(`\u{5F00}\u{59CB}\u{5B8C}\u{5168}\u{5E76}\u{884C}\u{751F}\u{6210} ${generationTasks.length} \u{4EFD}\u{6587}\u{6863}...`);
7667
+ const startTime = Date.now();
7668
+ const apiTask = generationTasks.find((t)=>"API" === t.requirementType);
7669
+ const htmlTask = generationTasks.find((t)=>"HTML" === t.requirementType);
7670
+ const results = [];
7671
+ const parallelTasks = [];
7672
+ if (apiTask) {
7673
+ const apiPromise = (async ()=>{
7674
+ try {
7675
+ logger.info(`\u{5F00}\u{59CB}\u{5E76}\u{884C}\u{751F}\u{6210}API\u{6587}\u{6863}\u{FF08}${API_SECTIONS.length}\u{4E2A}\u{7AE0}\u{8282}\u{FF09}`);
7676
+ const sectionResults = await Promise.all(API_SECTIONS.map((section)=>generateApiSection(section, apiTask.templateVariables)));
7677
+ const successSections = sectionResults.filter((r)=>r.success);
7678
+ const header = `# ${apiTask.templateVariables.featureName} - API\u{6280}\u{672F}\u{9700}\u{6C42}\u{6587}\u{6863}
7679
+
7680
+ > **\u{751F}\u{6210}\u{65F6}\u{95F4}**: ${new Date().toISOString()}
7681
+ > **\u{4E1A}\u{52A1}\u{9886}\u{57DF}**: ${apiTask.templateVariables.businessDomain}
7682
+
7683
+ ---
7684
+
7685
+ `;
7686
+ const document = header + successSections.map((s)=>s.content).join("\n\n---\n\n");
7687
+ const outputDir = external_path_default().dirname(apiTask.outputPath);
7688
+ await promises_namespaceObject.mkdir(outputDir, {
7689
+ recursive: true
7690
+ });
7691
+ await promises_namespaceObject.writeFile(apiTask.outputPath, document, "utf-8");
7692
+ results.push({
7693
+ type: "API",
7694
+ content: document,
7695
+ outputPath: apiTask.outputPath,
7696
+ success: true
7697
+ });
7698
+ logger.info(`API\u{6587}\u{6863}\u{751F}\u{6210}\u{5B8C}\u{6210}`, {
7699
+ length: document.length
7700
+ });
7701
+ } catch (error) {
7702
+ results.push({
7703
+ type: "API",
7704
+ content: "",
7705
+ outputPath: apiTask.outputPath,
7706
+ success: false,
7707
+ error: error.message
7708
+ });
7709
+ }
7710
+ })();
7711
+ parallelTasks.push(apiPromise);
7712
+ }
7713
+ if (htmlTask) {
7714
+ const htmlPromise = (async ()=>{
7715
+ try {
7716
+ logger.info(`\u{5F00}\u{59CB}\u{751F}\u{6210}\u{53EF}\u{4EA4}\u{4E92}HTML\u{9875}\u{9762}`);
7717
+ const htmlOutputPath = htmlTask.outputPath.replace(/\.md$/, ".html");
7718
+ const htmlContent = await generateInteractiveHtml(htmlTask.templateVariables);
7719
+ const outputDir = external_path_default().dirname(htmlOutputPath);
7720
+ await promises_namespaceObject.mkdir(outputDir, {
7721
+ recursive: true
7722
+ });
7723
+ await promises_namespaceObject.writeFile(htmlOutputPath, htmlContent, "utf-8");
7724
+ results.push({
7725
+ type: "HTML",
7726
+ content: htmlContent,
7727
+ outputPath: htmlOutputPath,
7728
+ success: true
7729
+ });
7730
+ logger.info(`HTML\u{9875}\u{9762}\u{751F}\u{6210}\u{5B8C}\u{6210}`, {
7731
+ length: htmlContent.length
7732
+ });
7733
+ } catch (error) {
7734
+ results.push({
7735
+ type: "HTML",
7736
+ content: "",
7737
+ outputPath: htmlTask.outputPath,
7738
+ success: false,
7739
+ error: error.message
7740
+ });
7741
+ }
7742
+ })();
7743
+ parallelTasks.push(htmlPromise);
7744
+ }
7745
+ await Promise.all(parallelTasks);
7746
+ const totalDuration = Date.now() - startTime;
7747
+ const successCount = results.filter((r)=>r.success).length;
7748
+ const failedCount = results.filter((r)=>!r.success).length;
7749
+ const generatedFiles = results.filter((r)=>r.success).map((r)=>r.outputPath);
7750
+ logger.info(`\u{5E76}\u{884C}\u{751F}\u{6210}\u{5B8C}\u{6210}`, {
7751
+ total: results.length,
7752
+ success: successCount,
7753
+ failed: failedCount,
7754
+ totalDuration: `${totalDuration}ms`
7153
7755
  });
7154
7756
  return {
7155
7757
  content: [
7156
7758
  {
7157
7759
  type: "text",
7158
7760
  text: JSON.stringify({
7159
- success: true,
7160
- message: serviceResult.message || "\u9700\u6C42\u5206\u6790\u4EFB\u52A1\u5DF2\u51C6\u5907",
7761
+ success: successCount > 0,
7762
+ message: `\u{6587}\u{6863}\u{751F}\u{6210}\u{5B8C}\u{6210}\u{FF1A}${successCount} \u{6210}\u{529F}\u{FF0C}${failedCount} \u{5931}\u{8D25}\u{FF0C}\u{603B}\u{8017}\u{65F6} ${totalDuration}ms`,
7161
7763
  data: {
7162
7764
  outputPath: serviceResult.outputPath,
7163
- generatedFiles: serviceResult.generatedFiles || [],
7765
+ generatedFiles,
7164
7766
  analysisInfo: serviceResult.analysisInfo || {},
7165
- generationTasks: serviceResult.generationTasks || []
7767
+ results: results.map((r)=>({
7768
+ type: r.type,
7769
+ outputPath: r.outputPath,
7770
+ success: r.success,
7771
+ error: r.error,
7772
+ contentLength: r.content?.length || 0
7773
+ }))
7166
7774
  }
7167
7775
  })
7168
7776
  }
@@ -7550,202 +8158,6 @@ ${requirementSection}
7550
8158
  }
7551
8159
  const external_sharp_namespaceObject = require("sharp");
7552
8160
  var external_sharp_default = /*#__PURE__*/ __webpack_require__.n(external_sharp_namespaceObject);
7553
- async function invokeFlow(params, streamCb) {
7554
- const { appid = 'app-ESTcrkOPOmkxdrO0120mE4s1', data, timeout = 1800000 } = params;
7555
- const controller = new AbortController();
7556
- const signal = controller.signal;
7557
- if ('undefined' == typeof ReadableStream) throw new Error('ReadableStream is not supported in this environment');
7558
- const fetchData = async (retryCount = 0)=>{
7559
- try {
7560
- const fetchOptions = {
7561
- method: 'POST',
7562
- headers: {
7563
- Authorization: `Bearer ${appid}`,
7564
- 'Content-Type': 'application/json'
7565
- },
7566
- body: JSON.stringify({
7567
- inputs: data,
7568
- response_mode: 'streaming',
7569
- user: "aico-mcp"
7570
- }),
7571
- signal
7572
- };
7573
- const res = await fetch('http://11.0.166.20:9199/v1/workflows/run', fetchOptions);
7574
- if (!res.ok) {
7575
- if (retryCount < 3) {
7576
- await new Promise((resolve)=>setTimeout(resolve, 1000));
7577
- return fetchData(retryCount + 1);
7578
- }
7579
- const errorResponse = await res.text();
7580
- throw new Error(`\u{7F51}\u{7EDC}\u{54CD}\u{5E94}\u{5F02}\u{5E38}: ${res.status} ${res.statusText} - ${errorResponse}`);
7581
- }
7582
- if (res.ok) if (res.body) {
7583
- const reader = res.body.getReader();
7584
- const decoder = new TextDecoder('utf-8');
7585
- if (streamCb) return void new ReadableStream({
7586
- start (controller) {
7587
- let buffer = '';
7588
- function push() {
7589
- reader.read().then(({ done, value })=>{
7590
- if (done) {
7591
- const lines = buffer.split('\n');
7592
- for (const line of lines)handleLine(line, controller);
7593
- if (streamCb) streamCb({
7594
- isEnd: true
7595
- });
7596
- controller.close();
7597
- return;
7598
- }
7599
- const chunkText = decoder.decode(value, {
7600
- stream: true
7601
- });
7602
- buffer += chunkText;
7603
- const lines = buffer.split('\n');
7604
- for(let i = 0; i < lines.length - 1; i++)handleLine(lines[i], controller);
7605
- buffer = lines[lines.length - 1];
7606
- push();
7607
- });
7608
- }
7609
- function handleLine(line, controller) {
7610
- line = line.trim();
7611
- if (line.startsWith('data:')) {
7612
- const dataStr = line.slice(5).trim();
7613
- if ('' === dataStr) return;
7614
- try {
7615
- const jsonData = JSON.parse(dataStr);
7616
- if (jsonData.data?.text) {
7617
- const wrappedData = {
7618
- content: jsonData.data.text.toString(),
7619
- controller
7620
- };
7621
- if (streamCb) streamCb(wrappedData);
7622
- }
7623
- } catch (e) {
7624
- console.error("\u89E3\u6790JSON\u5931\u8D25:", e);
7625
- }
7626
- }
7627
- }
7628
- push();
7629
- }
7630
- });
7631
- {
7632
- let buffer = '';
7633
- let accumulatedText = '';
7634
- let isResponseEnded = false;
7635
- const readAll = async ()=>{
7636
- const { done, value } = await reader.read();
7637
- if (done) {
7638
- if (!isResponseEnded) throw new Error("\u54CD\u5E94\u63D0\u524D\u7ED3\u675F");
7639
- return accumulatedText;
7640
- }
7641
- const chunkText = decoder.decode(value, {
7642
- stream: true
7643
- });
7644
- buffer += chunkText;
7645
- const lines = buffer.split('\n');
7646
- for(let i = 0; i < lines.length - 1; i++){
7647
- const line = lines[i].trim();
7648
- if (!line.startsWith('data:')) continue;
7649
- const dataStr = line.slice(5).trim();
7650
- if ('' !== dataStr) try {
7651
- const jsonData = JSON.parse(dataStr);
7652
- switch(jsonData.event){
7653
- case 'message':
7654
- case 'agent_message':
7655
- case 'text_chunk':
7656
- {
7657
- const content = 'text_chunk' === jsonData.event ? jsonData.data.text : jsonData.answer;
7658
- accumulatedText += content;
7659
- break;
7660
- }
7661
- case 'workflow_finished':
7662
- accumulatedText = jsonData.data;
7663
- isResponseEnded = true;
7664
- break;
7665
- case 'message_end':
7666
- isResponseEnded = true;
7667
- break;
7668
- case 'error':
7669
- throw new Error(`\u{670D}\u{52A1}\u{5668}\u{9519}\u{8BEF}: ${jsonData.code}, ${jsonData.message}`);
7670
- default:
7671
- break;
7672
- }
7673
- } catch (e) {
7674
- throw new Error("\u89E3\u6790JSON\u5931\u8D25: " + e.message);
7675
- }
7676
- }
7677
- buffer = lines[lines.length - 1];
7678
- return readAll();
7679
- };
7680
- return readAll();
7681
- }
7682
- } else throw new Error("\u54CD\u5E94\u4F53\u4E3A\u7A7A");
7683
- {
7684
- const errorResponse = await res.text();
7685
- throw new Error(`\u{7F51}\u{7EDC}\u{54CD}\u{5E94}\u{5F02}\u{5E38}: ${res.status} ${res.statusText} - ${errorResponse}`);
7686
- }
7687
- } catch (error) {
7688
- if ('AbortError' === error.name) throw new Error("\u8BF7\u6C42\u5DF2\u88AB\u4E2D\u6B62\uFF0C\u8D85\u65F6");
7689
- throw error;
7690
- }
7691
- };
7692
- try {
7693
- const result = await Promise.race([
7694
- fetchData(),
7695
- new Promise((_, reject)=>{
7696
- setTimeout(()=>{
7697
- controller.abort();
7698
- reject(new Error("\u8BF7\u6C42\u8D85\u65F6"));
7699
- }, timeout);
7700
- })
7701
- ]);
7702
- if (streamCb) return;
7703
- return result;
7704
- } catch (error) {
7705
- controller.abort();
7706
- throw error;
7707
- }
7708
- }
7709
- async function uploadFile(params) {
7710
- const { appid, filePath, user = 'aico-mcp' } = params;
7711
- try {
7712
- const fileBuffer = await external_fs_default().promises.readFile(filePath);
7713
- const fileName = external_path_default().basename(filePath);
7714
- const fileExtension = external_path_default().extname(filePath).toLowerCase().slice(1);
7715
- const mimeTypes = {
7716
- png: 'image/png',
7717
- jpeg: 'image/jpeg',
7718
- jpg: 'image/jpeg',
7719
- webp: 'image/webp',
7720
- gif: 'image/gif'
7721
- };
7722
- const mimeType = mimeTypes[fileExtension] || 'application/octet-stream';
7723
- const formData = new FormData();
7724
- formData.append('file', new Blob([
7725
- fileBuffer.buffer
7726
- ], {
7727
- type: mimeType
7728
- }), fileName);
7729
- formData.append('user', user);
7730
- const response = await fetch('http://11.0.166.20:9199/v1/files/upload', {
7731
- method: 'POST',
7732
- headers: {
7733
- Authorization: `Bearer ${appid}`
7734
- },
7735
- body: formData
7736
- });
7737
- if (!response.ok) {
7738
- const errorText = await response.text();
7739
- throw new Error(`\u{6587}\u{4EF6}\u{4E0A}\u{4F20}\u{5931}\u{8D25}: ${response.status} ${response.statusText} - ${errorText}`);
7740
- }
7741
- const result = await response.json();
7742
- if (!result.id || !result.name) throw new Error("\u65E0\u6548\u7684\u6587\u4EF6\u4E0A\u4F20\u54CD\u5E94\u683C\u5F0F");
7743
- return result;
7744
- } catch (error) {
7745
- if (error instanceof Error) throw new Error(`\u{6587}\u{4EF6}\u{4E0A}\u{4F20}\u{5931}\u{8D25}: ${error.message}`);
7746
- throw new Error("\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25: \u672A\u77E5\u9519\u8BEF");
7747
- }
7748
- }
7749
8161
  class ImageAnalysisError extends Error {
7750
8162
  code;
7751
8163
  context;
@@ -7782,7 +8194,7 @@ ${requirementSection}
7782
8194
  });
7783
8195
  await this.validateParams(imagePath);
7784
8196
  const basicInfo = await this.getImageBasicInfo(imagePath);
7785
- const analysisContent = await this.performAIAnalysis(imagePath, basicInfo, context);
8197
+ const analysisContent = await this.performAIAnalysis(imagePath, context);
7786
8198
  const processingTime = Date.now() - startTime;
7787
8199
  if (!analysisContent) throw new ImageAnalysisError("AI\u5206\u6790\u8FD4\u56DE\u7A7A\u7ED3\u679C", types_AnalysisErrorCodes.ANALYSIS_FAILED, {
7788
8200
  params: {
@@ -7809,16 +8221,15 @@ ${requirementSection}
7809
8221
  throw error;
7810
8222
  }
7811
8223
  }
7812
- async performAIAnalysis(imagePath, basicInfo, context) {
8224
+ async performAIAnalysis(imagePath, context) {
7813
8225
  try {
7814
- const imageBase64 = await this.imageToBase64(imagePath);
7815
8226
  const systemPrompt = `You must interpret and analyze images strictly according to the assigned task.
7816
8227
  When an image placeholder is provided, your role is to parse the image content only within the scope of the user's instructions.
7817
8228
  Do not ignore or deviate from the task.
7818
8229
  Always ensure that your response reflects a clear, accurate interpretation of the image aligned with the given objective.`;
7819
- const userPrompt = context || "\u8BF7\u5206\u6790\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9";
7820
- const aiResponse = await openAIService.analyzeImage({
7821
- image_base64: imageBase64,
8230
+ const userPrompt = `${context}, You must provide a complete and detailed description of all content in the image, including scenes, objects, text, colors, layout, relationships, and all other visible elements and details. Ensure the description is detailed enough so that subsequent text-based language models can fully understand the image content through text alone.Always respond in Chinese-simplified`;
8231
+ const aiResponse = await openAIService.analyzeImageWithPath({
8232
+ image_path: imagePath,
7822
8233
  prompt: userPrompt,
7823
8234
  system_prompt: systemPrompt
7824
8235
  });
@@ -7828,26 +8239,15 @@ Always ensure that your response reflects a clear, accurate interpretation of th
7828
8239
  tags: []
7829
8240
  };
7830
8241
  } catch (error) {
7831
- logger.warn("\u4E3BAI\u5206\u6790\u5931\u8D25\uFF0C\u5C1D\u8BD5Dify\u515C\u5E95\u5206\u6790", {
8242
+ logger.error("AI\u5206\u6790\u5931\u8D25", {
7832
8243
  error,
7833
8244
  params: {
7834
8245
  image_path: imagePath
7835
8246
  }
7836
8247
  });
7837
- try {
7838
- return await this.fallbackToDifyAnalysis(imagePath, context);
7839
- } catch (fallbackError) {
7840
- logger.error("Dify\u515C\u5E95\u5206\u6790\u4E5F\u5931\u8D25", {
7841
- error: fallbackError,
7842
- params: {
7843
- image_path: imagePath
7844
- }
7845
- });
7846
- throw new ImageAnalysisError("\u8BC6\u522B\u56FE\u7247\u5931\u8D25", types_AnalysisErrorCodes.ANALYSIS_FAILED, {
7847
- originalError: error,
7848
- fallbackError
7849
- });
7850
- }
8248
+ throw new ImageAnalysisError("\u8BC6\u522B\u56FE\u7247\u5931\u8D25", types_AnalysisErrorCodes.ANALYSIS_FAILED, {
8249
+ originalError: error
8250
+ });
7851
8251
  }
7852
8252
  }
7853
8253
  async getImageBasicInfo(imagePath) {
@@ -7856,7 +8256,7 @@ Always ensure that your response reflects a clear, accurate interpretation of th
7856
8256
  const stats = await promises_namespaceObject.stat(imagePath);
7857
8257
  return {
7858
8258
  path: imagePath,
7859
- format: metadata.format || 'unknown',
8259
+ format: metadata.format || "unknown",
7860
8260
  dimensions: {
7861
8261
  width: metadata.width || 0,
7862
8262
  height: metadata.height || 0
@@ -7870,37 +8270,6 @@ Always ensure that your response reflects a clear, accurate interpretation of th
7870
8270
  });
7871
8271
  }
7872
8272
  }
7873
- async imageToBase64(imagePath) {
7874
- try {
7875
- const imageBuffer = await promises_namespaceObject.readFile(imagePath);
7876
- const base64 = imageBuffer.toString('base64');
7877
- const ext = external_path_namespaceObject.extname(imagePath).toLowerCase();
7878
- let mimeType = 'image/jpeg';
7879
- switch(ext){
7880
- case '.png':
7881
- mimeType = 'image/png';
7882
- break;
7883
- case '.gif':
7884
- mimeType = 'image/gif';
7885
- break;
7886
- case '.webp':
7887
- mimeType = 'image/webp';
7888
- break;
7889
- case '.jpg':
7890
- case '.jpeg':
7891
- mimeType = 'image/jpeg';
7892
- break;
7893
- default:
7894
- mimeType = 'image/jpeg';
7895
- }
7896
- return `data:${mimeType};base64,${base64}`;
7897
- } catch (error) {
7898
- throw new ImageAnalysisError(`\u{65E0}\u{6CD5}\u{8BFB}\u{53D6}\u{56FE}\u{7247}\u{6587}\u{4EF6}: ${imagePath}`, types_AnalysisErrorCodes.FILE_NOT_FOUND, {
7899
- imagePath,
7900
- originalError: error
7901
- });
7902
- }
7903
- }
7904
8273
  async validateParams(imagePath) {
7905
8274
  try {
7906
8275
  await promises_namespaceObject.access(imagePath);
@@ -7915,81 +8284,17 @@ Always ensure that your response reflects a clear, accurate interpretation of th
7915
8284
  supportedFormats: SUPPORTED_IMAGE_FORMATS
7916
8285
  });
7917
8286
  }
7918
- formatFileSize(bytes) {
7919
- if (0 === bytes) return '0 B';
7920
- const k = 1024;
7921
- const sizes = [
7922
- 'B',
7923
- 'KB',
7924
- 'MB',
7925
- 'GB'
7926
- ];
7927
- const i = Math.floor(Math.log(bytes) / Math.log(k));
7928
- return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
7929
- }
7930
- async fallbackToDifyAnalysis(imagePath, context) {
7931
- logger.info("\u5F00\u59CBDify\u515C\u5E95\u56FE\u7247\u5206\u6790", {
7932
- imagePath: imagePath,
7933
- context: context
7934
- });
7935
- try {
7936
- const uploadResult = await uploadFile({
7937
- appid: 'app-AvlLh0nfN4l9oz1MSW4sEAQ6',
7938
- filePath: imagePath,
7939
- user: 'aico-mcp'
7940
- });
7941
- logger.info("\u6587\u4EF6\u4E0A\u4F20\u6210\u529F\uFF0C\u6587\u4EF6ID:", uploadResult.id);
7942
- const workflowData = {
7943
- imagePath: {
7944
- type: 'image',
7945
- transfer_method: 'local_file',
7946
- upload_file_id: uploadResult.id
7947
- },
7948
- context: context || "\u8BF7\u5206\u6790\u8FD9\u5F20\u56FE\u7247\u7684\u5185\u5BB9"
7949
- };
7950
- const workflowResponse = await invokeFlow({
7951
- appid: 'app-AvlLh0nfN4l9oz1MSW4sEAQ6',
7952
- data: workflowData
7953
- });
7954
- logger.info("Dify\u5DE5\u4F5C\u6D41\u8C03\u7528\u6210\u529F", {
7955
- response: workflowResponse
7956
- });
7957
- let summary = "\u5206\u6790\u5B8C\u6210";
7958
- if ('string' == typeof workflowResponse) summary = workflowResponse;
7959
- else if (workflowResponse?.data?.text) summary = workflowResponse.data.text;
7960
- else if (workflowResponse?.answer) summary = workflowResponse.answer;
7961
- else if (workflowResponse?.outputs?.text) summary = workflowResponse.outputs.text;
7962
- else if (workflowResponse?.status === 'failed') throw new Error(`Dify\u{5DE5}\u{4F5C}\u{6D41}\u{6267}\u{884C}\u{5931}\u{8D25}: ${workflowResponse.error || "\u672A\u77E5\u9519\u8BEF"}`);
7963
- return {
7964
- summary: summary,
7965
- details: {
7966
- dify_response: workflowResponse,
7967
- fallback_used: true
7968
- },
7969
- tags: [
7970
- 'dify-fallback'
7971
- ]
7972
- };
7973
- } catch (error) {
7974
- logger.error("Dify\u670D\u52A1\u8C03\u7528\u5931\u8D25", {
7975
- error: error instanceof Error ? error.message : String(error),
7976
- imagePath: imagePath,
7977
- context: context
7978
- });
7979
- throw new ImageAnalysisError(`\u{56FE}\u{7247}\u{5206}\u{6790}\u{670D}\u{52A1}\u{8C03}\u{7528}\u{5931}\u{8D25}: ${error instanceof Error ? error.message : String(error)}`, types_AnalysisErrorCodes.AI_SERVICE_ERROR);
7980
- }
7981
- }
7982
8287
  }
7983
8288
  const ImageAnalysisParamsSchema = objectType({
7984
8289
  image_path: stringType().min(1).describe("\u56FE\u7247\u6587\u4EF6\u8DEF\u5F84"),
7985
- context: stringType().optional().describe("\u4E0A\u4E0B\u6587\u5185\u5BB9\uFF0C\u7528\u4E8E\u6307\u5BFC\u56FE\u7247\u5206\u6790\u7684\u65B9\u5411\u548C\u8303\u56F4")
8290
+ context: stringType().min(1).describe("\u4E0A\u4E0B\u6587\u5185\u5BB9\uFF0C\u7528\u4E8E\u6307\u5BFC\u56FE\u7247\u5206\u6790\u7684\u65B9\u5411\u548C\u8303\u56F4")
7986
8291
  });
7987
8292
  const read_imageTool = {
7988
8293
  name: "read_image",
7989
8294
  description: "\u4E13\u4E1A\u56FE\u7247\u5185\u5BB9\u5206\u6790\u5DE5\u5177\uFF0C\u63D0\u4F9B\u7CBE\u786E\u7684\u56FE\u7247\u5185\u5BB9\u8BC6\u522B\u3002\u6839\u636E\u7528\u6237\u8F93\u5165\u7684\u4E0A\u4E0B\u6587\u4FE1\u606F\u548C\u56FE\u7247\u5185\u5BB9\uFF0C\u8FDB\u884C\u4E25\u683C\u57FA\u4E8E\u4EFB\u52A1\u6307\u4EE4\u7684\u5206\u6790\uFF0C\u4E0D\u504F\u79BB\u4EFB\u52A1\u8303\u56F4\uFF0C\u8F93\u51FA\u6E05\u6670\u51C6\u786E\u7684\u5206\u6790\u7ED3\u679C\u3002",
7990
8295
  inputSchema: {
7991
8296
  image_path: stringType().min(1).describe("\u56FE\u7247\u6587\u4EF6\u8DEF\u5F84"),
7992
- context: stringType().optional().describe("\u4E0A\u4E0B\u6587\u5185\u5BB9\uFF0C\u7528\u4E8E\u6307\u5BFC\u56FE\u7247\u5206\u6790\u7684\u65B9\u5411\u548C\u8303\u56F4")
8297
+ context: stringType().min(1).describe("\u4E0A\u4E0B\u6587\u5185\u5BB9\uFF0C\u7528\u4E8E\u6307\u5BFC\u56FE\u7247\u5206\u6790\u7684\u65B9\u5411\u548C\u8303\u56F4")
7993
8298
  },
7994
8299
  handler: async (args)=>{
7995
8300
  const analyzer = new ImageAnalyzer();
@@ -8315,7 +8620,7 @@ ${error?.message || "\u672A\u77E5\u9519\u8BEF"}`;
8315
8620
  output_directory: stringType().optional().describe("\u8F93\u51FA\u76EE\u5F55\uFF0C\u4E0D\u6307\u5B9A\u5219\u5728\u539F\u6587\u4EF6\u76EE\u5F55\u751F\u6210")
8316
8621
  });
8317
8622
  const imageConverterTool = {
8318
- name: "\u56FE\u7247\u683C\u5F0F\u8F6C\u6362\u667A\u80FD\u4F53",
8623
+ name: "image-converter",
8319
8624
  description: "\u4E13\u4E1A\u56FE\u7247\u683C\u5F0F\u8F6C\u6362\u5DE5\u5177\uFF0C\u652F\u6301\u5355\u5F20\u548C\u6279\u91CF\u8F6C\u6362\uFF0C\u5305\u542B\u5C3A\u5BF8\u8C03\u6574\u548C\u8D28\u91CF\u63A7\u5236\u529F\u80FD",
8320
8625
  inputSchema: {
8321
8626
  input_paths: unionType([
@@ -8407,7 +8712,7 @@ ${results.map((r, index)=>`
8407
8712
  - **\u{8F93}\u{51FA}**: \`${r.output_path}\`
8408
8713
  - **\u{683C}\u{5F0F}**: ${r.format?.toUpperCase()}
8409
8714
  - **\u{5C3A}\u{5BF8}**: ${r.dimensions?.width} \xd7 ${r.dimensions?.height}
8410
- - **\u{6587}\u{4EF6}\u{5927}\u{5C0F}**: ${image_converter_formatFileSize(r.file_size || 0)}
8715
+ - **\u{6587}\u{4EF6}\u{5927}\u{5C0F}**: ${formatFileSize(r.file_size || 0)}
8411
8716
  `).join("")}
8412
8717
 
8413
8718
  ${args.width || args.height ? `
@@ -8443,7 +8748,7 @@ ${successResults.map((r, index)=>`
8443
8748
  ${index + 1}. **${getFileName(r.input_path)}**
8444
8749
  - \u{8F93}\u{51FA}: \`${r.output_path}\`
8445
8750
  - \u{5C3A}\u{5BF8}: ${r.dimensions?.width} \xd7 ${r.dimensions?.height}
8446
- - \u{5927}\u{5C0F}: ${image_converter_formatFileSize(r.file_size || 0)}
8751
+ - \u{5927}\u{5C0F}: ${formatFileSize(r.file_size || 0)}
8447
8752
  `).join("")}
8448
8753
 
8449
8754
  ## \u{274C} \u{8F6C}\u{6362}\u{5931}\u{8D25} (${failedResults.length}\u{5F20})
@@ -8510,7 +8815,7 @@ ${getErrorSuggestion(error.code)}
8510
8815
  function getFileName(filePath) {
8511
8816
  return filePath.split("/").pop() || filePath;
8512
8817
  }
8513
- function image_converter_formatFileSize(bytes) {
8818
+ function formatFileSize(bytes) {
8514
8819
  if (0 === bytes) return "0 B";
8515
8820
  const k = 1024;
8516
8821
  const sizes = [
@@ -8581,6 +8886,7 @@ ${getErrorSuggestion(error.code)}
8581
8886
  RETRY_DELAY_MS: 1000
8582
8887
  };
8583
8888
  const ImageRecognitionParamsSchema = objectType({
8889
+ projectPath: stringType().min(1).describe("\u5F53\u524D\u9879\u76EE\u8DEF\u5F84\uFF0C\u8BC6\u522B\u7ED3\u679C\u5C06\u4FDD\u5B58\u5230\u8BE5\u8DEF\u5F84\u4E0B\u7684.aico/image-recognition\u76EE\u5F55"),
8584
8890
  imagePath: stringType().min(1).describe("\u56FE\u7247\u6587\u4EF6\u8DEF\u5F84"),
8585
8891
  context: stringType().optional().describe("\u4E0A\u4E0B\u6587\u5185\u5BB9\uFF0C\u7528\u4E8E\u6307\u5BFC\u56FE\u7247\u5206\u6790\u7684\u65B9\u5411\u548C\u8303\u56F4")
8586
8892
  });
@@ -8988,8 +9294,8 @@ ${getErrorSuggestion(error.code)}
8988
9294
  }
8989
9295
  class analyzer_ImageAnalyzer {
8990
9296
  context;
8991
- async analyzeLongImage(imagePath, imageInfo, segmentConfig, concurrencyConfig, apiPreference = 'auto', context) {
8992
- logger.info("ImageAnalyzer: \u5F00\u59CB\u5206\u6790\u957F\u56FE", {
9297
+ async analyzeLongImageStreaming(imagePath, imageInfo, segmentConfig, concurrencyConfig, apiPreference = 'auto', context, onSegmentComplete) {
9298
+ logger.info("ImageAnalyzer: \u5F00\u59CB\u6D41\u5F0F\u5206\u6790\u957F\u56FE", {
8993
9299
  imagePath,
8994
9300
  totalSegments: segmentConfig.totalSegments,
8995
9301
  maxConcurrency: concurrencyConfig.maxConcurrency,
@@ -8999,24 +9305,36 @@ ${getErrorSuggestion(error.code)}
8999
9305
  const startTime = Date.now();
9000
9306
  const segmentResults = [];
9001
9307
  try {
9002
- if (1 === segmentConfig.totalSegments) {
9003
- const imageBuffer = await external_sharp_default()(imagePath).toBuffer();
9004
- const segmentInfo = {
9005
- index: 0,
9006
- totalSegments: 1,
9007
- position: {
9008
- x: 0,
9009
- y: 0,
9010
- width: imageInfo.width,
9011
- height: imageInfo.height
9012
- },
9013
- isFirstSegment: true,
9014
- isLastSegment: true,
9015
- hasOverlap: false
9016
- };
9017
- const result = await this.analyzeSegment(imageBuffer, segmentInfo, apiPreference);
9018
- segmentResults.push(result);
9019
- } else segmentResults.push(...await this.processSegmentsConcurrently(imagePath, imageInfo, segmentConfig, concurrencyConfig, apiPreference));
9308
+ const segments = await this.generateSegments(imagePath, imageInfo, segmentConfig);
9309
+ for(let i = 0; i < segments.length; i++){
9310
+ const { buffer, info } = segments[i];
9311
+ try {
9312
+ const result = await this.analyzeSegment(buffer, info, apiPreference);
9313
+ segmentResults.push(result);
9314
+ if (onSegmentComplete) await onSegmentComplete(result, {
9315
+ current: i + 1,
9316
+ total: segments.length
9317
+ });
9318
+ } catch (error) {
9319
+ logger.error(`\u{6BB5}\u{843D} ${info.index} \u{5206}\u{6790}\u{5931}\u{8D25}`, {
9320
+ error
9321
+ });
9322
+ const errorResult = {
9323
+ segmentIndex: info.index,
9324
+ textContent: '',
9325
+ imageDescription: '',
9326
+ confidence: 0,
9327
+ processingTimeMs: 0,
9328
+ apiUsed: 'none',
9329
+ error: error instanceof Error ? error.message : "\u672A\u77E5\u9519\u8BEF"
9330
+ };
9331
+ segmentResults.push(errorResult);
9332
+ if (onSegmentComplete) await onSegmentComplete(errorResult, {
9333
+ current: i + 1,
9334
+ total: segments.length
9335
+ });
9336
+ }
9337
+ }
9020
9338
  const summary = this.generateProcessingSummary(segmentResults, startTime);
9021
9339
  const result = {
9022
9340
  imageInfo,
@@ -9025,7 +9343,7 @@ ${getErrorSuggestion(error.code)}
9025
9343
  outputPath: '',
9026
9344
  success: 0 === summary.failedSegments
9027
9345
  };
9028
- logger.info("\u957F\u56FE\u5206\u6790\u5B8C\u6210", {
9346
+ logger.info("\u957F\u56FE\u6D41\u5F0F\u5206\u6790\u5B8C\u6210", {
9029
9347
  imagePath,
9030
9348
  totalSegments: summary.totalSegments,
9031
9349
  successfulSegments: summary.successfulSegments,
@@ -9034,7 +9352,7 @@ ${getErrorSuggestion(error.code)}
9034
9352
  });
9035
9353
  return result;
9036
9354
  } catch (error) {
9037
- logger.error("\u957F\u56FE\u5206\u6790\u5931\u8D25", {
9355
+ logger.error("\u957F\u56FE\u6D41\u5F0F\u5206\u6790\u5931\u8D25", {
9038
9356
  imagePath,
9039
9357
  error
9040
9358
  });
@@ -9044,6 +9362,9 @@ ${getErrorSuggestion(error.code)}
9044
9362
  });
9045
9363
  }
9046
9364
  }
9365
+ async analyzeLongImage(imagePath, imageInfo, segmentConfig, concurrencyConfig, apiPreference = 'auto', context) {
9366
+ return this.analyzeLongImageStreaming(imagePath, imageInfo, segmentConfig, concurrencyConfig, apiPreference, context);
9367
+ }
9047
9368
  async processSegmentsConcurrently(imagePath, imageInfo, segmentConfig, concurrencyConfig, apiPreference) {
9048
9369
  const results = [];
9049
9370
  const { maxConcurrency, batchSize, delayBetweenBatches } = concurrencyConfig;
@@ -9223,7 +9544,7 @@ ${getErrorSuggestion(error.code)}
9223
9544
  let prompt = '';
9224
9545
  prompt = this.context ? `${this.context}
9225
9546
 
9226
- \u{8BF7}\u{6839}\u{636E}\u{4E0A}\u{8FF0}\u{4EFB}\u{52A1}\u{8981}\u{6C42}\u{FF0C}\u{5206}\u{6790}\u{8FD9}\u{5F20}\u{56FE}\u{7247}\u{5E76}\u{63D0}\u{4F9B}\u{76F8}\u{5173}\u{7ED3}\u{679C}\u{3002}\u{53EA}\u{8F93}\u{51FA}\u{4E0E}\u{4EFB}\u{52A1}\u{76F8}\u{5173}\u{7684}\u{5185}\u{5BB9}\u{FF0C}\u{4E0D}\u{8981}\u{6DFB}\u{52A0}\u{989D}\u{5916}\u{7684}\u{89E3}\u{91CA}\u{6216}\u{63CF}\u{8FF0}\u{3002}
9547
+ You must provide a complete and detailed description of all content in the image, including scenes, objects, text, colors, layout, relationships, and all other visible elements and details. Ensure the description is detailed enough so that subsequent text-based language models can fully understand the image content through text alone.
9227
9548
 
9228
9549
  ` : `\u{8BF7}\u{5BF9}\u{8FD9}\u{5F20}\u{56FE}\u{7247}\u{8FDB}\u{884C}\u{9AD8}\u{7CBE}\u{5EA6}OCR\u{6587}\u{5B57}\u{8BC6}\u{522B}\u{FF0C}\u{53EA}\u{8F93}\u{51FA}\u{56FE}\u{7247}\u{4E2D}\u{7684}\u{539F}\u{59CB}\u{6587}\u{5B57}\u{5185}\u{5BB9}\u{3002}
9229
9550
 
@@ -9241,7 +9562,10 @@ ${getErrorSuggestion(error.code)}
9241
9562
  else prompt += `\u{8FD9}\u{662F}\u{56FE}\u{7247}\u{7684}\u{4E2D}\u{95F4}\u{90E8}\u{5206}\u{3002}`;
9242
9563
  if (segmentInfo.hasOverlap) prompt += `\u{6CE8}\u{610F}\u{FF1A}\u{8FD9}\u{4E2A}\u{6BB5}\u{843D}\u{4E0E}\u{4E0A}\u{4E00}\u{6BB5}\u{6709}\u{91CD}\u{53E0}\u{533A}\u{57DF}\u{FF0C}\u{8BF7}\u{907F}\u{514D}\u{91CD}\u{590D}\u{8BC6}\u{522B}\u{76F8}\u{540C}\u{5185}\u{5BB9}\u{3002}`;
9243
9564
  }
9244
- prompt += `
9565
+ if (this.context) prompt += `
9566
+
9567
+ Always respond in Chinese-simplified. \u{8BF7}\u{786E}\u{4FDD}\u{63CF}\u{8FF0}\u{8DB3}\u{591F}\u{8BE6}\u{7EC6}\u{FF0C}\u{4F7F}\u{540E}\u{7EED}\u{7684}\u{7EAF}\u{6587}\u{672C}\u{8BED}\u{8A00}\u{6A21}\u{578B}\u{80FD}\u{591F}\u{5B8C}\u{5168}\u{7406}\u{89E3}\u{56FE}\u{7247}\u{5185}\u{5BB9}\u{3002}`;
9568
+ else prompt += `
9245
9569
 
9246
9570
  \u{8BF7}\u{76F4}\u{63A5}\u{8F93}\u{51FA}\u{8BC6}\u{522B}\u{5230}\u{7684}\u{6587}\u{5B57}\u{5185}\u{5BB9}\u{FF0C}\u{4E0D}\u{8981}\u{6DFB}\u{52A0}\u{4EFB}\u{4F55}\u{683C}\u{5F0F}\u{6807}\u{8BB0}\u{3001}\u{8BF4}\u{660E}\u{6587}\u{5B57}\u{6216}\u{63CF}\u{8FF0}\u{6027}\u{5185}\u{5BB9}\u{3002}
9247
9571
  \u{5982}\u{679C}\u{56FE}\u{7247}\u{4E2D}\u{6CA1}\u{6709}\u{6587}\u{5B57}\u{FF0C}\u{8BF7}\u{8F93}\u{51FA}"\u{65E0}\u{6587}\u{5B57}\u{5185}\u{5BB9}"\u{3002}`;
@@ -9347,11 +9671,13 @@ Always ensure that your response reflects a clear, accurate interpretation of th
9347
9671
  this.configCalculator = new ConfigCalculator();
9348
9672
  this.analyzer = new analyzer_ImageAnalyzer();
9349
9673
  }
9350
- async processImage(imagePath, context) {
9674
+ async processImage(imagePath, projectPath, context, callbacks) {
9351
9675
  const startTime = Date.now();
9352
9676
  logger.info("ImageRecognitionProcessor: \u5F00\u59CB\u5904\u7406\u56FE\u7247", {
9353
9677
  imagePath
9354
9678
  });
9679
+ let outputPath = '';
9680
+ const segmentResults = [];
9355
9681
  try {
9356
9682
  await this.validateImageFile(imagePath);
9357
9683
  const validation = await this.preprocessor.validateImage(imagePath);
@@ -9373,55 +9699,51 @@ Always ensure that your response reflects a clear, accurate interpretation of th
9373
9699
  segmentHeight: segmentConfig.segmentHeight,
9374
9700
  maxConcurrency: concurrencyConfig.maxConcurrency
9375
9701
  });
9376
- const analysisResult = await this.analyzer.analyzeLongImage(imagePath, imageInfo, segmentConfig, concurrencyConfig, 'auto', context);
9377
- const outputPath = await this.generateSingleOutputFile(imageInfo, analysisResult.segmentResults, analysisResult.summary);
9378
- const totalTime = Date.now() - startTime;
9379
- logger.info("\u56FE\u7247\u5904\u7406\u5B8C\u6210", {
9702
+ outputPath = await this.initializeOutputFile(imageInfo, segmentConfig.totalSegments, projectPath);
9703
+ callbacks?.onStart?.({
9380
9704
  outputPath,
9705
+ totalSegments: segmentConfig.totalSegments,
9706
+ imageInfo
9707
+ });
9708
+ const analysisResult = await this.analyzer.analyzeLongImageStreaming(imagePath, imageInfo, segmentConfig, concurrencyConfig, 'auto', context, async (result, progress)=>{
9709
+ segmentResults.push(result);
9710
+ await this.appendSegmentToFile(outputPath, result);
9711
+ callbacks?.onSegmentComplete?.(result, progress);
9712
+ });
9713
+ await this.finalizeOutputFile(outputPath, analysisResult.summary);
9714
+ const totalTime = Date.now() - startTime;
9715
+ const summary = {
9381
9716
  totalSegments: analysisResult.summary.totalSegments,
9382
9717
  successfulSegments: analysisResult.summary.successfulSegments,
9718
+ failedSegments: analysisResult.summary.failedSegments,
9719
+ successRate: analysisResult.summary.successRate,
9720
+ totalTextCharacters: analysisResult.summary.totalTextCharacters,
9721
+ totalProcessingTimeMs: totalTime,
9722
+ averageConfidence: analysisResult.summary.averageConfidence
9723
+ };
9724
+ callbacks?.onComplete?.(analysisResult.summary);
9725
+ logger.info("\u56FE\u7247\u5904\u7406\u5B8C\u6210", {
9726
+ outputPath,
9727
+ totalSegments: summary.totalSegments,
9728
+ successfulSegments: summary.successfulSegments,
9383
9729
  totalTimeMs: totalTime
9384
9730
  });
9385
9731
  return {
9386
9732
  outputPath,
9387
- summary: {
9388
- totalSegments: analysisResult.summary.totalSegments,
9389
- successfulSegments: analysisResult.summary.successfulSegments,
9390
- failedSegments: analysisResult.summary.failedSegments,
9391
- successRate: analysisResult.summary.successRate,
9392
- totalTextCharacters: analysisResult.summary.totalTextCharacters,
9393
- totalProcessingTimeMs: totalTime,
9394
- averageConfidence: analysisResult.summary.averageConfidence
9395
- }
9733
+ summary
9396
9734
  };
9397
9735
  } catch (error) {
9398
9736
  logger.error("\u56FE\u7247\u5904\u7406\u5931\u8D25", {
9399
9737
  imagePath,
9400
9738
  error
9401
9739
  });
9740
+ callbacks?.onError?.(error instanceof Error ? error : new Error(String(error)));
9402
9741
  throw error;
9403
9742
  }
9404
9743
  }
9405
- async validateImageFile(imagePath) {
9406
- try {
9407
- const stats = await external_fs_namespaceObject.promises.stat(imagePath);
9408
- if (!stats.isFile()) throw new ImageRecognitionError("\u63D0\u4F9B\u7684\u8DEF\u5F84\u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684\u6587\u4EF6", types_ErrorTypes.FILE_NOT_FOUND, {
9409
- imagePath
9410
- });
9411
- } catch (error) {
9412
- if ('ENOENT' === error.code) throw new ImageRecognitionError("\u56FE\u7247\u6587\u4EF6\u4E0D\u5B58\u5728", types_ErrorTypes.FILE_NOT_FOUND, {
9413
- imagePath
9414
- });
9415
- throw new ImageRecognitionError(`\u{6587}\u{4EF6}\u{8BBF}\u{95EE}\u{9519}\u{8BEF}: ${error.message}`, types_ErrorTypes.VALIDATION_ERROR, {
9416
- imagePath,
9417
- originalError: error
9418
- });
9419
- }
9420
- }
9421
- async generateSingleOutputFile(imageInfo, segmentResults, summary) {
9422
- const baseDir = getStorageDir();
9744
+ async initializeOutputFile(imageInfo, totalSegments, projectPath) {
9423
9745
  const dateDir = new Date().toISOString().split('T')[0];
9424
- const outputDirectory = external_path_namespaceObject.join(baseDir, 'image-recognition', dateDir);
9746
+ const outputDirectory = external_path_namespaceObject.join(projectPath, '.aico', 'image-recognition', dateDir);
9425
9747
  await external_fs_namespaceObject.promises.mkdir(outputDirectory, {
9426
9748
  recursive: true
9427
9749
  });
@@ -9429,39 +9751,78 @@ Always ensure that your response reflects a clear, accurate interpretation of th
9429
9751
  const imageBaseName = external_path_namespaceObject.basename(imageInfo.fileName, external_path_namespaceObject.extname(imageInfo.fileName));
9430
9752
  const fileName = `${imageBaseName}-${timestamp}.md`;
9431
9753
  const outputPath = external_path_namespaceObject.join(outputDirectory, fileName);
9432
- const allTextContent = segmentResults.filter((result)=>result.textContent && result.textContent.trim()).map((result)=>result.textContent.trim()).join('\n\n');
9433
- const content = `# ${imageInfo.fileName} - \u{56FE}\u{7247}\u{6587}\u{5B57}\u{8BC6}\u{522B}\u{7ED3}\u{679C}
9754
+ const header = `# ${imageInfo.fileName} - \u{56FE}\u{7247}\u{6587}\u{5B57}\u{8BC6}\u{522B}\u{7ED3}\u{679C}
9434
9755
 
9435
9756
  **\u{8BC6}\u{522B}\u{65F6}\u{95F4}**: ${new Date().toLocaleString('zh-CN')}
9436
9757
  **\u{56FE}\u{7247}\u{5C3A}\u{5BF8}**: ${imageInfo.width} \xd7 ${imageInfo.height} \u{50CF}\u{7D20}
9437
- **\u{5904}\u{7406}\u{6BB5}\u{6570}**: ${summary.totalSegments}
9438
- **\u{6210}\u{529F}\u{6BB5}\u{6570}**: ${summary.successfulSegments}
9439
- **\u{6587}\u{5B57}\u{5B57}\u{7B26}\u{603B}\u{6570}**: ${summary.totalTextCharacters.toLocaleString()}
9440
- **\u{5E73}\u{5747}\u{7F6E}\u{4FE1}\u{5EA6}**: ${(100 * summary.averageConfidence).toFixed(1)}%
9758
+ **\u{9884}\u{8BA1}\u{6BB5}\u{6570}**: ${totalSegments}
9759
+ **\u{72B6}\u{6001}**: \u{1F504} \u{8BC6}\u{522B}\u{4E2D}...
9441
9760
 
9442
9761
  ---
9443
9762
 
9444
9763
  ## \u{8BC6}\u{522B}\u{7684}\u{6587}\u{5B57}\u{5185}\u{5BB9}
9445
9764
 
9446
- ${allTextContent || "\u672A\u8BC6\u522B\u5230\u6587\u5B57\u5185\u5BB9"}
9447
-
9448
- ---
9449
-
9450
- **\u{8BC6}\u{522B}\u{5B8C}\u{6210}\u{65F6}\u{95F4}**: ${new Date().toLocaleString('zh-CN')}
9451
9765
  `;
9452
- await external_fs_namespaceObject.promises.writeFile(outputPath, content, 'utf8');
9453
- logger.info("\u8F93\u51FA\u6587\u4EF6\u751F\u6210\u5B8C\u6210", {
9766
+ await external_fs_namespaceObject.promises.writeFile(outputPath, header, 'utf8');
9767
+ logger.info("\u8F93\u51FA\u6587\u4EF6\u521D\u59CB\u5316\u5B8C\u6210", {
9454
9768
  outputPath,
9455
- fileName,
9456
- contentLength: content.length
9769
+ totalSegments
9457
9770
  });
9458
9771
  return outputPath;
9459
9772
  }
9773
+ async appendSegmentToFile(outputPath, result) {
9774
+ let content = '';
9775
+ if (result.error) content = `<!-- \u{6BB5}\u{843D} ${result.segmentIndex + 1} \u{5904}\u{7406}\u{5931}\u{8D25}: ${result.error} -->\n\n`;
9776
+ else if (result.textContent && result.textContent.trim()) content = `${result.textContent.trim()}\n\n`;
9777
+ if (content) await external_fs_namespaceObject.promises.appendFile(outputPath, content, 'utf8');
9778
+ }
9779
+ async finalizeOutputFile(outputPath, summary) {
9780
+ const footer = `
9781
+ ---
9782
+
9783
+ ## \u{5904}\u{7406}\u{6458}\u{8981}
9784
+
9785
+ - **\u{603B}\u{6BB5}\u{6570}**: ${summary.totalSegments}
9786
+ - **\u{6210}\u{529F}\u{6BB5}\u{6570}**: ${summary.successfulSegments}
9787
+ - **\u{5931}\u{8D25}\u{6BB5}\u{6570}**: ${summary.failedSegments}
9788
+ - **\u{6210}\u{529F}\u{7387}**: ${(100 * summary.successRate).toFixed(1)}%
9789
+ - **\u{6587}\u{5B57}\u{5B57}\u{7B26}\u{603B}\u{6570}**: ${summary.totalTextCharacters.toLocaleString()}
9790
+ - **\u{5E73}\u{5747}\u{7F6E}\u{4FE1}\u{5EA6}**: ${(100 * summary.averageConfidence).toFixed(1)}%
9791
+ - **\u{5904}\u{7406}\u{8017}\u{65F6}**: ${(summary.totalProcessingTimeMs / 1000).toFixed(2)}\u{79D2}
9792
+
9793
+ **\u{72B6}\u{6001}**: \u{2705} \u{8BC6}\u{522B}\u{5B8C}\u{6210}
9794
+ **\u{5B8C}\u{6210}\u{65F6}\u{95F4}**: ${new Date().toLocaleString('zh-CN')}
9795
+ `;
9796
+ await external_fs_namespaceObject.promises.appendFile(outputPath, footer, 'utf8');
9797
+ const content = await external_fs_namespaceObject.promises.readFile(outputPath, 'utf8');
9798
+ const updatedContent = content.replace("**\u72B6\u6001**: \uD83D\uDD04 \u8BC6\u522B\u4E2D...", "**\u72B6\u6001**: \u2705 \u8BC6\u522B\u5B8C\u6210");
9799
+ await external_fs_namespaceObject.promises.writeFile(outputPath, updatedContent, 'utf8');
9800
+ logger.info("\u8F93\u51FA\u6587\u4EF6\u5B8C\u6210", {
9801
+ outputPath
9802
+ });
9803
+ }
9804
+ async validateImageFile(imagePath) {
9805
+ try {
9806
+ const stats = await external_fs_namespaceObject.promises.stat(imagePath);
9807
+ if (!stats.isFile()) throw new ImageRecognitionError("\u63D0\u4F9B\u7684\u8DEF\u5F84\u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684\u6587\u4EF6", types_ErrorTypes.FILE_NOT_FOUND, {
9808
+ imagePath
9809
+ });
9810
+ } catch (error) {
9811
+ if ('ENOENT' === error.code) throw new ImageRecognitionError("\u56FE\u7247\u6587\u4EF6\u4E0D\u5B58\u5728", types_ErrorTypes.FILE_NOT_FOUND, {
9812
+ imagePath
9813
+ });
9814
+ throw new ImageRecognitionError(`\u{6587}\u{4EF6}\u{8BBF}\u{95EE}\u{9519}\u{8BEF}: ${error.message}`, types_ErrorTypes.VALIDATION_ERROR, {
9815
+ imagePath,
9816
+ originalError: error
9817
+ });
9818
+ }
9819
+ }
9460
9820
  }
9461
9821
  const imageRecognitionAgentTool = {
9462
9822
  name: "analyzeLongImage",
9463
- description: "\u4E13\u95E8\u5904\u7406\u957F\u56FE\u7684\u5185\u5BB9\u8BC6\u522B\u667A\u80FD\u4F53\uFF0C\u652F\u6301\u5206\u6BB5\u5904\u7406\u548C\u7EFC\u5408\u5185\u5BB9\u8BC6\u522B\uFF08\u6587\u5B57+\u56FE\u50CF\u63CF\u8FF0\uFF09\uFF0C\u4EE5\u4E2D\u6587Markdown\u683C\u5F0F\u8F93\u51FA\u3002\u53EA\u9700\u63D0\u4F9B\u56FE\u7247\u8DEF\u5F84\u5373\u53EF\uFF0C\u5176\u4ED6\u53C2\u6570\u81EA\u52A8\u4F18\u5316\u3002",
9823
+ description: "\u4E13\u95E8\u5904\u7406\u957F\u56FE\u7684\u5185\u5BB9\u8BC6\u522B\u667A\u80FD\u4F53\uFF0C\u652F\u6301\u5206\u6BB5\u5904\u7406\u548C\u6D41\u5F0F\u8F93\u51FA\u3002\u8BC6\u522B\u7ED3\u679C\u5B9E\u65F6\u5199\u5165Markdown\u6587\u4EF6\uFF0C\u53EF\u8FB9\u5904\u7406\u8FB9\u67E5\u770B\u3002\u8FD4\u56DE\u7ED3\u679C\u5305\u542B\u6587\u4EF6\u8DEF\u5F84\u548C\u5B8C\u6574\u8BC6\u522B\u5185\u5BB9\u3002",
9464
9824
  inputSchema: {
9825
+ projectPath: stringType().min(1).describe("\u5F53\u524D\u9879\u76EE\u8DEF\u5F84\uFF0C\u8BC6\u522B\u7ED3\u679C\u5C06\u4FDD\u5B58\u5230\u8BE5\u8DEF\u5F84\u4E0B\u7684.aico/image-recognition\u76EE\u5F55"),
9465
9826
  imagePath: stringType().min(1).describe("\u56FE\u7247\u6587\u4EF6\u8DEF\u5F84"),
9466
9827
  context: stringType().optional().describe("\u4E0A\u4E0B\u6587\u5185\u5BB9\uFF0C\u7528\u4E8E\u6307\u5BFC\u56FE\u7247\u5206\u6790\u7684\u65B9\u5411\u548C\u8303\u56F4")
9467
9828
  },
@@ -9471,13 +9832,21 @@ ${allTextContent || "\u672A\u8BC6\u522B\u5230\u6587\u5B57\u5185\u5BB9"}
9471
9832
  args
9472
9833
  });
9473
9834
  try {
9474
- const { imagePath, context } = ImageRecognitionParamsSchema.parse(args);
9835
+ const { projectPath, imagePath, context } = ImageRecognitionParamsSchema.parse(args);
9475
9836
  const processor = new ImageRecognitionProcessor();
9476
- const result = await processor.processImage(imagePath, context);
9837
+ const result = await processor.processImage(imagePath, projectPath, context);
9477
9838
  logger.info("\u56FE\u7247\u5185\u5BB9\u8BC6\u522B\u667A\u80FD\u4F53: \u5904\u7406\u5B8C\u6210", {
9478
9839
  outputPath: result.outputPath,
9479
9840
  summary: result.summary
9480
9841
  });
9842
+ let fileContent = '';
9843
+ try {
9844
+ fileContent = await external_fs_namespaceObject.promises.readFile(result.outputPath, 'utf8');
9845
+ } catch (readError) {
9846
+ logger.warn("\u8BFB\u53D6\u7ED3\u679C\u6587\u4EF6\u5931\u8D25", {
9847
+ error: readError
9848
+ });
9849
+ }
9481
9850
  return {
9482
9851
  content: [
9483
9852
  {
@@ -9492,10 +9861,14 @@ ${allTextContent || "\u672A\u8BC6\u522B\u5230\u6587\u5B57\u5185\u5BB9"}
9492
9861
  - \u{5E73}\u{5747}\u{7F6E}\u{4FE1}\u{5EA6}: ${(100 * result.summary.averageConfidence).toFixed(1)}%
9493
9862
  - \u{5904}\u{7406}\u{8017}\u{65F6}: ${(result.summary.totalProcessingTimeMs / 1000).toFixed(2)}\u{79D2}
9494
9863
 
9495
- \u{1F4C4} **\u{7ED3}\u{679C}\u{6587}\u{4EF6}**:
9864
+ \u{1F4C4} **\u{7ED3}\u{679C}\u{6587}\u{4EF6}\u{8DEF}\u{5F84}**:
9496
9865
  \`${result.outputPath}\`
9497
9866
 
9498
- \u{60A8}\u{53EF}\u{4EE5}\u{6253}\u{5F00}\u{4E0A}\u{8FF0}\u{6587}\u{4EF6}\u{67E5}\u{770B}\u{8BE6}\u{7EC6}\u{7684}\u{8BC6}\u{522B}\u{7ED3}\u{679C}\u{3002}`
9867
+ ---
9868
+
9869
+ ## \u{8BC6}\u{522B}\u{7684}\u{5B8C}\u{6574}\u{5185}\u{5BB9}
9870
+
9871
+ ${fileContent}`
9499
9872
  }
9500
9873
  ]
9501
9874
  };