intention-coding 0.6.9 → 0.7.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.
package/dist/index.cjs CHANGED
@@ -1084,6 +1084,11 @@ var __webpack_modules__ = {
1084
1084
  return module;
1085
1085
  });
1086
1086
  },
1087
+ https: function(module) {
1088
+ module.exports = import("https").then(function(module) {
1089
+ return module;
1090
+ });
1091
+ },
1087
1092
  "path?5fdd": function(module) {
1088
1093
  module.exports = import("path").then(function(module) {
1089
1094
  return module;
@@ -1093,6 +1098,11 @@ var __webpack_modules__ = {
1093
1098
  module.exports = import("pdf-parse/lib/pdf-parse.js").then(function(module) {
1094
1099
  return module;
1095
1100
  });
1101
+ },
1102
+ undici: function(module) {
1103
+ module.exports = import("undici").then(function(module) {
1104
+ return module;
1105
+ });
1096
1106
  }
1097
1107
  };
1098
1108
  var __webpack_module_cache__ = {};
@@ -6116,7 +6126,8 @@ ${logic}` : ""}`;
6116
6126
  kimiConfig = {
6117
6127
  apiKey: "sk-fp8wJSigZBEP3x8y6MAZWGPuVIHJ5PDZtX9lMQQk8hjP2R0u",
6118
6128
  baseUrl: "https://api.moonshot.cn/v1/chat/completions",
6119
- model: "kimi-k2-0905-preview"
6129
+ model: "kimi-k2-0905-preview",
6130
+ visionModel: "moonshot-v1-128k-vision-preview"
6120
6131
  };
6121
6132
  glm4vConfig = {
6122
6133
  apiKey: "fb26a7ff758c3974e43bfff49a684dd3.apcuRq6v6RvwuJDu",
@@ -6132,6 +6143,12 @@ ${logic}` : ""}`;
6132
6143
  apiKey: "app-AvlLh0nfN4l9oz1MSW4sEAQ6",
6133
6144
  baseUrl: "http://11.0.166.20:9199/v1"
6134
6145
  };
6146
+ internalConfig = {
6147
+ apiKey: "sk-3W5NXAzeXX9mNP5yppQwPt6cnEoSK03u5NgiNW1Hsi41Tniu",
6148
+ baseUrl: "https://aiproxy.jla.petrotech.cnpc/v1/chat/completions",
6149
+ visionModel: "qwen2-7b-vl",
6150
+ ocrModel: "deepseek-ocr"
6151
+ };
6135
6152
  constructor(){}
6136
6153
  async generateText(params) {
6137
6154
  const { prompt, temperature, system_prompt } = params;
@@ -6517,7 +6534,7 @@ ${logic}` : ""}`;
6517
6534
  }
6518
6535
  const image_base64 = `data:${mimeType};base64,${base64}`;
6519
6536
  try {
6520
- logger.k.info("[OpenAI] \u5C1D\u8BD5\u4F7F\u7528 Kimi \u8FDB\u884C\u56FE\u50CF\u8BC6\u522B");
6537
+ logger.k.info("[OpenAI] \u5C1D\u8BD5\u4F7F\u7528 Kimi Vision \u8FDB\u884C\u56FE\u50CF\u8BC6\u522B");
6521
6538
  const controller = new AbortController();
6522
6539
  const timeoutId = setTimeout(()=>controller.abort(), 30000);
6523
6540
  const response = await fetch(this.kimiConfig.baseUrl, {
@@ -6527,17 +6544,12 @@ ${logic}` : ""}`;
6527
6544
  Authorization: `Bearer ${this.kimiConfig.apiKey}`
6528
6545
  },
6529
6546
  body: JSON.stringify({
6530
- model: this.kimiConfig.model,
6547
+ model: this.kimiConfig.visionModel,
6531
6548
  messages: [
6532
6549
  ...system_prompt ? [
6533
6550
  {
6534
6551
  role: "system",
6535
- content: [
6536
- {
6537
- type: "text",
6538
- text: system_prompt
6539
- }
6540
- ]
6552
+ content: system_prompt
6541
6553
  }
6542
6554
  ] : [],
6543
6555
  {
@@ -6558,7 +6570,10 @@ ${logic}` : ""}`;
6558
6570
  ],
6559
6571
  stream: false,
6560
6572
  temperature,
6561
- max_tokens
6573
+ max_tokens,
6574
+ stop: [
6575
+ "<<<END>>>"
6576
+ ]
6562
6577
  }),
6563
6578
  signal: controller.signal
6564
6579
  });
@@ -6569,103 +6584,103 @@ ${logic}` : ""}`;
6569
6584
  }
6570
6585
  const data = await response.json();
6571
6586
  if (!data.choices || 0 === data.choices.length) throw new Error("No choices returned from Kimi Vision API");
6572
- logger.k.info("[OpenAI] Kimi \u56FE\u50CF\u8BC6\u522B\u6210\u529F");
6587
+ logger.k.info("[OpenAI] Kimi Vision \u56FE\u50CF\u8BC6\u522B\u6210\u529F");
6573
6588
  return data.choices[0].message.content;
6574
6589
  } catch (kimiError) {
6575
- logger.k.error("[OpenAI] Kimi \u8C03\u7528\u5931\u8D25\uFF0C\u56DE\u9000\u5230 Dify", {
6590
+ logger.k.error("[OpenAI] Kimi Vision \u8C03\u7528\u5931\u8D25\uFF0C\u56DE\u9000\u5230 GLM-4V", {
6576
6591
  error: kimiError instanceof Error ? kimiError.message : String(kimiError)
6577
6592
  });
6578
6593
  try {
6579
- logger.k.info("[OpenAI] \u5C1D\u8BD5\u4F7F\u7528 Dify \u5DE5\u4F5C\u6D41");
6580
- const uploadResult = await uploadFile({
6581
- appid: this.difyConfig.apiKey,
6582
- filePath: image_path,
6583
- user: "aico-mcp"
6584
- });
6585
- logger.k.info("[OpenAI] \u6587\u4EF6\u4E0A\u4F20\u6210\u529F", {
6586
- upload_file_id: uploadResult.id
6587
- });
6588
- const workflowData = {
6589
- imagePath: {
6590
- type: "image",
6591
- transfer_method: "local_file",
6592
- upload_file_id: uploadResult.id
6594
+ logger.k.info("[OpenAI] \u5C1D\u8BD5\u4F7F\u7528 GLM-4V \u8FDB\u884C\u56FE\u50CF\u8BC6\u522B");
6595
+ const controller = new AbortController();
6596
+ const timeoutId = setTimeout(()=>controller.abort(), 30000);
6597
+ const response = await fetch(this.glm4vConfig.baseUrl, {
6598
+ method: "POST",
6599
+ headers: {
6600
+ "Content-Type": "application/json",
6601
+ Authorization: `Bearer ${this.glm4vConfig.apiKey}`
6593
6602
  },
6594
- context: prompt
6595
- };
6596
- const workflowResponse = await invokeFlow({
6597
- appid: this.difyConfig.apiKey,
6598
- data: workflowData,
6599
- timeout: 120000
6600
- });
6601
- let summary = "";
6602
- if ("string" == typeof workflowResponse && workflowResponse.length > 0) summary = workflowResponse;
6603
- else if (workflowResponse?.outputs?.text) summary = workflowResponse.outputs.text;
6604
- else if (workflowResponse?.data?.outputs?.text) summary = workflowResponse.data.outputs.text;
6605
- else if (workflowResponse?.data?.text) summary = workflowResponse.data.text;
6606
- else if (workflowResponse?.answer) summary = workflowResponse.answer;
6607
- 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"}`);
6608
- if (!summary || 0 === summary.length) throw new Error("Dify\u5DE5\u4F5C\u6D41\u54CD\u5E94\u4E2D\u672A\u627E\u5230\u6709\u6548\u6587\u672C\u5185\u5BB9");
6609
- logger.k.info("[OpenAI] Dify \u5206\u6790\u5B8C\u6210", {
6610
- summary_length: summary.length
6603
+ body: JSON.stringify({
6604
+ model: this.glm4vConfig.model,
6605
+ messages: [
6606
+ ...system_prompt ? [
6607
+ {
6608
+ role: "system",
6609
+ content: system_prompt
6610
+ }
6611
+ ] : [],
6612
+ {
6613
+ role: "user",
6614
+ content: [
6615
+ {
6616
+ type: "image_url",
6617
+ image_url: {
6618
+ url: image_base64
6619
+ }
6620
+ },
6621
+ {
6622
+ type: "text",
6623
+ text: prompt
6624
+ }
6625
+ ]
6626
+ }
6627
+ ],
6628
+ stream: false,
6629
+ temperature,
6630
+ max_tokens
6631
+ }),
6632
+ signal: controller.signal
6611
6633
  });
6612
- return summary;
6613
- } catch (difyError) {
6614
- logger.k.error("[OpenAI] Dify \u8C03\u7528\u5931\u8D25\uFF0C\u56DE\u9000\u5230 GLM-4V", {
6615
- error: difyError instanceof Error ? difyError.message : String(difyError)
6634
+ clearTimeout(timeoutId);
6635
+ if (!response.ok) {
6636
+ const errorText = await response.text();
6637
+ throw new Error(`GLM-4V API error: ${response.status} ${response.statusText} - ${errorText}`);
6638
+ }
6639
+ const data = await response.json();
6640
+ if (!data.choices || 0 === data.choices.length) throw new Error("No choices returned from GLM-4V API");
6641
+ logger.k.info("[OpenAI] GLM-4V \u56FE\u50CF\u8BC6\u522B\u6210\u529F");
6642
+ return data.choices[0].message.content;
6643
+ } catch (glmError) {
6644
+ logger.k.error("[OpenAI] GLM-4V \u8C03\u7528\u5931\u8D25\uFF0C\u56DE\u9000\u5230 Dify", {
6645
+ error: glmError instanceof Error ? glmError.message : String(glmError)
6616
6646
  });
6617
6647
  try {
6618
- logger.k.info("[OpenAI] \u5C1D\u8BD5\u4F7F\u7528 GLM-4V");
6619
- const controller = new AbortController();
6620
- const timeoutId = setTimeout(()=>controller.abort(), 30000);
6621
- const response = await fetch(this.glm4vConfig.baseUrl, {
6622
- method: "POST",
6623
- headers: {
6624
- "Content-Type": "application/json",
6625
- Authorization: `Bearer ${this.glm4vConfig.apiKey}`
6648
+ logger.k.info("[OpenAI] \u5C1D\u8BD5\u4F7F\u7528 Dify \u5DE5\u4F5C\u6D41");
6649
+ const uploadResult = await uploadFile({
6650
+ appid: this.difyConfig.apiKey,
6651
+ filePath: image_path,
6652
+ user: "aico-mcp"
6653
+ });
6654
+ logger.k.info("[OpenAI] \u6587\u4EF6\u4E0A\u4F20\u6210\u529F", {
6655
+ upload_file_id: uploadResult.id
6656
+ });
6657
+ const workflowData = {
6658
+ imagePath: {
6659
+ type: "image",
6660
+ transfer_method: "local_file",
6661
+ upload_file_id: uploadResult.id
6626
6662
  },
6627
- body: JSON.stringify({
6628
- model: this.glm4vConfig.model,
6629
- messages: [
6630
- ...system_prompt ? [
6631
- {
6632
- role: "system",
6633
- content: system_prompt
6634
- }
6635
- ] : [],
6636
- {
6637
- role: "user",
6638
- content: [
6639
- {
6640
- type: "image_url",
6641
- image_url: {
6642
- url: image_base64
6643
- }
6644
- },
6645
- {
6646
- type: "text",
6647
- text: prompt
6648
- }
6649
- ]
6650
- }
6651
- ],
6652
- stream: false,
6653
- temperature,
6654
- max_tokens
6655
- }),
6656
- signal: controller.signal
6663
+ context: prompt
6664
+ };
6665
+ const workflowResponse = await invokeFlow({
6666
+ appid: this.difyConfig.apiKey,
6667
+ data: workflowData,
6668
+ timeout: 120000
6657
6669
  });
6658
- clearTimeout(timeoutId);
6659
- if (!response.ok) {
6660
- const errorText = await response.text();
6661
- throw new Error(`GLM-4V API error: ${response.status} ${response.statusText} - ${errorText}`);
6662
- }
6663
- const data = await response.json();
6664
- if (!data.choices || 0 === data.choices.length) throw new Error("No choices returned from GLM-4V API");
6665
- logger.k.info("[OpenAI] GLM-4V \u56FE\u50CF\u8BC6\u522B\u6210\u529F");
6666
- return data.choices[0].message.content;
6667
- } catch (glmError) {
6668
- throw new Error(`All vision services failed. Kimi: ${kimiError instanceof Error ? kimiError.message : String(kimiError)}, Dify: ${difyError instanceof Error ? difyError.message : String(difyError)}, GLM-4V: ${glmError instanceof Error ? glmError.message : String(glmError)}`);
6670
+ let summary = "";
6671
+ if ("string" == typeof workflowResponse && workflowResponse.length > 0) summary = workflowResponse;
6672
+ else if (workflowResponse?.outputs?.text) summary = workflowResponse.outputs.text;
6673
+ else if (workflowResponse?.data?.outputs?.text) summary = workflowResponse.data.outputs.text;
6674
+ else if (workflowResponse?.data?.text) summary = workflowResponse.data.text;
6675
+ else if (workflowResponse?.answer) summary = workflowResponse.answer;
6676
+ 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"}`);
6677
+ if (!summary || 0 === summary.length) throw new Error("Dify\u5DE5\u4F5C\u6D41\u54CD\u5E94\u4E2D\u672A\u627E\u5230\u6709\u6548\u6587\u672C\u5185\u5BB9");
6678
+ logger.k.info("[OpenAI] Dify \u5206\u6790\u5B8C\u6210", {
6679
+ summary_length: summary.length
6680
+ });
6681
+ return summary;
6682
+ } catch (difyError) {
6683
+ throw new Error(`All vision services failed. Kimi: ${kimiError instanceof Error ? kimiError.message : String(kimiError)}, GLM-4V: ${glmError instanceof Error ? glmError.message : String(glmError)}, Dify: ${difyError instanceof Error ? difyError.message : String(difyError)}`);
6669
6684
  }
6670
6685
  }
6671
6686
  }
@@ -6775,6 +6790,205 @@ ${logic}` : ""}`;
6775
6790
  }
6776
6791
  }
6777
6792
  }
6793
+ async analyzeTextImage(imagePath, prompt, systemPrompt, temperature = 0.1, maxTokens = 8000, stop) {
6794
+ const fs = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "fs/promises?238c"));
6795
+ const pathModule = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "path?5fdd"));
6796
+ const imageBuffer = await fs.readFile(imagePath);
6797
+ const base64 = imageBuffer.toString("base64");
6798
+ const ext = pathModule.extname(imagePath).toLowerCase();
6799
+ const mimeType = ".png" === ext ? "image/png" : "image/jpeg";
6800
+ const image_base64 = `data:${mimeType};base64,${base64}`;
6801
+ logger.k.info("[OpenAI] \u4F7F\u7528\u5185\u7F51\u6A21\u578B\u5206\u6790\u7EAF\u6587\u5B57\u56FE\u7247");
6802
+ const [visionResult, ocrResult] = await Promise.all([
6803
+ this.callInternalVision(image_base64, prompt, systemPrompt, temperature, maxTokens, stop),
6804
+ this.callInternalOCR(image_base64)
6805
+ ]);
6806
+ const coverage = this.calculateOcrCoverage(visionResult, ocrResult);
6807
+ logger.k.info("[OpenAI] \u7EAF\u6587\u5B57\u56FE\u7247\u5206\u6790\u5B8C\u6210", {
6808
+ visionLength: visionResult.length,
6809
+ ocrLength: ocrResult.length,
6810
+ coverage: `${(100 * coverage).toFixed(1)}%`
6811
+ });
6812
+ let finalResult = visionResult;
6813
+ if (coverage < 0.7 && ocrResult.length > 0.5 * visionResult.length) {
6814
+ logger.k.warn("[OpenAI] \u89C6\u89C9\u6A21\u578B\u8986\u76D6\u7387\u4F4E\uFF0C\u4F7F\u7528 OCR \u7ED3\u679C\u8865\u5145");
6815
+ finalResult = this.mergeVisionAndOcr(visionResult, ocrResult);
6816
+ }
6817
+ return {
6818
+ result: finalResult,
6819
+ ocrResult,
6820
+ coverage
6821
+ };
6822
+ }
6823
+ async analyzeComplexImage(imagePath, prompt, systemPrompt, temperature = 0.1, maxTokens = 8000) {
6824
+ logger.k.info("[OpenAI] \u4F7F\u7528 Kimi \u5206\u6790\u590D\u6742\u56FE\u7247");
6825
+ return this.analyzeImageWithPath({
6826
+ image_path: imagePath,
6827
+ prompt,
6828
+ system_prompt: systemPrompt,
6829
+ temperature,
6830
+ max_tokens: maxTokens
6831
+ });
6832
+ }
6833
+ async getInternalAgent() {
6834
+ const https = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "https"));
6835
+ return new https.Agent({
6836
+ rejectUnauthorized: false
6837
+ });
6838
+ }
6839
+ async callInternalVision(image_base64, prompt, systemPrompt, temperature = 0.1, maxTokens = 8000, stop) {
6840
+ const controller = new AbortController();
6841
+ const timeoutId = setTimeout(()=>controller.abort(), 60000);
6842
+ try {
6843
+ await this.getInternalAgent();
6844
+ const response = await fetch(this.internalConfig.baseUrl, {
6845
+ method: "POST",
6846
+ headers: {
6847
+ "Content-Type": "application/json",
6848
+ Authorization: `Bearer ${this.internalConfig.apiKey}`
6849
+ },
6850
+ body: JSON.stringify({
6851
+ model: this.internalConfig.visionModel,
6852
+ messages: [
6853
+ ...systemPrompt ? [
6854
+ {
6855
+ role: "system",
6856
+ content: systemPrompt
6857
+ }
6858
+ ] : [],
6859
+ {
6860
+ role: "user",
6861
+ content: [
6862
+ {
6863
+ type: "image_url",
6864
+ image_url: {
6865
+ url: image_base64
6866
+ }
6867
+ },
6868
+ {
6869
+ type: "text",
6870
+ text: prompt
6871
+ }
6872
+ ]
6873
+ }
6874
+ ],
6875
+ stream: false,
6876
+ temperature,
6877
+ max_tokens: maxTokens,
6878
+ ...stop ? {
6879
+ stop
6880
+ } : {}
6881
+ }),
6882
+ signal: controller.signal,
6883
+ dispatcher: new (await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "undici"))).Agent({
6884
+ connect: {
6885
+ rejectUnauthorized: false
6886
+ }
6887
+ })
6888
+ });
6889
+ clearTimeout(timeoutId);
6890
+ if (!response.ok) {
6891
+ const errorText = await response.text();
6892
+ throw new Error(`Internal Vision API error: ${response.status} - ${errorText}`);
6893
+ }
6894
+ const data = await response.json();
6895
+ if (!data.choices || 0 === data.choices.length) throw new Error("No choices returned from Internal Vision API");
6896
+ logger.k.info("[OpenAI] \u5185\u7F51\u89C6\u89C9\u6A21\u578B\u8C03\u7528\u6210\u529F");
6897
+ return data.choices[0].message.content;
6898
+ } catch (error) {
6899
+ clearTimeout(timeoutId);
6900
+ const errorMsg = error instanceof Error ? error.message : String(error);
6901
+ logger.k.error("[OpenAI] \u5185\u7F51\u89C6\u89C9\u6A21\u578B\u8C03\u7528\u5931\u8D25", {
6902
+ error: errorMsg,
6903
+ baseUrl: this.internalConfig.baseUrl,
6904
+ model: this.internalConfig.visionModel
6905
+ });
6906
+ throw error;
6907
+ }
6908
+ }
6909
+ async callInternalOCR(image_base64, stop) {
6910
+ const controller = new AbortController();
6911
+ const timeoutId = setTimeout(()=>controller.abort(), 30000);
6912
+ const ocrPrompt = `\u{8BF7}\u{63D0}\u{53D6}\u{56FE}\u{7247}\u{4E2D}\u{7684}\u{6240}\u{6709}\u{6587}\u{5B57}\u{5185}\u{5BB9}\u{FF0C}\u{539F}\u{6587}\u{7167}\u{6284}\u{FF0C}\u{4FDD}\u{6301}\u{683C}\u{5F0F}\u{3002}\u{53EA}\u{8F93}\u{51FA}\u{6587}\u{5B57}\u{FF0C}\u{4E0D}\u{8981}\u{6DFB}\u{52A0}\u{4EFB}\u{4F55}\u{89E3}\u{91CA}\u{3002}`;
6913
+ try {
6914
+ const response = await fetch(this.internalConfig.baseUrl, {
6915
+ method: "POST",
6916
+ headers: {
6917
+ "Content-Type": "application/json",
6918
+ Authorization: `Bearer ${this.internalConfig.apiKey}`
6919
+ },
6920
+ body: JSON.stringify({
6921
+ model: this.internalConfig.ocrModel,
6922
+ messages: [
6923
+ {
6924
+ role: "user",
6925
+ content: [
6926
+ {
6927
+ type: "image_url",
6928
+ image_url: {
6929
+ url: image_base64
6930
+ }
6931
+ },
6932
+ {
6933
+ type: "text",
6934
+ text: ocrPrompt
6935
+ }
6936
+ ]
6937
+ }
6938
+ ],
6939
+ stream: false,
6940
+ temperature: 0,
6941
+ max_tokens: 4000,
6942
+ ...stop ? {
6943
+ stop
6944
+ } : {
6945
+ stop: [
6946
+ "<<<END>>>"
6947
+ ]
6948
+ }
6949
+ }),
6950
+ signal: controller.signal,
6951
+ dispatcher: new (await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "undici"))).Agent({
6952
+ connect: {
6953
+ rejectUnauthorized: false
6954
+ }
6955
+ })
6956
+ });
6957
+ clearTimeout(timeoutId);
6958
+ if (!response.ok) {
6959
+ const errorText = await response.text();
6960
+ throw new Error(`Internal OCR API error: ${response.status} - ${errorText}`);
6961
+ }
6962
+ const data = await response.json();
6963
+ if (!data.choices || 0 === data.choices.length) throw new Error("No choices returned from Internal OCR API");
6964
+ logger.k.info("[OpenAI] \u5185\u7F51 OCR \u6A21\u578B\u8C03\u7528\u6210\u529F");
6965
+ return data.choices[0].message.content;
6966
+ } catch (error) {
6967
+ clearTimeout(timeoutId);
6968
+ const errorMsg = error instanceof Error ? error.message : String(error);
6969
+ logger.k.warn("[OpenAI] \u5185\u7F51 OCR \u8C03\u7528\u5931\u8D25", {
6970
+ error: errorMsg,
6971
+ baseUrl: this.internalConfig.baseUrl,
6972
+ model: this.internalConfig.ocrModel
6973
+ });
6974
+ return "";
6975
+ }
6976
+ }
6977
+ calculateOcrCoverage(visionResult, ocrResult) {
6978
+ if (!ocrResult || 0 === ocrResult.length) return 1;
6979
+ const ocrLines = ocrResult.split('\n').map((line)=>line.trim()).filter((line)=>line.length > 5);
6980
+ if (0 === ocrLines.length) return 1;
6981
+ let matchedCount = 0;
6982
+ for (const line of ocrLines){
6983
+ const sample = line.length > 10 ? line.substring(Math.floor(line.length / 2) - 5, Math.floor(line.length / 2) + 5) : line;
6984
+ if (visionResult.includes(sample)) matchedCount++;
6985
+ }
6986
+ return matchedCount / ocrLines.length;
6987
+ }
6988
+ mergeVisionAndOcr(visionResult, ocrResult) {
6989
+ if (ocrResult.length > visionResult.length) return ocrResult;
6990
+ return visionResult;
6991
+ }
6778
6992
  }
6779
6993
  const openAIService = new OpenAIService();
6780
6994
  const renderRequirementDocumentTool = {
@@ -7140,7 +7354,7 @@ ${chaptersContent}
7140
7354
  context;
7141
7355
  constructor(message, code, context){
7142
7356
  super(message), this.code = code, this.context = context;
7143
- this.name = 'ImageAnalysisError';
7357
+ this.name = "ImageAnalysisError";
7144
7358
  }
7145
7359
  }
7146
7360
  var types_AnalysisErrorCodes = /*#__PURE__*/ function(AnalysisErrorCodes) {
@@ -7153,343 +7367,602 @@ ${chaptersContent}
7153
7367
  return AnalysisErrorCodes;
7154
7368
  }({});
7155
7369
  const SUPPORTED_IMAGE_FORMATS = [
7156
- 'jpg',
7157
- 'jpeg',
7158
- 'png',
7159
- 'gif',
7160
- 'bmp',
7161
- 'tiff',
7162
- 'tif',
7163
- 'webp'
7370
+ "jpg",
7371
+ "jpeg",
7372
+ "png",
7373
+ "gif",
7374
+ "bmp",
7375
+ "tiff",
7376
+ "tif",
7377
+ "webp"
7164
7378
  ];
7165
- const DEFAULT_CHUNK_CONFIG = {
7166
- maxChunks: 6,
7167
- overlapRatio: 0.15,
7168
- minResultLength: 200
7379
+ const DEFAULT_SEGMENT_CONFIG = {
7380
+ maxHeight: 1500,
7381
+ overlapRatio: 0.1
7169
7382
  };
7170
- class ImageAnalyzer {
7171
- async analyzeImage(imagePath, context) {
7172
- const startTime = Date.now();
7173
- try {
7174
- logger.k.info("\u5F00\u59CB\u56FE\u7247\u5185\u5BB9\u5206\u6790", {
7175
- imagePath: imagePath
7176
- });
7177
- await this.validateParams(imagePath);
7178
- const basicInfo = await this.getImageBasicInfo(imagePath);
7179
- const analysisContent = await this.performSmartAnalysis(imagePath, context, basicInfo);
7180
- const processingTime = Date.now() - startTime;
7181
- if (!analysisContent) throw new ImageAnalysisError("AI\u5206\u6790\u8FD4\u56DE\u7A7A\u7ED3\u679C", types_AnalysisErrorCodes.ANALYSIS_FAILED, {
7182
- params: {
7183
- image_path: imagePath
7184
- }
7185
- });
7186
- const result = {
7187
- basic_info: basicInfo,
7188
- content: analysisContent,
7189
- processing_time_ms: processingTime
7190
- };
7191
- logger.k.info("\u56FE\u7247\u5185\u5BB9\u5206\u6790\u5B8C\u6210", {
7192
- imagePath: imagePath,
7193
- processingTimeMs: processingTime
7194
- });
7195
- return result;
7196
- } catch (error) {
7197
- logger.k.error("\u56FE\u7247\u5185\u5BB9\u5206\u6790\u5931\u8D25", {
7198
- error,
7199
- params: {
7200
- image_path: imagePath
7201
- }
7202
- });
7203
- throw error;
7204
- }
7205
- }
7206
- async performSmartAnalysis(imagePath, context, basicInfo) {
7207
- try {
7208
- logger.k.info("\u5F00\u59CB\u6574\u4F53\u56FE\u7247\u8BC6\u522B", {
7209
- imagePath
7210
- });
7211
- const initialResult = await this.performAIAnalysisWithCompletenessCheck(imagePath, context);
7212
- const completenessCheck = this.checkCompleteness(initialResult);
7213
- if (completenessCheck.complete) {
7214
- logger.k.info("\u56FE\u7247\u8BC6\u522B\u5B8C\u6574\uFF0C\u65E0\u9700\u5206\u5757");
7215
- return {
7216
- summary: completenessCheck.content,
7217
- details: {},
7218
- tags: []
7219
- };
7220
- }
7221
- logger.k.info("\u56FE\u7247\u8BC6\u522B\u4E0D\u5B8C\u6574\uFF0C\u542F\u7528\u5206\u5757\u8BC6\u522B", {
7222
- reason: completenessCheck.reason,
7223
- width: basicInfo.dimensions.width,
7224
- height: basicInfo.dimensions.height
7225
- });
7226
- const chunkedResult = await this.analyzeWithChunks(imagePath, context, basicInfo);
7227
- return {
7228
- summary: chunkedResult,
7229
- details: {
7230
- chunked: true,
7231
- reason: completenessCheck.reason
7232
- },
7233
- tags: []
7234
- };
7235
- } catch (error) {
7236
- logger.k.error("\u667A\u80FD\u5206\u6790\u5931\u8D25", {
7237
- error,
7238
- imagePath
7239
- });
7240
- throw new ImageAnalysisError("\u8BC6\u522B\u56FE\u7247\u5931\u8D25", types_AnalysisErrorCodes.ANALYSIS_FAILED, {
7241
- originalError: error
7242
- });
7243
- }
7383
+ const LONG_IMAGE_THRESHOLD = {
7384
+ minHeight: 2000,
7385
+ minAspectRatio: 2
7386
+ };
7387
+ async function getImageInfo(imagePath) {
7388
+ try {
7389
+ const metadata = await external_sharp_default()(imagePath).metadata();
7390
+ const stats = await promises_.stat(imagePath);
7391
+ return {
7392
+ path: imagePath,
7393
+ format: metadata.format || "unknown",
7394
+ dimensions: {
7395
+ width: metadata.width || 0,
7396
+ height: metadata.height || 0
7397
+ },
7398
+ file_size: stats.size
7399
+ };
7400
+ } catch (error) {
7401
+ throw new ImageAnalysisError(`\u{65E0}\u{6CD5}\u{8BFB}\u{53D6}\u{56FE}\u{7247}\u{4FE1}\u{606F}: ${imagePath}`, types_AnalysisErrorCodes.IMAGE_CORRUPTED, {
7402
+ imagePath,
7403
+ originalError: error
7404
+ });
7244
7405
  }
7245
- async performAIAnalysisWithCompletenessCheck(imagePath, context) {
7246
- const systemPrompt = `You are an OCR transcription machine. Your ONLY job is to output the EXACT text from images.
7247
- You must NEVER summarize, paraphrase, analyze, or interpret.
7248
- You must NEVER use words like "\u{9875}\u{9762}\u{7ED3}\u{6784}", "\u{6838}\u{5FC3}\u{5185}\u{5BB9}", "\u{4E3B}\u{8981}\u{529F}\u{80FD}", "\u{91CD}\u{8981}\u{901A}\u{77E5}" unless they appear verbatim in the image.
7249
- Output ONLY what you see, character by character.`;
7250
- const userPrompt = `\u{8BF7}\u{9010}\u{5B57}\u{6284}\u{5F55}\u{56FE}\u{7247}\u{4E2D}\u{7684}\u{6240}\u{6709}\u{6587}\u{5B57}\u{5185}\u{5BB9}\u{3002}
7251
-
7252
- \u{89C4}\u{5219}\u{FF1A}
7253
- 1. \u{539F}\u{6587}\u{7167}\u{6284}\u{FF1A}\u{6BCF}\u{4E00}\u{4E2A}\u{5B57}\u{3001}\u{6BCF}\u{4E00}\u{4E2A}\u{6807}\u{70B9}\u{3001}\u{6BCF}\u{4E00}\u{4E2A}\u{7A7A}\u{683C}\u{90FD}\u{8981}\u{5B8C}\u{5168}\u{4E00}\u{6837}
7254
- 2. \u{4FDD}\u{6301}\u{683C}\u{5F0F}\u{FF1A}\u{6362}\u{884C}\u{3001}\u{7F29}\u{8FDB}\u{3001}\u{5217}\u{8868}\u{7F16}\u{53F7}\u{90FD}\u{4FDD}\u{6301}\u{539F}\u{6837}
7255
- 3. \u{4EE3}\u{7801}\u{5757}\u{FF1A}\u{7528} \`\`\` \u{5305}\u{88F9}\u{FF0C}\u{4FDD}\u{6301}\u{539F}\u{59CB}\u{7F29}\u{8FDB}
7256
- 4. \u{8868}\u{683C}\u{FF1A}\u{7528} markdown \u{8868}\u{683C}\u{683C}\u{5F0F}
7257
- 5. \u{56FE}\u{7247}/\u{56FE}\u{6807}\u{FF1A}\u{7528} [\u{56FE}\u{7247}: \u{7B80}\u{8981}\u{63CF}\u{8FF0}] \u{6807}\u{6CE8}
7258
-
7259
- \u{7981}\u{6B62}\u{FF1A}
7260
- - \u{7981}\u{6B62}\u{4F7F}\u{7528}"\u{9875}\u{9762}\u{7ED3}\u{6784}"\u{3001}"\u{6838}\u{5FC3}\u{5185}\u{5BB9}"\u{3001}"\u{4E3B}\u{8981}\u{529F}\u{80FD}"\u{7B49}\u{603B}\u{7ED3}\u{6027}\u{8BCD}\u{6C47}\u{FF08}\u{9664}\u{975E}\u{56FE}\u{7247}\u{4E2D}\u{539F}\u{6587}\u{5C31}\u{6709}\u{FF09}
7261
- - \u{7981}\u{6B62}\u{6DFB}\u{52A0}\u{4EFB}\u{4F55}\u{89E3}\u{91CA}\u{3001}\u{5206}\u{6790}\u{3001}\u{8BC4}\u{8BBA}
7262
- - \u{7981}\u{6B62}\u{7701}\u{7565}\u{4EFB}\u{4F55}\u{5185}\u{5BB9}
7263
-
7264
- ${context ? `\u{8865}\u{5145}\u{8981}\u{6C42}\u{FF1A}${context}\n\n` : ''}\u{73B0}\u{5728}\u{5F00}\u{59CB}\u{9010}\u{5B57}\u{6284}\u{5F55}\u{FF1A}`;
7265
- const aiResponse = await openAIService.analyzeImageWithPath({
7266
- image_path: imagePath,
7267
- prompt: userPrompt,
7268
- system_prompt: systemPrompt,
7269
- temperature: 0,
7270
- max_tokens: 8000
7406
+ }
7407
+ function image_processor_isLongImage(info) {
7408
+ const { width, height } = info.dimensions;
7409
+ const aspectRatio = height / width;
7410
+ return height > LONG_IMAGE_THRESHOLD.minHeight && aspectRatio > LONG_IMAGE_THRESHOLD.minAspectRatio;
7411
+ }
7412
+ async function validateImage(imagePath) {
7413
+ try {
7414
+ await promises_.access(imagePath);
7415
+ } catch {
7416
+ throw new ImageAnalysisError(`\u{56FE}\u{7247}\u{6587}\u{4EF6}\u{4E0D}\u{5B58}\u{5728}: ${imagePath}`, types_AnalysisErrorCodes.FILE_NOT_FOUND, {
7417
+ imagePath
7271
7418
  });
7272
- return aiResponse.trim();
7273
7419
  }
7274
- checkCompleteness(result) {
7275
- if (result.includes("[\u5B8C\u6574]")) return {
7276
- complete: true,
7277
- content: result.replace(/\[完整\]/g, '').trim()
7420
+ const ext = external_path_.extname(imagePath).slice(1).toLowerCase();
7421
+ if (!SUPPORTED_IMAGE_FORMATS.includes(ext)) throw new ImageAnalysisError(`\u{4E0D}\u{652F}\u{6301}\u{7684}\u{56FE}\u{7247}\u{683C}\u{5F0F}: ${ext}`, types_AnalysisErrorCodes.UNSUPPORTED_FORMAT, {
7422
+ format: ext,
7423
+ supportedFormats: SUPPORTED_IMAGE_FORMATS
7424
+ });
7425
+ }
7426
+ async function splitLongImage(imagePath, info, config = DEFAULT_SEGMENT_CONFIG) {
7427
+ const { width, height } = info.dimensions;
7428
+ const { maxHeight, overlapRatio } = config;
7429
+ const overlap = Math.floor(maxHeight * overlapRatio);
7430
+ const segments = [];
7431
+ let currentY = 0;
7432
+ let index = 0;
7433
+ while(currentY < height){
7434
+ const endY = Math.min(currentY + maxHeight, height);
7435
+ const segmentHeight = endY - currentY;
7436
+ const buffer = await external_sharp_default()(imagePath).extract({
7437
+ left: 0,
7438
+ top: currentY,
7439
+ width: width,
7440
+ height: segmentHeight
7441
+ }).jpeg({
7442
+ quality: 90
7443
+ }).toBuffer();
7444
+ segments.push({
7445
+ index,
7446
+ total: 0,
7447
+ startY: currentY,
7448
+ endY,
7449
+ buffer
7450
+ });
7451
+ currentY = endY - overlap;
7452
+ if (currentY >= height - overlap) break;
7453
+ index++;
7454
+ }
7455
+ const total = segments.length;
7456
+ segments.forEach((s)=>s.total = total);
7457
+ logger.k.info("\u957F\u56FE\u5206\u6BB5\u5B8C\u6210", {
7458
+ width,
7459
+ height,
7460
+ segments: total
7461
+ });
7462
+ return segments;
7463
+ }
7464
+ async function saveSegmentToTemp(segment) {
7465
+ const tempPath = external_path_.join("/tmp", `segment_${Date.now()}_${segment.index}.jpg`);
7466
+ await promises_.writeFile(tempPath, segment.buffer);
7467
+ return tempPath;
7468
+ }
7469
+ async function cleanupTempFile(filePath) {
7470
+ try {
7471
+ await promises_.unlink(filePath);
7472
+ } catch {}
7473
+ }
7474
+ function mergeSegmentResults(results) {
7475
+ if (0 === results.length) return "";
7476
+ if (1 === results.length) return results[0];
7477
+ let merged = results[0];
7478
+ for(let i = 1; i < results.length; i++){
7479
+ const current = results[i];
7480
+ const overlapLen = findTextOverlap(merged, current);
7481
+ if (overlapLen > 0) merged += "\n" + current.substring(overlapLen);
7482
+ else merged += "\n\n" + current;
7483
+ }
7484
+ return merged.trim();
7485
+ }
7486
+ function findTextOverlap(prev, curr) {
7487
+ const prevLines = prev.split("\n").slice(-10);
7488
+ const currLines = curr.split("\n").slice(0, 10);
7489
+ for(let i = Math.min(prevLines.length, currLines.length); i >= 2; i--){
7490
+ const prevTail = prevLines.slice(-i).map((l)=>l.trim()).join("\n");
7491
+ const currHead = currLines.slice(0, i).map((l)=>l.trim()).join("\n");
7492
+ if (prevTail === currHead) return currLines.slice(0, i).join("\n").length;
7493
+ }
7494
+ return 0;
7495
+ }
7496
+ const INTERNAL_CONFIG = {
7497
+ apiKey: "sk-3W5NXAzeXX9mNP5yppQwPt6cnEoSK03u5NgiNW1Hsi41Tniu",
7498
+ baseUrl: "https://aiproxy.jla.petrotech.cnpc/v1/chat/completions",
7499
+ visionModel: "qwen2-7b-vl",
7500
+ ocrModel: "deepseek-ocr"
7501
+ };
7502
+ const DIFY_CONFIG = {
7503
+ apiKey: "app-xPG7ROh2YaAzR3v9vKnhAWpz"
7504
+ };
7505
+ const KIMI_CONFIG = {
7506
+ apiKey: "sk-fp8wJSigZBEP3x8y6MAZWGPuVIHJ5PDZtX9lMQQk8hjP2R0u",
7507
+ baseUrl: "https://api.moonshot.cn/v1/chat/completions",
7508
+ model: "moonshot-v1-128k-vision-preview"
7509
+ };
7510
+ const GLM_CONFIG = {
7511
+ apiKey: "fb26a7ff758c3974e43bfff49a684dd3.apcuRq6v6RvwuJDu",
7512
+ baseUrl: "https://open.bigmodel.cn/api/paas/v4/chat/completions",
7513
+ model: "glm-4v-flash"
7514
+ };
7515
+ async function getHttpsAgent() {
7516
+ const { Agent } = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "undici"));
7517
+ return new Agent({
7518
+ connect: {
7519
+ rejectUnauthorized: false
7520
+ }
7521
+ });
7522
+ }
7523
+ async function imageToBase64(imagePath) {
7524
+ const buffer = await promises_.readFile(imagePath);
7525
+ const ext = external_path_.extname(imagePath).toLowerCase();
7526
+ const mimeType = ".png" === ext ? "image/png" : "image/jpeg";
7527
+ return `data:${mimeType};base64,${buffer.toString("base64")}`;
7528
+ }
7529
+ function bufferToBase64(buffer, format = "jpeg") {
7530
+ const mimeType = "png" === format ? "image/png" : "image/jpeg";
7531
+ return `data:${mimeType};base64,${buffer.toString("base64")}`;
7532
+ }
7533
+ const SYSTEM_PROMPT = `You must interpret and analyze images strictly according to the assigned task.
7534
+ When an image is provided, your role is to parse the image content only within the scope of the user's instructions.
7535
+ Do not ignore or deviate from the task.
7536
+ Always ensure that your response reflects a clear, accurate interpretation of the image aligned with the given objective.`;
7537
+ async function callInternalVision(imageBase64, prompt, maxTokens = 8000) {
7538
+ const controller = new AbortController();
7539
+ const timeoutId = setTimeout(()=>controller.abort(), 90000);
7540
+ try {
7541
+ const agent = await getHttpsAgent();
7542
+ const response = await fetch(INTERNAL_CONFIG.baseUrl, {
7543
+ method: "POST",
7544
+ headers: {
7545
+ "Content-Type": "application/json",
7546
+ Authorization: `Bearer ${INTERNAL_CONFIG.apiKey}`
7547
+ },
7548
+ body: JSON.stringify({
7549
+ model: INTERNAL_CONFIG.visionModel,
7550
+ messages: [
7551
+ {
7552
+ role: "system",
7553
+ content: SYSTEM_PROMPT
7554
+ },
7555
+ {
7556
+ role: "user",
7557
+ content: [
7558
+ {
7559
+ type: "image_url",
7560
+ image_url: {
7561
+ url: imageBase64
7562
+ }
7563
+ },
7564
+ {
7565
+ type: "text",
7566
+ text: prompt
7567
+ }
7568
+ ]
7569
+ }
7570
+ ],
7571
+ temperature: 0.2,
7572
+ max_tokens: maxTokens
7573
+ }),
7574
+ signal: controller.signal,
7575
+ dispatcher: agent
7576
+ });
7577
+ clearTimeout(timeoutId);
7578
+ if (!response.ok) {
7579
+ const errorText = await response.text();
7580
+ throw new Error(`\u{5185}\u{7F51}\u{89C6}\u{89C9}\u{6A21}\u{578B}\u{9519}\u{8BEF}: ${response.status} - ${errorText}`);
7581
+ }
7582
+ const data = await response.json();
7583
+ const content = data.choices?.[0]?.message?.content || "";
7584
+ if (!content) throw new Error("\u5185\u7F51\u89C6\u89C9\u6A21\u578B\u8FD4\u56DE\u7A7A\u7ED3\u679C");
7585
+ logger.k.info("\u5185\u7F51\u89C6\u89C9\u6A21\u578B\u8C03\u7528\u6210\u529F", {
7586
+ contentLength: content.length
7587
+ });
7588
+ return content;
7589
+ } catch (error) {
7590
+ clearTimeout(timeoutId);
7591
+ throw error;
7592
+ }
7593
+ }
7594
+ async function callInternalOCR(imageBase64, prompt, maxTokens = 4000) {
7595
+ const controller = new AbortController();
7596
+ const timeoutId = setTimeout(()=>controller.abort(), 60000);
7597
+ try {
7598
+ const agent = await getHttpsAgent();
7599
+ const response = await fetch(INTERNAL_CONFIG.baseUrl, {
7600
+ method: "POST",
7601
+ headers: {
7602
+ "Content-Type": "application/json",
7603
+ Authorization: `Bearer ${INTERNAL_CONFIG.apiKey}`
7604
+ },
7605
+ body: JSON.stringify({
7606
+ model: INTERNAL_CONFIG.ocrModel,
7607
+ messages: [
7608
+ {
7609
+ role: "system",
7610
+ content: SYSTEM_PROMPT
7611
+ },
7612
+ {
7613
+ role: "user",
7614
+ content: [
7615
+ {
7616
+ type: "image_url",
7617
+ image_url: {
7618
+ url: imageBase64
7619
+ }
7620
+ },
7621
+ {
7622
+ type: "text",
7623
+ text: prompt
7624
+ }
7625
+ ]
7626
+ }
7627
+ ],
7628
+ temperature: 0.2,
7629
+ max_tokens: maxTokens
7630
+ }),
7631
+ signal: controller.signal,
7632
+ dispatcher: agent
7633
+ });
7634
+ clearTimeout(timeoutId);
7635
+ if (!response.ok) throw new Error(`\u{5185}\u{7F51}OCR\u{9519}\u{8BEF}: ${response.status}`);
7636
+ const data = await response.json();
7637
+ const content = data.choices?.[0]?.message?.content || "";
7638
+ logger.k.info("\u5185\u7F51OCR\u8C03\u7528\u6210\u529F", {
7639
+ contentLength: content.length
7640
+ });
7641
+ return content;
7642
+ } catch (error) {
7643
+ clearTimeout(timeoutId);
7644
+ logger.k.warn("\u5185\u7F51OCR\u8C03\u7528\u5931\u8D25", {
7645
+ error
7646
+ });
7647
+ return "";
7648
+ }
7649
+ }
7650
+ async function callDifyWorkflow(imagePath, context) {
7651
+ try {
7652
+ const uploadResult = await uploadFile({
7653
+ appid: DIFY_CONFIG.apiKey,
7654
+ filePath: imagePath,
7655
+ user: "aico-mcp"
7656
+ });
7657
+ logger.k.info("Dify \u6587\u4EF6\u4E0A\u4F20\u6210\u529F", {
7658
+ fileId: uploadResult.id
7659
+ });
7660
+ const workflowData = {
7661
+ imagePath: {
7662
+ type: "image",
7663
+ transfer_method: "local_file",
7664
+ upload_file_id: uploadResult.id
7665
+ },
7666
+ context: context
7278
7667
  };
7279
- const incompleteMatch = result.match(/\[可能不完整[:::](.+?)\]/i);
7280
- if (incompleteMatch) return {
7281
- complete: false,
7282
- reason: incompleteMatch[1].trim(),
7283
- content: result.replace(/\[可能不完整[:::].+?\]/gi, '').trim()
7668
+ const response = await invokeFlow({
7669
+ appid: DIFY_CONFIG.apiKey,
7670
+ data: workflowData,
7671
+ timeout: 120000
7672
+ });
7673
+ let content = "";
7674
+ if ("string" == typeof response && response.length > 0) content = response;
7675
+ else if (response?.outputs?.text) content = response.outputs.text;
7676
+ else if (response?.data?.outputs?.text) content = response.data.outputs.text;
7677
+ if (!content) throw new Error("Dify \u54CD\u5E94\u4E2D\u672A\u627E\u5230\u6709\u6548\u5185\u5BB9");
7678
+ logger.k.info("Dify \u5DE5\u4F5C\u6D41\u8C03\u7528\u6210\u529F", {
7679
+ contentLength: content.length
7680
+ });
7681
+ return content;
7682
+ } catch (error) {
7683
+ throw error;
7684
+ }
7685
+ }
7686
+ async function callKimiVision(imageBase64, prompt, maxTokens = 8000) {
7687
+ const controller = new AbortController();
7688
+ const timeoutId = setTimeout(()=>controller.abort(), 90000);
7689
+ try {
7690
+ const response = await fetch(KIMI_CONFIG.baseUrl, {
7691
+ method: "POST",
7692
+ headers: {
7693
+ "Content-Type": "application/json",
7694
+ Authorization: `Bearer ${KIMI_CONFIG.apiKey}`
7695
+ },
7696
+ body: JSON.stringify({
7697
+ model: KIMI_CONFIG.model,
7698
+ messages: [
7699
+ {
7700
+ role: "system",
7701
+ content: SYSTEM_PROMPT
7702
+ },
7703
+ {
7704
+ role: "user",
7705
+ content: [
7706
+ {
7707
+ type: "image_url",
7708
+ image_url: {
7709
+ url: imageBase64
7710
+ }
7711
+ },
7712
+ {
7713
+ type: "text",
7714
+ text: prompt
7715
+ }
7716
+ ]
7717
+ }
7718
+ ],
7719
+ temperature: 0.2,
7720
+ max_tokens: maxTokens
7721
+ }),
7722
+ signal: controller.signal
7723
+ });
7724
+ clearTimeout(timeoutId);
7725
+ if (!response.ok) {
7726
+ const errorText = await response.text();
7727
+ throw new Error(`Kimi \u{9519}\u{8BEF}: ${response.status} - ${errorText}`);
7728
+ }
7729
+ const data = await response.json();
7730
+ const content = data.choices?.[0]?.message?.content || "";
7731
+ if (!content) throw new Error("Kimi \u8FD4\u56DE\u7A7A\u7ED3\u679C");
7732
+ logger.k.info("Kimi Vision \u8C03\u7528\u6210\u529F", {
7733
+ contentLength: content.length
7734
+ });
7735
+ return content;
7736
+ } catch (error) {
7737
+ clearTimeout(timeoutId);
7738
+ throw error;
7739
+ }
7740
+ }
7741
+ async function callGLMVision(imageBase64, prompt, maxTokens = 4000) {
7742
+ const controller = new AbortController();
7743
+ const timeoutId = setTimeout(()=>controller.abort(), 60000);
7744
+ try {
7745
+ const response = await fetch(GLM_CONFIG.baseUrl, {
7746
+ method: "POST",
7747
+ headers: {
7748
+ "Content-Type": "application/json",
7749
+ Authorization: `Bearer ${GLM_CONFIG.apiKey}`
7750
+ },
7751
+ body: JSON.stringify({
7752
+ model: GLM_CONFIG.model,
7753
+ messages: [
7754
+ {
7755
+ role: "system",
7756
+ content: SYSTEM_PROMPT
7757
+ },
7758
+ {
7759
+ role: "user",
7760
+ content: [
7761
+ {
7762
+ type: "image_url",
7763
+ image_url: {
7764
+ url: imageBase64
7765
+ }
7766
+ },
7767
+ {
7768
+ type: "text",
7769
+ text: prompt
7770
+ }
7771
+ ]
7772
+ }
7773
+ ],
7774
+ temperature: 0.2,
7775
+ max_tokens: maxTokens
7776
+ }),
7777
+ signal: controller.signal
7778
+ });
7779
+ clearTimeout(timeoutId);
7780
+ if (!response.ok) {
7781
+ const errorText = await response.text();
7782
+ throw new Error(`GLM-4V \u{9519}\u{8BEF}: ${response.status} - ${errorText}`);
7783
+ }
7784
+ const data = await response.json();
7785
+ const content = data.choices?.[0]?.message?.content || "";
7786
+ if (!content) throw new Error("GLM-4V \u8FD4\u56DE\u7A7A\u7ED3\u679C");
7787
+ logger.k.info("GLM-4V \u8C03\u7528\u6210\u529F", {
7788
+ contentLength: content.length
7789
+ });
7790
+ return content;
7791
+ } catch (error) {
7792
+ clearTimeout(timeoutId);
7793
+ throw error;
7794
+ }
7795
+ }
7796
+ async function analyzeWithVision(imagePath, imageBase64, prompt, context) {
7797
+ try {
7798
+ const [visionResult, ocrResult] = await Promise.all([
7799
+ callInternalVision(imageBase64, prompt).catch(()=>""),
7800
+ callInternalOCR(imageBase64, prompt).catch(()=>"")
7801
+ ]);
7802
+ if (visionResult || ocrResult) {
7803
+ const chosen = chooseBestTranscription(visionResult, ocrResult);
7804
+ return {
7805
+ content: chosen.content,
7806
+ model: chosen.source
7807
+ };
7808
+ }
7809
+ throw new Error("\u5185\u7F51\u6A21\u578B\u5747\u8FD4\u56DE\u7A7A\u7ED3\u679C");
7810
+ } catch (internalError) {
7811
+ logger.k.warn("\u5185\u7F51\u6A21\u578B\u5931\u8D25", {
7812
+ error: internalError
7813
+ });
7814
+ }
7815
+ try {
7816
+ const content = await callKimiVision(imageBase64, prompt);
7817
+ return {
7818
+ content,
7819
+ model: "kimi"
7284
7820
  };
7285
- if (result.length < DEFAULT_CHUNK_CONFIG.minResultLength) return {
7286
- complete: false,
7287
- reason: "\u8BC6\u522B\u7ED3\u679C\u8FC7\u77ED",
7288
- content: result
7821
+ } catch (kimiError) {
7822
+ logger.k.warn("Kimi \u5931\u8D25", {
7823
+ error: kimiError
7824
+ });
7825
+ }
7826
+ try {
7827
+ const content = await callGLMVision(imageBase64, prompt);
7828
+ return {
7829
+ content,
7830
+ model: "glm"
7289
7831
  };
7832
+ } catch (glmError) {
7833
+ logger.k.warn("GLM-4V \u5931\u8D25", {
7834
+ error: glmError
7835
+ });
7836
+ }
7837
+ const content = await callDifyWorkflow(imagePath, context || prompt);
7838
+ return {
7839
+ content,
7840
+ model: "dify"
7841
+ };
7842
+ }
7843
+ function chooseBestTranscription(vision, ocr) {
7844
+ const hasSummaryPattern = (s)=>{
7845
+ if (!s) return false;
7846
+ const lines = s.split(/\r?\n/).slice(0, 5).join("\n");
7847
+ const summaryHeaders = /(截图内容分析|核心信息|功能描述|接口说明|限制条件|主要内容|图片内容|内容概述)/;
7848
+ const chattyPrefix = /^(好的|如下|以下为|以下是|我将|这是一张|根据图片|请见)[,,::]?/m;
7849
+ return summaryHeaders.test(lines) || chattyPrefix.test(lines);
7850
+ };
7851
+ const visionIsSummary = hasSummaryPattern(vision);
7852
+ const ocrIsSummary = hasSummaryPattern(ocr);
7853
+ if (ocr && !ocrIsSummary) return {
7854
+ content: ocr,
7855
+ source: "internal-ocr"
7856
+ };
7857
+ if (vision && !visionIsSummary) return {
7858
+ content: vision,
7859
+ source: "internal-vision"
7860
+ };
7861
+ if ((ocr || "").length >= (vision || "").length) return {
7862
+ content: ocr || vision,
7863
+ source: ocr ? "internal-ocr" : "internal-vision"
7864
+ };
7865
+ return {
7866
+ content: vision,
7867
+ source: "internal-vision"
7868
+ };
7869
+ }
7870
+ class ImageAnalyzer {
7871
+ async analyzeImage(imagePath, context) {
7872
+ const startTime = Date.now();
7873
+ logger.k.info("\u5F00\u59CB\u56FE\u7247\u5206\u6790", {
7874
+ imagePath
7875
+ });
7876
+ await validateImage(imagePath);
7877
+ const imageInfo = await getImageInfo(imagePath);
7878
+ logger.k.info("\u56FE\u7247\u4FE1\u606F", {
7879
+ width: imageInfo.dimensions.width,
7880
+ height: imageInfo.dimensions.height,
7881
+ format: imageInfo.format
7882
+ });
7883
+ let content;
7884
+ content = image_processor_isLongImage(imageInfo) ? await this.analyzeLongImage(imagePath, imageInfo, context) : await this.analyzeSingleImage(imagePath, context);
7885
+ const processingTime = Date.now() - startTime;
7886
+ logger.k.info("\u56FE\u7247\u5206\u6790\u5B8C\u6210", {
7887
+ processingTime,
7888
+ contentLength: content.summary.length
7889
+ });
7290
7890
  return {
7291
- complete: true,
7292
- content: result
7891
+ basic_info: imageInfo,
7892
+ content,
7893
+ processing_time_ms: processingTime
7293
7894
  };
7294
7895
  }
7295
- async analyzeWithChunks(imagePath, context, basicInfo) {
7296
- const { width, height } = basicInfo.dimensions;
7297
- const chunks = this.calculateChunks(width, height);
7298
- logger.k.info("\u56FE\u7247\u5206\u5757\u65B9\u6848", {
7299
- totalChunks: chunks.length,
7300
- chunks: chunks.map((c)=>({
7301
- position: c.position,
7302
- x: c.x,
7303
- y: c.y,
7304
- width: c.width,
7305
- height: c.height
7306
- }))
7896
+ async analyzeSingleImage(imagePath, context) {
7897
+ const imageBase64 = await imageToBase64(imagePath);
7898
+ const prompt = this.buildPrompt(context);
7899
+ const result = await analyzeWithVision(imagePath, imageBase64, prompt, context);
7900
+ logger.k.info("\u56FE\u7247\u8BC6\u522B\u5B8C\u6210", {
7901
+ model: result.model,
7902
+ contentLength: result.content.length
7307
7903
  });
7308
- const chunkResults = [];
7309
- const tempDir = await promises_.mkdtemp(external_path_.join(external_os_.tmpdir(), 'image-chunks-'));
7310
- try {
7311
- const concurrencyLimit = 3;
7312
- for(let i = 0; i < chunks.length; i += concurrencyLimit){
7313
- const batch = chunks.slice(i, i + concurrencyLimit);
7314
- const batchResults = await Promise.all(batch.map(async (chunk)=>{
7315
- const chunkPath = await this.extractChunk(imagePath, chunk, tempDir);
7316
- const content = await this.analyzeChunk(chunkPath, chunk.position, context);
7317
- return {
7318
- chunk,
7319
- content,
7320
- isComplete: true
7321
- };
7322
- }));
7323
- chunkResults.push(...batchResults);
7324
- }
7325
- const mergedResult = await this.mergeChunkResults(chunkResults, context);
7326
- return mergedResult;
7327
- } finally{
7904
+ return {
7905
+ summary: result.content,
7906
+ details: {
7907
+ model: result.model
7908
+ },
7909
+ tags: []
7910
+ };
7911
+ }
7912
+ async analyzeLongImage(imagePath, imageInfo, context) {
7913
+ const segments = await splitLongImage(imagePath, imageInfo);
7914
+ const results = [];
7915
+ const models = [];
7916
+ for (const segment of segments){
7917
+ const segmentBase64 = bufferToBase64(segment.buffer);
7918
+ const prompt = this.buildPrompt(context, segment.index + 1, segment.total);
7919
+ const tempPath = await saveSegmentToTemp(segment);
7328
7920
  try {
7329
- await promises_.rm(tempDir, {
7330
- recursive: true,
7331
- force: true
7921
+ const result = await analyzeWithVision(tempPath, segmentBase64, prompt, context);
7922
+ results.push(result.content);
7923
+ models.push(result.model);
7924
+ logger.k.info(`\u{5206}\u{6BB5} ${segment.index + 1}/${segment.total} \u{5B8C}\u{6210}`, {
7925
+ model: result.model
7332
7926
  });
7333
- } catch (e) {
7334
- logger.k.warn("\u6E05\u7406\u4E34\u65F6\u6587\u4EF6\u5931\u8D25", {
7335
- tempDir,
7336
- error: e
7927
+ } catch (error) {
7928
+ logger.k.error(`\u{5206}\u{6BB5} ${segment.index + 1} \u{8BC6}\u{522B}\u{5931}\u{8D25}`, {
7929
+ error
7337
7930
  });
7931
+ results.push(`[\u{7B2C} ${segment.index + 1} \u{90E8}\u{5206}\u{8BC6}\u{522B}\u{5931}\u{8D25}]`);
7932
+ } finally{
7933
+ await cleanupTempFile(tempPath);
7338
7934
  }
7339
7935
  }
7936
+ const mergedContent = mergeSegmentResults(results);
7937
+ return {
7938
+ summary: mergedContent,
7939
+ details: {
7940
+ segments: segments.length,
7941
+ models: [
7942
+ ...new Set(models)
7943
+ ]
7944
+ },
7945
+ tags: []
7946
+ };
7340
7947
  }
7341
- calculateChunks(width, height) {
7342
- const chunks = [];
7343
- const area = width * height;
7344
- let cols, rows;
7345
- if (area <= 2000000) {
7346
- cols = 1;
7347
- rows = 1;
7348
- } else if (area <= 4000000) {
7349
- cols = 2;
7350
- rows = 1;
7351
- } else if (area <= 6000000) {
7352
- cols = 2;
7353
- rows = 2;
7354
- } else {
7355
- cols = 3;
7356
- rows = 2;
7357
- }
7358
- if (1 === cols && 1 === rows) return [
7359
- {
7360
- index: 0,
7361
- position: "\u5168\u56FE",
7362
- x: 0,
7363
- y: 0,
7364
- width,
7365
- height
7366
- }
7367
- ];
7368
- const overlapRatio = DEFAULT_CHUNK_CONFIG.overlapRatio;
7369
- const chunkWidth = Math.ceil(width / cols);
7370
- const chunkHeight = Math.ceil(height / rows);
7371
- const overlapX = Math.ceil(chunkWidth * overlapRatio);
7372
- const overlapY = Math.ceil(chunkHeight * overlapRatio);
7373
- const positionNames = [
7374
- [
7375
- "\u5DE6\u4E0A",
7376
- "\u4E2D\u4E0A",
7377
- "\u53F3\u4E0A"
7378
- ],
7379
- [
7380
- "\u5DE6\u4E2D",
7381
- "\u4E2D\u592E",
7382
- "\u53F3\u4E2D"
7383
- ],
7384
- [
7385
- "\u5DE6\u4E0B",
7386
- "\u4E2D\u4E0B",
7387
- "\u53F3\u4E0B"
7388
- ]
7389
- ];
7390
- let index = 0;
7391
- for(let row = 0; row < rows; row++)for(let col = 0; col < cols; col++){
7392
- const x = Math.max(0, col * chunkWidth - (col > 0 ? overlapX : 0));
7393
- const y = Math.max(0, row * chunkHeight - (row > 0 ? overlapY : 0));
7394
- const w = Math.min(chunkWidth + (col > 0 ? overlapX : 0) + (col < cols - 1 ? overlapX : 0), width - x);
7395
- const h = Math.min(chunkHeight + (row > 0 ? overlapY : 0) + (row < rows - 1 ? overlapY : 0), height - y);
7396
- chunks.push({
7397
- index,
7398
- position: positionNames[row]?.[col] || `\u{533A}\u{57DF}${index + 1}`,
7399
- x,
7400
- y,
7401
- width: w,
7402
- height: h
7403
- });
7404
- index++;
7405
- }
7406
- return chunks;
7407
- }
7408
- async extractChunk(imagePath, chunk, tempDir) {
7409
- const chunkPath = external_path_.join(tempDir, `chunk_${chunk.index}.png`);
7410
- await external_sharp_default()(imagePath).extract({
7411
- left: chunk.x,
7412
- top: chunk.y,
7413
- width: chunk.width,
7414
- height: chunk.height
7415
- }).toFile(chunkPath);
7416
- return chunkPath;
7417
- }
7418
- async analyzeChunk(chunkPath, position, context) {
7419
- const systemPrompt = "You are an OCR transcription machine. Output ONLY the exact text from images. Never summarize or interpret.";
7420
- const userPrompt = `\u{8FD9}\u{662F}\u{56FE}\u{7247}\u{7684}\u{3010}${position}\u{3011}\u{90E8}\u{5206}\u{3002}\u{8BF7}\u{9010}\u{5B57}\u{6284}\u{5F55}\u{6B64}\u{533A}\u{57DF}\u{5185}\u{7684}\u{6240}\u{6709}\u{6587}\u{5B57}\u{3002}
7948
+ buildPrompt(context, segmentIndex, totalSegments) {
7949
+ let prompt = `\u{4F60}\u{662F}\u{4E00}\u{4E2A}\u{4EC5}\u{505A}\u{9010}\u{5B57}\u{6284}\u{5F55}\u{7684} OCR \u{5DE5}\u{5177}\u{FF0C}\u{53EA}\u{80FD}\u{628A}\u{56FE}\u{7247}\u{91CC}\u{7684}\u{6587}\u{5B57}\u{539F}\u{6837}\u{6284}\u{5199}\u{51FA}\u{6765}\u{FF0C}\u{4E0D}\u{5141}\u{8BB8}\u{6DFB}\u{52A0}\u{4EFB}\u{4F55}\u{8BF4}\u{660E}\u{6216}\u{603B}\u{7ED3}\u{3002}
7421
7950
 
7422
7951
  \u{89C4}\u{5219}\u{FF1A}
7423
- 1. \u{539F}\u{6587}\u{7167}\u{6284}\u{FF0C}\u{4FDD}\u{6301}\u{683C}\u{5F0F}
7424
- 2. \u{4EE3}\u{7801}\u{7528} \`\`\` \u{5305}\u{88F9}
7425
- 3. \u{56FE}\u{7247}/\u{56FE}\u{6807}\u{7528} [\u{56FE}\u{7247}: \u{63CF}\u{8FF0}] \u{6807}\u{6CE8}
7426
- 4. \u{7981}\u{6B62}\u{603B}\u{7ED3}\u{3001}\u{7981}\u{6B62}\u{89E3}\u{91CA}
7427
-
7428
- ${context ? `\u{8865}\u{5145}\u{FF1A}${context}\n\n` : ''}\u{5F00}\u{59CB}\u{6284}\u{5F55}\u{FF1A}`;
7429
- const aiResponse = await openAIService.analyzeImageWithPath({
7430
- image_path: chunkPath,
7431
- prompt: userPrompt,
7432
- system_prompt: systemPrompt,
7433
- temperature: 0,
7434
- max_tokens: 4000
7435
- });
7436
- return aiResponse.trim();
7437
- }
7438
- async mergeChunkResults(chunkResults, context) {
7439
- if (1 === chunkResults.length) return chunkResults[0].content;
7440
- const chunkedResultsText = chunkResults.map((r)=>`### ${r.chunk.position}\u{533A}\u{57DF}
7441
- ${r.content}`).join('\n\n');
7442
- const mergePrompt = `\u{4EE5}\u{4E0B}\u{662F}\u{540C}\u{4E00}\u{5F20}\u{56FE}\u{7247}\u{4E0D}\u{540C}\u{533A}\u{57DF}\u{7684}\u{8BC6}\u{522B}\u{7ED3}\u{679C}\u{FF0C}\u{8BF7}\u{6574}\u{5408}\u{4E3A}\u{5B8C}\u{6574}\u{7684}\u{56FE}\u{7247}\u{63CF}\u{8FF0}\u{FF1A}
7443
-
7444
- 1. \u{5408}\u{5E76}\u{6240}\u{6709}\u{533A}\u{57DF}\u{7684}\u{5185}\u{5BB9}
7445
- 2. \u{6D88}\u{9664}\u{91CD}\u{590D}\u{63CF}\u{8FF0}\u{FF08}\u{91CD}\u{53E0}\u{533A}\u{57DF}\u{53EF}\u{80FD}\u{6709}\u{76F8}\u{540C}\u{5185}\u{5BB9}\u{FF09}
7446
- 3. \u{4FDD}\u{6301}\u{5185}\u{5BB9}\u{7684}\u{7A7A}\u{95F4}\u{4F4D}\u{7F6E}\u{5173}\u{7CFB}
7447
- 4. \u{4E0D}\u{6DFB}\u{52A0}\u{3001}\u{4E0D}\u{4FEE}\u{6539}\u{539F}\u{59CB}\u{8BC6}\u{522B}\u{5230}\u{7684}\u{5185}\u{5BB9}
7448
-
7449
- ${context}
7952
+ 1) \u{539F}\u{6587}\u{7167}\u{6284}\u{FF1A}\u{56FE}\u{7247}\u{91CC}\u{6709}\u{4EC0}\u{4E48}\u{5C31}\u{8F93}\u{51FA}\u{4EC0}\u{4E48}\u{FF0C}\u{4E00}\u{4E2A}\u{5B57}\u{90FD}\u{4E0D}\u{80FD}\u{5C11}\u{6216}\u{6539}
7953
+ 2) \u{4FDD}\u{6301}\u{683C}\u{5F0F}\u{FF1A}\u{6362}\u{884C}\u{3001}\u{7A7A}\u{683C}\u{3001}\u{7F29}\u{8FDB}\u{3001}\u{5217}\u{8868}\u{7F16}\u{53F7}\u{5168}\u{90E8}\u{4FDD}\u{7559}
7954
+ 3) \u{4EE3}\u{7801}\u{5757}\u{FF1A}\u{7528} \`\`\` \u{5305}\u{88F9}\u{FF0C}\u{7F29}\u{8FDB}\u{4E0E}\u{7A7A}\u{683C}\u{5FC5}\u{987B}\u{4FDD}\u{6301}
7955
+ 4) \u{8868}\u{683C}\u{FF1A}\u{7528} markdown \u{8868}\u{683C}\u{8868}\u{793A}
7956
+ 5) \u{7981}\u{6B62}\u{6DFB}\u{52A0}\u{5F00}\u{573A}\u{767D}\u{FF08}\u{5982}\u{201C}\u{4EE5}\u{4E0B}\u{662F}/\u{4E0B}\u{9762}\u{662F}/\u{6211}\u{5C06}/\u{8FD9}\u{662F}\u{2026}\u{201D}\u{FF09}
7957
+ 6) \u{7981}\u{6B62}\u{51ED}\u{7A7A}\u{751F}\u{6210}\u{6807}\u{9898}\u{FF08}\u{5982}\u{201C}\u{6838}\u{5FC3}\u{4FE1}\u{606F}/\u{529F}\u{80FD}\u{63CF}\u{8FF0}/\u{63A5}\u{53E3}\u{8BF4}\u{660E}\u{201D}\u{7B49}\u{FF09}\u{3002}\u{5982}\u{679C}\u{8FD9}\u{4E9B}\u{8BCD}\u{51FA}\u{73B0}\u{5728}\u{56FE}\u{7247}\u{91CC}\u{FF0C}\u{6309}\u{539F}\u{6837}\u{8F93}\u{51FA}\u{5373}\u{53EF}
7958
+ 7) \u{4E0D}\u{8981}\u{7FFB}\u{8BD1}\u{6216}\u{6539}\u{5199}
7959
+ `;
7960
+ if (segmentIndex && totalSegments) prompt = `\u{7B2C} ${segmentIndex}/${totalSegments} \u{90E8}\u{5206}
7450
7961
 
7451
- \u{5404}\u{533A}\u{57DF}\u{8BC6}\u{522B}\u{7ED3}\u{679C}\u{FF1A}
7452
- ${chunkedResultsText}`;
7453
- const mergedResult = await openAIService.generateText({
7454
- prompt: mergePrompt,
7455
- system_prompt: "\u4F60\u662F\u4E00\u4E2A\u5185\u5BB9\u6574\u5408\u4E13\u5BB6\uFF0C\u64C5\u957F\u5C06\u591A\u4E2A\u7247\u6BB5\u7684\u63CF\u8FF0\u6574\u5408\u4E3A\u5B8C\u6574\u3001\u8FDE\u8D2F\u7684\u6587\u672C\u3002\u4F7F\u7528\u4E2D\u6587\u56DE\u7B54\u3002",
7456
- temperature: 0.3
7457
- });
7458
- return mergedResult.trim();
7459
- }
7460
- async getImageBasicInfo(imagePath) {
7461
- try {
7462
- const metadata = await external_sharp_default()(imagePath).metadata();
7463
- const stats = await promises_.stat(imagePath);
7464
- return {
7465
- path: imagePath,
7466
- format: metadata.format || "unknown",
7467
- dimensions: {
7468
- width: metadata.width || 0,
7469
- height: metadata.height || 0
7470
- },
7471
- file_size: stats.size
7472
- };
7473
- } catch (error) {
7474
- throw new ImageAnalysisError(`\u{65E0}\u{6CD5}\u{8BFB}\u{53D6}\u{56FE}\u{7247}\u{4FE1}\u{606F}: ${imagePath}`, types_AnalysisErrorCodes.IMAGE_CORRUPTED, {
7475
- imagePath,
7476
- originalError: error
7477
- });
7478
- }
7479
- }
7480
- async validateParams(imagePath) {
7481
- try {
7482
- await promises_.access(imagePath);
7483
- } catch {
7484
- throw new ImageAnalysisError(`\u{56FE}\u{7247}\u{6587}\u{4EF6}\u{4E0D}\u{5B58}\u{5728}: ${imagePath}`, types_AnalysisErrorCodes.FILE_NOT_FOUND, {
7485
- imagePath: imagePath
7486
- });
7487
- }
7488
- const ext = external_path_.extname(imagePath).slice(1).toLowerCase();
7489
- if (!SUPPORTED_IMAGE_FORMATS.includes(ext)) throw new ImageAnalysisError(`\u{4E0D}\u{652F}\u{6301}\u{7684}\u{56FE}\u{7247}\u{683C}\u{5F0F}: ${ext}`, types_AnalysisErrorCodes.UNSUPPORTED_FORMAT, {
7490
- format: ext,
7491
- supportedFormats: SUPPORTED_IMAGE_FORMATS
7492
- });
7962
+ ${prompt}`;
7963
+ if (context) prompt += `
7964
+ \u{4E0A}\u{4E0B}\u{6587}\u{63D0}\u{793A}\u{FF08}\u{4EC5}\u{4F9B}\u{4F60}\u{7406}\u{89E3}\u{FF0C}\u{4E0D}\u{5F97}\u{5199}\u{5165}\u{8F93}\u{51FA}\u{FF09}\u{FF1A}${context}`;
7965
+ return prompt;
7493
7966
  }
7494
7967
  }
7495
7968
  const ImageAnalysisParamsSchema = objectType({
@@ -12298,7 +12771,8 @@ ${failedProjects.map((p)=>`- ${p.projectName}: ${p.errorMessage}`).join("\n")}
12298
12771
  usersFile;
12299
12772
  constructor(){
12300
12773
  try {
12301
- const storageDir = (0, utils_config.WR)();
12774
+ const homeDir = process.env.HOME || process.env.USERPROFILE || "/tmp";
12775
+ const storageDir = external_path_.join(homeDir, ".aico");
12302
12776
  this.dataDir = external_path_.join(storageDir, "lark");
12303
12777
  this.usersFile = external_path_.join(this.dataDir, "users.json");
12304
12778
  this.ensureDataDir();
@@ -12526,12 +13000,16 @@ ${failedProjects.map((p)=>`- ${p.projectName}: ${p.errorMessage}`).join("\n")}
12526
13000
  });
12527
13001
  const createDocTool = {
12528
13002
  name: "lark_doc_create",
12529
- description: "[\u521B\u5EFA\u65B0\u6587\u6863] \u521B\u5EFA\u6606\u4ED1\u667A\u8054\u4E91\u6587\u6863\u5E76\u5199\u5165\u5185\u5BB9\u3002\u4F7F\u7528\u573A\u666F: \u7528\u6237\u8981\u6C42\u521B\u5EFA/\u65B0\u5EFA/\u7F16\u5199/\u751F\u6210\u4E00\u4E2A\u65B0\u7684\u6587\u6863\u4E14\u6CA1\u6709\u63D0\u4F9B\u5DF2\u6709\u6587\u6863ID\u6216\u94FE\u63A5\u65F6\u4F7F\u7528\u3002\u5982\u679C\u7528\u6237\u63D0\u4F9B\u4E86\u6587\u6863ID\u6216\u94FE\u63A5\u8981\u6C42\u66F4\u65B0\u5185\u5BB9,\u8BF7\u4F7F\u7528lark_doc_append\u3002\u5FC5\u987B\u63D0\u4F9Bemail\u53C2\u6570",
13003
+ description: `\u{3010}\u{521B}\u{5EFA}\u{4E91}\u{6587}\u{6863}\u{9996}\u{9009}\u{3011}\u{521B}\u{5EFA}\u{6606}\u{4ED1}\u{667A}\u{8054}\u{4E91}\u{6587}\u{6863}\u{5E76}\u{5199}\u{5165}\u{5185}\u{5BB9}\u{3002}
13004
+ \u{4F7F}\u{7528}\u{573A}\u{666F}: \u{7528}\u{6237}\u{8BF4}"\u{5E2E}\u{6211}\u{5199}\u{4E00}\u{4E2A}XXX\u{6587}\u{6863}/\u{62A5}\u{544A}/\u{8BF4}\u{660E}/\u{65B9}\u{6848}"\u{65F6}\u{4F7F}\u{7528}\u{6B64}\u{5DE5}\u{5177}\u{3002}
13005
+ \u{793A}\u{4F8B}: "\u{5199}\u{4E00}\u{4E2A}\u{4F1A}\u{8BAE}\u{7EAA}\u{8981}" \u{2192} title="\u{4F1A}\u{8BAE}\u{7EAA}\u{8981}", blocks=[{type:"h1",content:"\u{4F1A}\u{8BAE}\u{4E3B}\u{9898}"},{type:"text",content:"\u{5185}\u{5BB9}..."}]
13006
+ \u{5757}\u{7C7B}\u{578B}: text=\u{6587}\u{672C}, h1-h6=\u{6807}\u{9898}, bullet=\u{65E0}\u{5E8F}\u{5217}\u{8868}, ordered=\u{6709}\u{5E8F}\u{5217}\u{8868}, code=\u{4EE3}\u{7801}, quote=\u{5F15}\u{7528}, todo=\u{5F85}\u{529E}, callout=\u{9AD8}\u{4EAE}, divider=\u{5206}\u{5272}\u{7EBF}
13007
+ \u{26A0}\u{FE0F} \u{5FC5}\u{987B}\u{63D0}\u{4F9B}email\u{53C2}\u{6570}\u{FF0C}\u{8BF7}\u{5148}\u{8BE2}\u{95EE}\u{7528}\u{6237}\u{90AE}\u{7BB1}\u{FF01}\u{6210}\u{529F}\u{540E}\u{4EC5}\u{8FD4}\u{56DE}\u{6587}\u{6863}\u{94FE}\u{63A5}\u{3002}`,
12530
13008
  inputSchema: {
12531
- title: stringType().describe("\u6587\u6863\u6807\u9898"),
12532
- blocks: arrayType(blockSchema).optional().describe("\u6587\u6863\u5185\u5BB9\u5757\u6570\u7EC4,\u6309\u987A\u5E8F\u5199\u5165\u6587\u6863"),
12533
- folder: stringType().optional().describe("\u6587\u4EF6\u5939token"),
12534
- email: stringType().describe("\u6240\u6709\u8005\u90AE\u7BB1(\u5FC5\u586B)")
13009
+ title: stringType().describe("\u6587\u6863\u6807\u9898(\u5982: \u4F1A\u8BAE\u7EAA\u8981, \u9879\u76EE\u65B9\u6848)"),
13010
+ blocks: arrayType(blockSchema).optional().describe("\u6587\u6863\u5185\u5BB9\u5757\u6570\u7EC4\u3002\u793A\u4F8B: [{type:'h1',content:'\u6807\u9898'},{type:'text',content:'\u5185\u5BB9'}]"),
13011
+ folder: stringType().optional().describe("\u6587\u4EF6\u5939token(\u53EF\u9009)"),
13012
+ email: stringType().describe("\u6240\u6709\u8005\u90AE\u7BB1\u3010\u5FC5\u586B\u3011- \u8BF7\u5148\u8BE2\u95EE\u7528\u6237\u90AE\u7BB1\u5730\u5740")
12535
13013
  },
12536
13014
  handler: async (args)=>{
12537
13015
  const client = getLarkClient();
@@ -12569,12 +13047,14 @@ ${failedProjects.map((p)=>`- ${p.projectName}: ${p.errorMessage}`).join("\n")}
12569
13047
  };
12570
13048
  const importMarkdownTool = {
12571
13049
  name: "lark_doc_import_md",
12572
- description: "\u5C06Markdown\u5185\u5BB9\u5BFC\u5165\u4E3A\u6606\u4ED1\u667A\u8054\u4E91\u6587\u6863,\u8FD4\u56DE\u6587\u6863\u94FE\u63A5\u3002\u5FC5\u987B\u63D0\u4F9Bemail\u53C2\u6570",
13050
+ description: `\u{5C06}Markdown\u{5185}\u{5BB9}\u{5BFC}\u{5165}\u{4E3A}\u{6606}\u{4ED1}\u{667A}\u{8054}\u{4E91}\u{6587}\u{6863}\u{3002}
13051
+ \u{4F7F}\u{7528}\u{573A}\u{666F}: \u{7528}\u{6237}\u{63D0}\u{4F9B}\u{4E86}Markdown\u{683C}\u{5F0F}\u{5185}\u{5BB9},\u{8981}\u{6C42}\u{8F6C}\u{4E3A}\u{4E91}\u{6587}\u{6863}\u{3002}
13052
+ \u{26A0}\u{FE0F} \u{5FC5}\u{987B}\u{63D0}\u{4F9B}email\u{53C2}\u{6570}\u{FF01}`,
12573
13053
  inputSchema: {
12574
13054
  md: stringType().describe("Markdown\u5185\u5BB9"),
12575
13055
  title: stringType().optional().describe("\u6587\u6863\u6807\u9898"),
12576
- folder: stringType().optional().describe("\u6587\u4EF6\u5939token"),
12577
- email: stringType().describe("\u6240\u6709\u8005\u90AE\u7BB1(\u5FC5\u586B)")
13056
+ folder: stringType().optional().describe("\u6587\u4EF6\u5939token(\u53EF\u9009)"),
13057
+ email: stringType().describe("\u6240\u6709\u8005\u90AE\u7BB1\u3010\u5FC5\u586B\u3011")
12578
13058
  },
12579
13059
  handler: async (args)=>{
12580
13060
  const client = getLarkClient();
@@ -12624,9 +13104,10 @@ ${failedProjects.map((p)=>`- ${p.projectName}: ${p.errorMessage}`).join("\n")}
12624
13104
  };
12625
13105
  const getDocContentTool = {
12626
13106
  name: "lark_doc_content",
12627
- description: "\u83B7\u53D6\u4E91\u6587\u6863\u7684\u7EAF\u6587\u672C\u5185\u5BB9",
13107
+ description: `\u{83B7}\u{53D6}\u{4E91}\u{6587}\u{6863}\u{7684}\u{7EAF}\u{6587}\u{672C}\u{5185}\u{5BB9}\u{3002}
13108
+ \u{4F7F}\u{7528}\u{573A}\u{666F}: \u{9700}\u{8981}\u{8BFB}\u{53D6}\u{67D0}\u{4E2A}\u{6587}\u{6863}\u{5185}\u{5BB9}\u{65F6}\u{4F7F}\u{7528}\u{3002}`,
12628
13109
  inputSchema: {
12629
- id: stringType().describe("\u6587\u6863ID")
13110
+ id: stringType().describe("\u6587\u6863ID(\u4ECE\u94FE\u63A5\u4E2D\u63D0\u53D6,\u5982https://xxx/docx/ABC123\u5219ID\u4E3AABC123)")
12630
13111
  },
12631
13112
  handler: async (args)=>{
12632
13113
  const client = getLarkClient();
@@ -12643,7 +13124,8 @@ ${failedProjects.map((p)=>`- ${p.projectName}: ${p.errorMessage}`).join("\n")}
12643
13124
  };
12644
13125
  const searchDocsTool = {
12645
13126
  name: "lark_doc_search",
12646
- description: "\u641C\u7D22\u6606\u4ED1\u667A\u8054\u4E91\u6587\u6863",
13127
+ description: `\u{641C}\u{7D22}\u{6606}\u{4ED1}\u{667A}\u{8054}\u{4E91}\u{6587}\u{6863}\u{3002}
13128
+ \u{4F7F}\u{7528}\u{573A}\u{666F}: \u{7528}\u{6237}\u{8981}\u{6C42}\u{67E5}\u{627E}/\u{641C}\u{7D22}\u{67D0}\u{4E2A}\u{6587}\u{6863}\u{65F6}\u{4F7F}\u{7528}\u{3002}`,
12647
13129
  inputSchema: {
12648
13130
  q: stringType().describe("\u641C\u7D22\u5173\u952E\u8BCD"),
12649
13131
  types: arrayType(enumType([
@@ -12651,8 +13133,8 @@ ${failedProjects.map((p)=>`- ${p.projectName}: ${p.errorMessage}`).join("\n")}
12651
13133
  "sheet",
12652
13134
  "bitable",
12653
13135
  "docx"
12654
- ])).optional().describe("\u6587\u6863\u7C7B\u578B"),
12655
- limit: numberType().optional().describe("\u8FD4\u56DE\u6570\u91CF,\u9ED8\u8BA420")
13136
+ ])).optional().describe("\u6587\u6863\u7C7B\u578B: doc=\u65E7\u7248\u6587\u6863, docx=\u65B0\u7248\u6587\u6863, sheet=\u8868\u683C, bitable=\u591A\u7EF4\u8868\u683C"),
13137
+ limit: numberType().optional().describe("\u8FD4\u56DE\u6570\u91CF(\u9ED8\u8BA420)")
12656
13138
  },
12657
13139
  handler: async (args)=>{
12658
13140
  const client = getLarkClient();
@@ -12680,10 +13162,12 @@ ${failedProjects.map((p)=>`- ${p.projectName}: ${p.errorMessage}`).join("\n")}
12680
13162
  };
12681
13163
  const appendDocTool = {
12682
13164
  name: "lark_doc_append",
12683
- description: "[\u66F4\u65B0\u5DF2\u6709\u6587\u6863] \u5411\u5DF2\u6709\u4E91\u6587\u6863\u8FFD\u52A0\u5185\u5BB9\u3002\u4F7F\u7528\u573A\u666F: \u7528\u6237\u63D0\u4F9B\u4E86\u6587\u6863ID\u6216\u6587\u6863\u94FE\u63A5,\u8981\u6C42\u66F4\u65B0/\u4FEE\u6539/\u8FFD\u52A0/\u8865\u5145\u5185\u5BB9\u65F6\u4F7F\u7528\u3002\u5982\u679C\u7528\u6237\u8981\u6C42\u521B\u5EFA\u65B0\u6587\u6863,\u8BF7\u4F7F\u7528lark_doc_create",
13165
+ description: `\u{5411}\u{5DF2}\u{6709}\u{4E91}\u{6587}\u{6863}\u{8FFD}\u{52A0}\u{5185}\u{5BB9}\u{3002}
13166
+ \u{4F7F}\u{7528}\u{573A}\u{666F}: \u{7528}\u{6237}\u{63D0}\u{4F9B}\u{4E86}\u{6587}\u{6863}ID\u{6216}\u{94FE}\u{63A5},\u{8981}\u{6C42}\u{66F4}\u{65B0}/\u{8FFD}\u{52A0}\u{5185}\u{5BB9}\u{65F6}\u{4F7F}\u{7528}\u{3002}
13167
+ \u{6CE8}\u{610F}: \u{5982}\u{679C}\u{7528}\u{6237}\u{8981}\u{6C42}\u{521B}\u{5EFA}\u{65B0}\u{6587}\u{6863},\u{8BF7}\u{4F7F}\u{7528}lark_doc_create\u{3002}`,
12684
13168
  inputSchema: {
12685
- doc: stringType().describe("\u6587\u6863ID(\u4ECE\u6587\u6863\u94FE\u63A5\u4E2D\u63D0\u53D6,\u5982\u94FE\u63A5\u4E3Ahttps://xxx/docx/ABC123\u5219ID\u4E3AABC123)"),
12686
- blocks: arrayType(blockSchema).describe("\u8981\u8FFD\u52A0\u7684\u5185\u5BB9\u5757\u6570\u7EC4")
13169
+ doc: stringType().describe("\u6587\u6863ID(\u4ECE\u94FE\u63A5\u4E2D\u63D0\u53D6,\u5982https://xxx/docx/ABC123\u5219ID\u4E3AABC123)"),
13170
+ blocks: arrayType(blockSchema).describe("\u8981\u8FFD\u52A0\u7684\u5185\u5BB9\u5757\u6570\u7EC4\u3002\u793A\u4F8B: [{type:'text',content:'\u65B0\u5185\u5BB9'}]")
12687
13171
  },
12688
13172
  handler: async (args)=>{
12689
13173
  const client = getLarkClient();
@@ -12728,13 +13212,87 @@ ${failedProjects.map((p)=>`- ${p.projectName}: ${p.errorMessage}`).join("\n")}
12728
13212
  if (email) return email;
12729
13213
  return await larkDbOperations.getDefaultEmail();
12730
13214
  }
13215
+ const bitable_tools_fieldSchema = objectType({
13216
+ name: stringType().describe("\u5B57\u6BB5\u540D\u79F0"),
13217
+ type: numberType().describe("\u5B57\u6BB5\u7C7B\u578B: 1=\u6587\u672C, 2=\u6570\u5B57, 3=\u5355\u9009, 4=\u591A\u9009, 5=\u65E5\u671F, 7=\u590D\u9009\u6846, 11=\u4EBA\u5458, 15=\u94FE\u63A5"),
13218
+ options: arrayType(stringType()).optional().describe("\u9009\u9879\u503C(\u4EC5\u5355\u9009/\u591A\u9009\u7C7B\u578B\u9700\u8981)")
13219
+ });
13220
+ const createCompleteBitableTool = {
13221
+ name: "lark_bitable_create_complete",
13222
+ description: `\u{3010}\u{521B}\u{5EFA}\u{591A}\u{7EF4}\u{8868}\u{683C}\u{9996}\u{9009}\u{3011}\u{4E00}\u{6B65}\u{5B8C}\u{6210}\u{521B}\u{5EFA}\u{591A}\u{7EF4}\u{8868}\u{683C}\u{3001}\u{6570}\u{636E}\u{8868}\u{3001}\u{5B57}\u{6BB5}\u{5B9A}\u{4E49}\u{3002}
13223
+ \u{4F7F}\u{7528}\u{573A}\u{666F}: \u{7528}\u{6237}\u{8BF4}"\u{5E2E}\u{6211}\u{521B}\u{5EFA}\u{4E00}\u{4E2A}\u{7EDF}\u{8BA1}XXX\u{7684}\u{591A}\u{7EF4}\u{8868}\u{683C}/\u{8868}\u{683C}"\u{65F6}\u{4F7F}\u{7528}\u{6B64}\u{5DE5}\u{5177}\u{3002}
13224
+ \u{793A}\u{4F8B}: "\u{521B}\u{5EFA}\u{4E00}\u{4E2A}\u{5458}\u{5DE5}\u{624B}\u{673A}\u{53F7}\u{7EDF}\u{8BA1}\u{8868}\u{683C}" \u{2192} name="\u{5458}\u{5DE5}\u{624B}\u{673A}\u{53F7}\u{7EDF}\u{8BA1}", tableName="\u{5458}\u{5DE5}\u{4FE1}\u{606F}", fields=[{name:"\u{59D3}\u{540D}",type:1},{name:"\u{90E8}\u{95E8}",type:1},{name:"\u{624B}\u{673A}\u{53F7}",type:1}]
13225
+ \u{5B57}\u{6BB5}\u{7C7B}\u{578B}: 1=\u{6587}\u{672C}, 2=\u{6570}\u{5B57}, 3=\u{5355}\u{9009}, 4=\u{591A}\u{9009}, 5=\u{65E5}\u{671F}, 7=\u{590D}\u{9009}\u{6846}, 11=\u{4EBA}\u{5458}, 15=\u{94FE}\u{63A5}
13226
+ \u{26A0}\u{FE0F} \u{5FC5}\u{987B}\u{63D0}\u{4F9B}email\u{53C2}\u{6570}\u{FF0C}\u{8BF7}\u{5148}\u{8BE2}\u{95EE}\u{7528}\u{6237}\u{90AE}\u{7BB1}\u{FF01}\u{6210}\u{529F}\u{540E}\u{4EC5}\u{8FD4}\u{56DE}\u{8868}\u{683C}\u{94FE}\u{63A5}\u{3002}`,
13227
+ inputSchema: {
13228
+ name: stringType().describe("\u591A\u7EF4\u8868\u683C\u540D\u79F0(\u5982: \u5458\u5DE5\u4FE1\u606F\u7EDF\u8BA1)"),
13229
+ tableName: stringType().describe("\u6570\u636E\u8868\u540D\u79F0(\u5982: \u5458\u5DE5\u5217\u8868)"),
13230
+ fields: arrayType(bitable_tools_fieldSchema).describe("\u5B57\u6BB5\u5B9A\u4E49\u6570\u7EC4\u3002\u793A\u4F8B: [{name:'\u59D3\u540D',type:1},{name:'\u5E74\u9F84',type:2}]"),
13231
+ records: arrayType(recordType(anyType())).optional().describe("\u521D\u59CB\u6570\u636E(\u53EF\u9009),\u5B57\u6BB5\u540D\u4E3Akey\u3002\u793A\u4F8B: [{\u59D3\u540D:'\u5F20\u4E09',\u5E74\u9F84:25}]"),
13232
+ folder: stringType().optional().describe("\u6587\u4EF6\u5939token(\u53EF\u9009)"),
13233
+ email: stringType().describe("\u6240\u6709\u8005\u90AE\u7BB1\u3010\u5FC5\u586B\u3011- \u8BF7\u5148\u8BE2\u95EE\u7528\u6237\u90AE\u7BB1\u5730\u5740")
13234
+ },
13235
+ handler: async (args)=>{
13236
+ const client = getLarkClient();
13237
+ try {
13238
+ const email = await bitable_tools_getEmail(args.email);
13239
+ if (!email) return bitable_tools_formatResponse(false, null, "\u8BF7\u63D0\u4F9B\u90AE\u7BB1(email)\u53C2\u6570,\u7528\u4E8E\u8BBE\u7F6E\u8868\u683C\u6240\u6709\u8005\u3002\u8BF7\u8BE2\u95EE\u7528\u6237\u7684\u90AE\u7BB1\u5730\u5740");
13240
+ const createRes = await client.post("/open-apis/bitable/v1/apps", {
13241
+ name: args.name,
13242
+ folder_token: args.folder
13243
+ });
13244
+ if (0 !== createRes.code) throw new Error(createRes.msg);
13245
+ const appToken = createRes.data?.app?.app_token;
13246
+ if (!appToken) throw new Error("\u521B\u5EFA\u8868\u683C\u5931\u8D25,\u672A\u83B7\u53D6\u5230token");
13247
+ const url = createRes.data?.app?.url || client.buildDocUrl(appToken, "bitable");
13248
+ const fields = args.fields.map((f)=>{
13249
+ const field = {
13250
+ field_name: f.name,
13251
+ type: f.type
13252
+ };
13253
+ if ((3 === f.type || 4 === f.type) && f.options?.length) field.property = {
13254
+ options: f.options.map((opt)=>({
13255
+ name: opt
13256
+ }))
13257
+ };
13258
+ return field;
13259
+ });
13260
+ const tableRes = await client.post(`/open-apis/bitable/v1/apps/${appToken}/tables`, {
13261
+ table: {
13262
+ name: args.tableName,
13263
+ fields
13264
+ }
13265
+ });
13266
+ if (0 !== tableRes.code) throw new Error(tableRes.msg);
13267
+ const tableId = tableRes.data?.table_id;
13268
+ if (args.records && args.records.length > 0 && tableId) {
13269
+ const records = args.records.map((r)=>({
13270
+ fields: r
13271
+ }));
13272
+ await client.post(`/open-apis/bitable/v1/apps/${appToken}/tables/${tableId}/records/batch_create`, {
13273
+ records
13274
+ });
13275
+ }
13276
+ const ok = await client.transferOwnerByEmail(appToken, "bitable", email);
13277
+ if (ok) await larkDbOperations.saveUser({
13278
+ email
13279
+ });
13280
+ return bitable_tools_formatResponse(true, {
13281
+ url
13282
+ });
13283
+ } catch (error) {
13284
+ return bitable_tools_formatResponse(false, null, error.message);
13285
+ }
13286
+ }
13287
+ };
12731
13288
  const createBitableTool = {
12732
13289
  name: "lark_bitable_create",
12733
- description: "[\u521B\u5EFA\u65B0\u8868\u683C] \u521B\u5EFA\u6606\u4ED1\u667A\u8054\u591A\u7EF4\u8868\u683C,\u8FD4\u56DE\u8868\u683C\u94FE\u63A5\u3002\u4F7F\u7528\u573A\u666F: \u7528\u6237\u8981\u6C42\u521B\u5EFA/\u65B0\u5EFA\u4E00\u4E2A\u65B0\u7684\u591A\u7EF4\u8868\u683C\u4E14\u6CA1\u6709\u63D0\u4F9B\u5DF2\u6709\u8868\u683CID\u6216\u94FE\u63A5\u65F6\u4F7F\u7528\u3002\u5982\u679C\u7528\u6237\u63D0\u4F9B\u4E86\u8868\u683CID\u6216\u94FE\u63A5\u8981\u6C42\u6DFB\u52A0\u6570\u636E,\u8BF7\u4F7F\u7528lark_bitable_add_record\u6216lark_bitable_batch_records\u3002\u5FC5\u987B\u63D0\u4F9Bemail\u53C2\u6570",
13290
+ description: `\u{521B}\u{5EFA}\u{7A7A}\u{767D}\u{591A}\u{7EF4}\u{8868}\u{683C}\u{3002}\u{5982}\u{9700}\u{540C}\u{65F6}\u{521B}\u{5EFA}\u{5B57}\u{6BB5},\u{63A8}\u{8350}\u{4F7F}\u{7528}lark_bitable_create_complete\u{3002}
13291
+ \u{26A0}\u{FE0F} \u{5FC5}\u{987B}\u{63D0}\u{4F9B}email\u{53C2}\u{6570}\u{FF01}`,
12734
13292
  inputSchema: {
12735
13293
  name: stringType().describe("\u8868\u683C\u540D\u79F0"),
12736
13294
  folder: stringType().optional().describe("\u6587\u4EF6\u5939token"),
12737
- email: stringType().describe("\u6240\u6709\u8005\u90AE\u7BB1(\u5FC5\u586B)")
13295
+ email: stringType().describe("\u6240\u6709\u8005\u90AE\u7BB1\u3010\u5FC5\u586B\u3011")
12738
13296
  },
12739
13297
  handler: async (args)=>{
12740
13298
  const client = getLarkClient();
@@ -13003,6 +13561,7 @@ ${failedProjects.map((p)=>`- ${p.projectName}: ${p.errorMessage}`).join("\n")}
13003
13561
  }
13004
13562
  };
13005
13563
  const bitableTools = [
13564
+ createCompleteBitableTool,
13006
13565
  createBitableTool,
13007
13566
  createTableTool,
13008
13567
  listTablesTool,