- 点击可信验证增加两类生效旁证: 页面跳转/新开标签页(淘宝搜索按钮), 点击后元素整体消失(关闭登录弹窗); 此前均被误报为"目标未收到可信点击" 并在节点超时内反复重试, 造成"点击生效却等很久还报错" - 相似元素列表引用增加 index 序号: 动态id泛化后各卡片选择器相同, 46 条引用全部命中第一张卡导致抓取结果全重复; 修复 NodeList 无 indexOf 的 TypeError 被静默吞掉导致序号从未写入 - 元素定位改为两段式: 先在当前附着页查找, 找不到才跟随前台标签页, 避免多标签环境下被无条件切到 pages[0] 导致找错页面 - 新开标签页优先复用启动残留的 about:blank 空白页, 不再堆积空标签 - AI 能力输入识别增加 hint_word 字段(此前提示词读到的是空) - try_catch 捕获子步骤失败时记录 warn 日志, 不再静默 - Excel 落盘遇 EBUSY(文件被打开占用)时自动另存为带时间戳的文件 - 新增 similar-list.test.ts 端到端回归(46 卡片动态 id 真实浏览器验证) - 新增 export-last-run.js: 从运行记录导出比价 Excel
56 lines
3.6 KiB
TypeScript
56 lines
3.6 KiB
TypeScript
import { register } from "@rpa/core";
|
||
import { RuntimeError } from "@rpa/core";
|
||
import { chatCompletion, requireAiConfig } from "@rpa/core";
|
||
|
||
function inputText(args: Record<string, unknown>, nodeId: string): string {
|
||
for (const key of ["input", "hint_word", "text", "content", "sentence", "prompt", "sourceFilePath", "filePath", "source", "document"]) {
|
||
const v = String(args[key] ?? "").trim();
|
||
if (v) return v;
|
||
}
|
||
throw new RuntimeError("validation_error", "输入文本为空", { nodeId, componentId: nodeId });
|
||
}
|
||
|
||
async function readMaybeFile(value: string): Promise<string> {
|
||
const looksLikeFile = /\.(txt|md|csv|json|log)$/i.test(value) && value.length < 260 && !value.includes("\n");
|
||
if (!looksLikeFile) return value;
|
||
try {
|
||
const fs = await import("node:fs/promises");
|
||
const stat = await fs.stat(value);
|
||
if (stat.isFile()) return await fs.readFile(value, "utf8");
|
||
} catch { /* treat the value as literal text */ }
|
||
return value;
|
||
}
|
||
|
||
async function complete(prompt: string, input: string, temperature = 0.3): Promise<string> {
|
||
requireAiConfig();
|
||
return chatCompletion([
|
||
{ role: "system", content: prompt },
|
||
{ role: "user", content: input }
|
||
], { temperature });
|
||
}
|
||
|
||
const TEXT_TASKS: Array<{ ids: string[]; system: string; task: string }> = [
|
||
{ ids: ["DataService_AIGenTxt"], system: "你是写作助手,根据用户要求生成高质量中文内容。", task: "AI 生成文本" },
|
||
{ ids: ["DataService_LargeModel", "DataService_ZBrain", "DataService_AgentCall", "NLP_XunFei_NLPBaseServer"], system: "你是智能助手,尽力完成用户的任务。", task: "通用模型调用" },
|
||
{ ids: ["DataService_ChatBot"], system: "你是对话机器人,用中文自然对话。", task: "对话机器人" },
|
||
{ ids: ["DataService_KeyWord", "NLP_KeyWordsAnalysis", "NLP_SplitText"], system: "从文本中提取关键词,输出 JSON 数组(字符串列表),不要输出其他内容。", task: "关键词抽取" },
|
||
{ ids: ["DataService_Correct"], system: "修正文本中的错别字与语病,直接输出修正后的全文。", task: "文本纠错" },
|
||
{ ids: ["DataService_Review"], system: '审核文本内容是否合规,输出 JSON:{\"pass\":true/false,\"reason\":\"原因\"}。', task: "文本审核" },
|
||
{ ids: ["DataService_TextComparison", "Scenario_TextComparison"], system: "比较两段文本差异,输出简明差异摘要。", task: "文档比对" },
|
||
{ ids: ["NLP_SplitWords"], system: '对文本分词,输出 JSON 数组(字符串列表)。', task: "分词" },
|
||
{ ids: ["NLP_EmotionalAnalysis"], system: '分析文本情感倾向,输出 JSON:{\"label\":\"正面/负面/中性\",\"score\":0.99}。', task: "情感分析" },
|
||
{ ids: ["NLP_SemanticSimilarity"], system: '判断两段文本语义相似度,输出 JSON:{\"score\":0.99}(0-1)。输入格式:文本1\n---\n文本2。', task: "语义相似度" },
|
||
{ ids: ["NLP_PerspectiveAnalysis"], system: '分析文本中的观点与立场,输出 JSON:{\"perspectives\":[{\"view\":\"...\",\"stance\":\"支持/反对/中立\"}]}。', task: "观点分析" },
|
||
{ ids: ["NLP_AnalyseProductReview", "NLP_BatchAnalyseProductReview"], system: '分析商品评论,输出 JSON:{\"summary\":\"...\",\"sentiment\":\"...\",\"issues\":[]}。', task: "商品评论分析" },
|
||
];
|
||
|
||
for (const task of TEXT_TASKS) {
|
||
register(task.ids, async (ctx, node, args) => {
|
||
const rawInput = inputText(args, node.id);
|
||
const input = await readMaybeFile(rawInput);
|
||
const result = await complete(task.system, input);
|
||
ctx.log(task.task + "完成", "info", node.id);
|
||
return result;
|
||
});
|
||
}
|