 | |  |  | 解析Kimi返回的拖动距离示例
- // AIWROK 自动化流程:截图B站验证码 → 启动Kimi助手 → 发送截图询问拖动距离 → 采集回答 → 切回B站拖动滑块
- // 包名:com.moonshot.kimichat(Kimi AI)
- //
- // 使用说明:
- // 1. 在B站验证码页面运行脚本
- // 2. 脚本自动截图并发送给Kimi识别
- // 3. 解析Kimi返回的拖动距离,切回B站拖动滑块
- // 4. Kimi使用WebView/Compose渲染,XML可能无可用节点,故采用OCR优先+坐标兜底策略
- print.log("===== KIMI识别验证码拖动B站流程启动 =====");
- print.time();
- // ========== 配置区 ==========
- var KIMI包名 = "com.moonshot.kimichat";
- var B站包名 = "tv.danmaku.bili";
- var 截图保存路径 = "/sdcard/验证码截图.png";
- var 等待回答超时秒 = 60;
- var 回答输出等待秒 = 60;
- var 滑块校准系数 = 1.0;
- var 提问话术 = "请帮我分析这张图片,告诉我左边的方块需要向右移动多少像素才能和右边的缺口对齐,只输出:距离加数字。";
- // ========== 获取设备信息 ==========
- var 屏幕宽 = screen.getScreenWidth();
- var 屏幕高 = screen.getScreenHeight();
- var 验证码滑块距离 = null;
- print.log("屏幕尺寸:" + 屏幕宽 + " x " + 屏幕高);
- try {
- var 代理状态 = agent.isOpen();
- print.log("代理状态:" + (代理状态 ? "已开启" : "未开启"));
- } catch (e) {
- print.log("代理状态检查失败:" + e.message);
- }
- // ========== 工具函数 ==========
- function 获取UI() {
- var xml = agent.getXml();
- return "" + xml;
- }
- function 字符串长度(s) {
- var str = "" + s;
- return str.length;
- }
- function 解码HTML实体(s) {
- var str = "" + s;
- str = str.replace(/
- /g, "\n");
- str = str.replace(/
- /g, "\r");
- str = str.replace(/ /g, "\t");
- str = str.replace(/'/g, "'");
- str = str.replace(/"/g, '"');
- str = str.replace(/"/g, '"');
- str = str.replace(/'/g, "'");
- str = str.replace(/&/g, "&");
- str = str.replace(/</g, "<");
- str = str.replace(/>/g, ">");
- return str;
- }
- function 获取当前最后AI回答(xml) {
- var 回答列表 = 采集AI回答列表(xml);
- if (回答列表.length === 0) return "";
-
- print.log("调试:回答列表共" + 回答列表.length + "条:" + 回答列表.join(", "));
-
- var 候选回答 = [];
- for (var i = 0; i < 回答列表.length; i++) {
- var 回答 = 回答列表[i];
- if (回答.indexOf("距离") !== -1 || 回答.indexOf("像素") !== -1) {
- 候选回答.push({ text: 回答, len: 回答.length });
- }
- }
-
- if (候选回答.length > 0) {
- 候选回答.sort(function(a, b) { return a.len - b.len; });
- print.log("✓ 找到包含距离信息的回答,选择最短的:'" + 候选回答[0].text + "'");
- return 候选回答[0].text;
- }
-
- for (var j = 0; j < 回答列表.length; j++) {
- var 回答2 = 回答列表[j];
- var 数字匹配 = 回答2.match(/\d+/g);
- if (数字匹配 && 数字匹配.length > 0) {
- var 数字 = parseInt(数字匹配[0]);
- if (数字 >= 10 && 数字 <= 500) {
- print.log("✓ 找到包含合理数字的回答:'" + 回答2 + "'");
- return 回答2;
- }
- }
- }
-
- return 回答列表[回答列表.length - 1];
- }
- function OCR识别屏幕区域(xml) {
- try {
- var img = screen.screenShotFull();
-
- var ocrres = img.MLKitOcr('zhs');
- var ocrText = "";
-
- if (ocrres && typeof ocrres.getAllString === 'function') {
- ocrText = "" + ocrres.getAllString();
- } else if (ocrres && typeof ocrres.getJsonString === 'function') {
- var jsonStr = "" + ocrres.getJsonString();
- var textPattern = /"text"\s*:\s*"([^"]+)"/g;
- var match;
- var allText = [];
- while ((match = textPattern.exec(jsonStr)) !== null) {
- if (match[1] && match[1].length > 0) {
- allText.push(match[1]);
- }
- }
- ocrText = allText.join("\n");
- } else {
- var str = "" + ocrres;
- var textPattern2 = /"text"\s*:\s*"([^"]+)"/g;
- var match2;
- var allText2 = [];
- while ((match2 = textPattern2.exec(str)) !== null) {
- if (match2[1] && match2[1].length > 0) {
- allText2.push(match2[1]);
- }
- }
- ocrText = allText2.join("\n");
- }
-
- img.recycle();
-
- if (ocrText && ocrText.length > 0) {
- print.log("✓ MLKitOcr识别成功");
- print.log("--- OCR结果开始 ---");
- print.log(ocrText);
- print.log("--- OCR结果结束 ---");
- return "" + ocrText;
- }
-
- print.log("⚠ MLKitOcr未识别到内容");
- return "";
- } catch (e) {
- print.log("⚠ OCR识别异常:" + e.message);
- return "";
- }
- }
- function 提取数字(文本) {
- var str = "" + 文本;
- var 精确匹配 = str.match(/距离加(\d+)/);
- if (精确匹配) {
- var num = parseInt(精确匹配[1]);
- if (num >= 30) {
- return "" + num;
- }
- }
- var 备选匹配 = str.match(/距离精[\u51c6\u79ef\u786e]加?(\d+)/);
- if (备选匹配) {
- var num2 = parseInt(备选匹配[1]);
- if (num2 >= 30) {
- return "" + num2;
- }
- }
- var 距离匹配 = str.match(/距离[\uFF0C,\s]*(\d+)/);
- if (距离匹配) {
- var num3 = parseInt(距离匹配[1]);
- if (num3 >= 30) {
- return "" + num3;
- }
- }
- var allMatches = str.match(/\d+/g);
- if (allMatches) {
- var 候选数字 = [];
- for (var i = 0; i < allMatches.length; i++) {
- var n = parseInt(allMatches[i]);
- if (n >= 30 && n < 1000) {
- 候选数字.push(n);
- }
- }
- if (候选数字.length > 0) {
- 候选数字.sort(function(a, b) { return b - a; });
- return "" + 候选数字[0];
- }
- var allNums = [];
- for (var j = 0; j < allMatches.length; j++) {
- allNums.push(parseInt(allMatches[j]));
- }
- allNums.sort(function(a, b) { return b - a; });
- return "" + allNums[0];
- }
- return "";
- }
- function 采集AI回答列表(xml) {
- var xmlStr = "" + xml;
- var 回答列表 = [];
- var textViewPattern = /<node[^>]*?text="([^"]+)"[^>]*?class="android\.widget\.TextView"[^>]*?\/?>/g;
- var tvMatch;
- while ((tvMatch = textViewPattern.exec(xmlStr)) !== null) {
- if (tvMatch[1] && 字符串长度(tvMatch[1]) > 1) {
- var 原始文本 = tvMatch[1];
- var 解码文本 = 解码HTML实体(原始文本);
-
- if (解码文本.includes("给Kimi发消息") ||
- 解码文本.includes("有问题尽管问我") ||
- 解码文本.includes("拍照解题") ||
- 解码文本.includes("深度研究") ||
- 解码文本.includes("OK Computer") ||
- 解码文本.includes("发送") ||
- 解码文本.includes("消息")) {
- continue;
- }
-
- if (!回答列表.includes(解码文本)) {
- 回答列表.push(解码文本);
- print.log("✓ 在TextView中找到文本: '" + 解码文本 + "'");
- }
- }
- }
- if (回答列表.length === 0) {
- print.log("⚠ 未找到AI回答节点");
- } else {
- print.log("✓ 采集到" + 回答列表.length + "条AI回答");
- }
- return 回答列表;
- }
- function 全屏截图(保存路径) {
- try {
- var result = agent.shell("screencap -p " + 保存路径);
- print.log("✓ 截图命令执行:" + result);
-
- var lsResult = agent.shell("ls -la " + 保存路径);
- print.log("✓ 截图文件检查:" + lsResult);
-
- return true;
- } catch (e) {
- print.log("⚠ 截图失败:" + e.message);
- return false;
- }
- }
- function 判断KIMI打开形式(xml) {
- var xmlStr = "" + xml;
-
- var inputKeywords = ["给Kimi发消息", "有问题尽管问我", "输入消息", "发消息"];
- var hasInput = false;
- for (var i = 0; i < inputKeywords.length; i++) {
- if (xmlStr.indexOf('text="' + inputKeywords[i] + '"') !== -1) {
- hasInput = true;
- break;
- }
- }
-
- var plusKeywords = ["加号", "附件", "图片", "相册"];
- var hasPlus = false;
- for (var j = 0; j < plusKeywords.length; j++) {
- if (xmlStr.indexOf('text="' + plusKeywords[j] + '"') !== -1 ||
- xmlStr.indexOf('content-desc="' + plusKeywords[j] + '"') !== -1) {
- hasPlus = true;
- break;
- }
- }
-
- if (hasInput || hasPlus) {
- print.log("✓ Kimi APP打开形式:对话页面");
- return "对话页";
- }
-
- print.log("⚠ Kimi APP打开形式:未知页面");
- return "未知";
- }
- function 开启新对话(xml) {
- var xmlStr = "" + xml;
-
- var newChatIdx = xmlStr.indexOf('content-desc="开启新会话"');
- if (newChatIdx !== -1) {
- var 段 = xmlStr.substring(newChatIdx);
- var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m) {
- var x = (parseInt(m[1]) + parseInt(m[3])) / 2;
- var y = (parseInt(m[2]) + parseInt(m[4])) / 2;
- agent.click(x, y);
- print.log("✓ 已点击开启新对话按钮,content-desc=开启新会话,坐标(" + Math.round(x) + "," + Math.round(y) + ")");
- sleep.second(秒 = 3);
- return true;
- }
- }
-
- var rightButtonPattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
- var rbMatch;
- var 右上角按钮 = [];
- while ((rbMatch = rightButtonPattern.exec(xmlStr)) !== null) {
- var bx1 = parseInt(rbMatch[1]);
- var by1 = parseInt(rbMatch[2]);
- if (bx1 > 屏幕宽 * 0.85 && by1 > 100 && by1 < 400) {
- 右上角按钮.push({ x: (bx1 + parseInt(rbMatch[3])) / 2, y: (by1 + parseInt(rbMatch[4])) / 2 });
- }
- }
-
- if (右上角按钮.length > 0) {
- 右上角按钮.sort(function(a, b) { return a.x - b.x; });
- var 最右边按钮 = 右上角按钮[右上角按钮.length - 1];
- agent.click(最右边按钮.x, 最右边按钮.y);
- print.log("✓ 已点击右上角按钮开启新对话,坐标(" + Math.round(最右边按钮.x) + "," + Math.round(最右边按钮.y) + ")");
- sleep.second(秒 = 3);
- return true;
- }
-
- print.log("⚠ 未找到开启新对话按钮,使用坐标兜底(右上角)");
- var 兜底X = 屏幕宽 * 0.96;
- var 兜底Y = 屏幕高 * 0.06;
- agent.click(兜底X, 兜底Y);
- print.log("✓ 已点击右上角兜底位置开启新对话,坐标(" + Math.round(兜底X) + "," + Math.round(兜底Y) + ")");
- sleep.second(秒 = 3);
- return true;
- }
- function 查找输入框中心(xml) {
- var xmlStr = "" + xml;
-
- var inputKeywords = ["有问题尽管问我...", "给Kimi发消息", "输入消息", "发消息", "接着问"];
- for (var i = 0; i < inputKeywords.length; i++) {
- var kw = inputKeywords[i];
- var inputIdx = xmlStr.indexOf('text="' + kw + '"');
- if (inputIdx !== -1) {
- var 段 = xmlStr.substring(inputIdx);
- var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m) {
- var x1 = parseInt(m[1]);
- var y1 = parseInt(m[2]);
- var x2 = parseInt(m[3]);
- var y2 = parseInt(m[4]);
- print.log("✓ 输入框定位:text=" + kw + ",bounds=[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "]");
- return {
- x: (x1 + x2) / 2,
- y: (y1 + y2) / 2
- };
- }
- }
- }
- var editTextIdx = xmlStr.indexOf('class="android.widget.EditText"');
- if (editTextIdx !== -1) {
- var 段2 = xmlStr.substring(editTextIdx);
- var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m2) {
- var x1 = parseInt(m2[1]);
- var y1 = parseInt(m2[2]);
- var x2 = parseInt(m2[3]);
- var y2 = parseInt(m2[4]);
- print.log("✓ 输入框定位(EditText):bounds=[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "]");
- return {
- x: (x1 + x2) / 2,
- y: (y1 + y2) / 2
- };
- }
- }
- var viewFactoryHolderIdx = xmlStr.indexOf('class="androidx.compose.ui.viewinterop.ViewFactoryHolder"');
- if (viewFactoryHolderIdx !== -1) {
- var 段3 = xmlStr.substring(viewFactoryHolderIdx);
- var m3 = 段3.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m3) {
- var x1 = parseInt(m3[1]);
- var y1 = parseInt(m3[2]);
- var x2 = parseInt(m3[3]);
- var y2 = parseInt(m3[4]);
- print.log("✓ 输入框定位(ViewFactoryHolder):bounds=[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "]");
- return {
- x: (x1 + x2) / 2,
- y: (y1 + y2) / 2
- };
- }
- }
- print.log("⚠ 未找到输入框,使用坐标兜底(屏幕下方区域)");
- return {
- x: 屏幕宽 * 0.35,
- y: 屏幕高 * 0.55
- };
- }
- function 查找加号按钮(xml) {
- var xmlStr = "" + xml;
-
- var plusDescIdx = xmlStr.indexOf('content-desc="更多输入方式"');
- if (plusDescIdx !== -1) {
- var 段 = xmlStr.substring(plusDescIdx);
- var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m) {
- var x1 = parseInt(m[1]);
- var y1 = parseInt(m[2]);
- var x2 = parseInt(m[3]);
- var y2 = parseInt(m[4]);
- var centerX = (x1 + x2) / 2;
- var centerY = (y1 + y2) / 2;
- print.log("✓ 加号按钮定位:content-desc=更多输入方式,坐标(" + Math.round(centerX) + "," + Math.round(centerY) + ")");
- return { x: centerX, y: centerY };
- }
- }
- var inputIdx = xmlStr.indexOf('text="有问题尽管问我..."');
- if (inputIdx === -1) {
- inputIdx = xmlStr.indexOf('text="给Kimi发消息"');
- }
- if (inputIdx === -1) {
- inputIdx = xmlStr.indexOf('text="有问题尽管问我"');
- }
-
- if (inputIdx !== -1) {
- var 输入框段 = xmlStr.substring(inputIdx);
- var 输入框边界 = 输入框段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (输入框边界) {
- var 输入框X2 = parseInt(输入框边界[3]);
- var 输入框Y = parseInt(输入框边界[2]);
- var 输入框底部Y = parseInt(输入框边界[4]);
- var 输入框中心Y = (输入框Y + 输入框底部Y) / 2;
-
- var clickablePattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
- var clickMatch;
- var 候选按钮 = [];
-
- while ((clickMatch = clickablePattern.exec(xmlStr)) !== null) {
- var bx1 = parseInt(clickMatch[1]);
- var by1 = parseInt(clickMatch[2]);
- var bx2 = parseInt(clickMatch[3]);
- var by2 = parseInt(clickMatch[4]);
-
- if (by1 >= 输入框中心Y - 100 && by2 <= 输入框中心Y + 200 && bx1 > 输入框X2 - 50) {
- 候选按钮.push({ x: (bx1 + bx2) / 2, y: (by1 + by2) / 2 });
- }
- }
-
- if (候选按钮.length > 0) {
- 候选按钮.sort(function(a, b) { return a.x - b.x; });
- print.log("✓ 加号按钮定位:输入框右侧clickable元素,坐标(" + Math.round(候选按钮[0].x) + "," + Math.round(候选按钮[0].y) + ")");
- return 候选按钮[0];
- }
- }
- }
- print.log("⚠ 加号按钮使用坐标兜底(输入框右侧)");
- var 输入框 = 查找输入框中心(xml);
- return {
- x: 屏幕宽 * 0.92,
- y: 输入框.y
- };
- }
- function 查找相册按钮(xml) {
- var xmlStr = "" + xml;
-
- var clickablePattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
- var clickMatch;
- var 候选按钮 = [];
-
- while ((clickMatch = clickablePattern.exec(xmlStr)) !== null) {
- var bx1 = parseInt(clickMatch[1]);
- var by1 = parseInt(clickMatch[2]);
- var bx2 = parseInt(clickMatch[3]);
- var by2 = parseInt(clickMatch[4]);
-
- var 节点段 = xmlStr.substring(xmlStr.indexOf(clickMatch[0]));
- var 节点结束 = 节点段.indexOf('</node>');
- if (节点结束 !== -1) {
- var 子节点内容 = 节点段.substring(0, 节点结束);
- if (子节点内容.indexOf('text="相册"') !== -1 ||
- 子节点内容.indexOf('content-desc="相册"') !== -1) {
- var centerX = (bx1 + bx2) / 2;
- var centerY = (by1 + by2) / 2;
- print.log("✓ 相册按钮定位:clickable父节点包含相册,bounds=[" + bx1 + "," + by1 + "][" + bx2 + "," + by2 + "],坐标(" + Math.round(centerX) + "," + Math.round(centerY) + ")");
- return { x: centerX, y: centerY };
- }
- }
- }
-
- var albumDescIdx = xmlStr.indexOf('content-desc="相册"');
- if (albumDescIdx !== -1) {
- var 段 = xmlStr.substring(albumDescIdx);
- var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m) {
- var x1 = parseInt(m[1]);
- var y1 = parseInt(m[2]);
- var x2 = parseInt(m[3]);
- var y2 = parseInt(m[4]);
- var centerX = (x1 + x2) / 2;
- var centerY = (y1 + y2) / 2;
- print.log("✓ 相册按钮定位:content-desc=相册,bounds=[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "],坐标(" + Math.round(centerX) + "," + Math.round(centerY) + ")");
- return { x: centerX, y: centerY };
- }
- }
-
- var albumKeywords = ["相册", "图片", "照片"];
- for (var i = 0; i < albumKeywords.length; i++) {
- var kw = albumKeywords[i];
- var albumIdx = xmlStr.indexOf('text="' + kw + '"');
- if (albumIdx !== -1) {
- var 段 = xmlStr.substring(albumIdx);
- var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m) {
- var x1 = parseInt(m[1]);
- var y1 = parseInt(m[2]);
- var x2 = parseInt(m[3]);
- var y2 = parseInt(m[4]);
- var centerX = (x1 + x2) / 2;
- var centerY = (y1 + y2) / 2;
- print.log("✓ 相册按钮定位:text=" + kw + ",bounds=[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "],坐标(" + Math.round(centerX) + "," + Math.round(centerY) + ")");
- return { x: centerX, y: centerY };
- }
- }
- }
- print.log("⚠ 相册按钮使用坐标兜底(底部中间)");
- return {
- x: 屏幕宽 * 0.5,
- y: 屏幕高 * 0.88
- };
- }
- function 查找相册选项(xml) {
- var xmlStr = "" + xml;
-
- var text关键词 = ["相册", "图片", "照片", "所有照片", "从相册选择", "选择图片"];
- for (var i = 0; i < text关键词.length; i++) {
- var kw = text关键词[i];
- var idx = xmlStr.indexOf('text="' + kw + '"');
- if (idx !== -1) {
- var 段 = xmlStr.substring(idx);
- var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m) {
- print.log("✓ 相册选项定位:text=" + kw);
- return {
- x: (parseInt(m[1]) + parseInt(m[3])) / 2,
- y: (parseInt(m[2]) + parseInt(m[4])) / 2
- };
- }
- }
- }
- var desc关键词 = ["相册", "图片", "照片"];
- for (var j = 0; j < desc关键词.length; j++) {
- var kw2 = desc关键词[j];
- var idx2 = xmlStr.indexOf('content-desc="' + kw2 + '"');
- if (idx2 !== -1) {
- var 段2 = xmlStr.substring(idx2);
- var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m2) {
- print.log("✓ 相册选项定位:content-desc=" + kw2);
- return {
- x: (parseInt(m2[1]) + parseInt(m2[3])) / 2,
- y: (parseInt(m2[2]) + parseInt(m2[4])) / 2
- };
- }
- }
- }
-
- return null;
- }
- function 粘贴文本(文本) {
- try {
- Clipboard.copy("" + 文本);
- } catch (e) {
- print.log("⚠ Clipboard.copy 失败:" + e.message);
- }
- sleep.millisecond(毫秒 = 300);
- try {
- agent.shell("service call clipboard 3 i32 1 s16 '" + 文本 + "' i32 0");
- } catch (e2) {
- // 忽略错误
- }
- sleep.millisecond(毫秒 = 300);
- agent.shell("input keyevent 279");
- sleep.millisecond(毫秒 = 500);
-
- try {
- agent.shell("input text '" + 文本 + "'");
- print.log("✓ 已通过input text直接输入文本");
- } catch (e3) {
- print.log("⚠ input text失败:" + e3.message);
- }
-
- sleep.second(秒 = 1);
- print.log("✓ 已粘贴文本:" + 文本);
- }
- function 是否在系统相册页面(xml) {
- var xmlStr = "" + xml;
-
- var packageMatch = xmlStr.match(/package="([^"]+)"/);
- var 当前包名 = packageMatch ? packageMatch[1] : "";
-
- if (当前包名 && 当前包名 !== KIMI包名) {
- print.log("✓ 检测到系统相册页面,包名:" + 当前包名);
- return true;
- }
-
- return false;
- }
- function 是否在图片预览页面(xml) {
- var xmlStr = "" + xml;
- if (xmlStr.indexOf('text="完成"') !== -1 || xmlStr.indexOf('text="发送"') !== -1) {
- return true;
- }
- if (xmlStr.indexOf('content-desc="完成"') !== -1 || xmlStr.indexOf('content-desc="发送"') !== -1) {
- return true;
- }
- return false;
- }
- function 查找图片预览确认按钮(xml) {
- var xmlStr = "" + xml;
-
- var 关键词 = ["完成", "发送", "确认"];
- for (var i = 0; i < 关键词.length; i++) {
- var kw = 关键词[i];
- var textIdx = xmlStr.indexOf('text="' + kw + '"');
- if (textIdx !== -1) {
- var 段 = xmlStr.substring(textIdx);
- var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m) {
- var x = (parseInt(m[1]) + parseInt(m[3])) / 2;
- var y = (parseInt(m[2]) + parseInt(m[4])) / 2;
- print.log("✓ 图片预览确认按钮定位:text=" + kw + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
- return { x: x, y: y };
- }
- }
- }
-
- for (var j = 0; j < 关键词.length; j++) {
- var kw2 = 关键词[j];
- var descIdx = xmlStr.indexOf('content-desc="' + kw2 + '"');
- if (descIdx !== -1) {
- var 段2 = xmlStr.substring(descIdx);
- var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m2) {
- var x = (parseInt(m2[1]) + parseInt(m2[3])) / 2;
- var y = (parseInt(m2[2]) + parseInt(m2[4])) / 2;
- print.log("✓ 图片预览确认按钮定位:content-desc=" + kw2 + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
- return { x: x, y: y };
- }
- }
- }
-
- print.log("⚠ 图片预览确认按钮使用坐标兜底(底部中间)");
- return { x: 屏幕宽 * 0.5, y: 屏幕高 * 0.92 };
- }
- function 查找相册选择按钮(xml) {
- var xmlStr = "" + xml;
-
- var 关键词列表 = ["选择", "完成", "确认", "发送", "确定"];
- for (var i = 0; i < 关键词列表.length; i++) {
- var kw = 关键词列表[i];
-
- var textPattern = new RegExp('text="' + kw + '[^"]*"[^>]*?bounds="\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]"', 'gi');
- var textMatch = textPattern.exec(xmlStr);
- if (textMatch) {
- var x = (parseInt(textMatch[1]) + parseInt(textMatch[3])) / 2;
- var y = (parseInt(textMatch[2]) + parseInt(textMatch[4])) / 2;
- print.log("✓ 相册选择按钮定位:text=" + kw + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
- return { x: x, y: y };
- }
-
- var descIdx = xmlStr.indexOf('content-desc="' + kw + '"');
- if (descIdx !== -1) {
- var 段2 = xmlStr.substring(descIdx);
- var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m2) {
- var x = (parseInt(m2[1]) + parseInt(m2[3])) / 2;
- var y = (parseInt(m2[2]) + parseInt(m2[4])) / 2;
- print.log("✓ 相册选择按钮定位:content-desc=" + kw + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
- return { x: x, y: y };
- }
- }
- }
-
- var bottomButtonPattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
- var bottomMatch;
- var 底部按钮列表 = [];
- while ((bottomMatch = bottomButtonPattern.exec(xmlStr)) !== null) {
- var bx1 = parseInt(bottomMatch[1]);
- var by1 = parseInt(bottomMatch[2]);
- var bx2 = parseInt(bottomMatch[3]);
- var by2 = parseInt(bottomMatch[4]);
- if (by1 >= 屏幕高 * 0.85) {
- 底部按钮列表.push({ x: (bx1 + bx2) / 2, y: (by1 + by2) / 2 });
- }
- }
-
- if (底部按钮列表.length > 0) {
- 底部按钮列表.sort(function(a, b) { return b.x - a.x; });
- var 最右边按钮 = 底部按钮列表[0];
- print.log("✓ 相册选择按钮定位:底部最右边按钮,坐标(" + Math.round(最右边按钮.x) + "," + Math.round(最右边按钮.y) + ")");
- return { x: 最右边按钮.x, y: 最右边按钮.y };
- }
-
- print.log("⚠ 相册选择按钮使用坐标兜底(底部)");
- return { x: 屏幕宽 * 0.78, y: 屏幕高 * 0.92 };
- }
- function 查找第一张图片(xml) {
- var xmlStr = "" + xml;
-
- if (是否在系统相册页面(xmlStr)) {
- agent.shell("echo '" + xmlStr.substring(0, 5000) + "' > /sdcard/相册UI_dump.xml");
- print.log("✓ 已保存相册UI XML到/sdcard/相册UI_dump.xml");
-
- var nafPattern = /<node[^>]*?NAF="true"[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
- var nafMatch;
- var NAF小圆点列表 = [];
-
- while ((nafMatch = nafPattern.exec(xmlStr)) !== null) {
- var nx1 = parseInt(nafMatch[1]);
- var ny1 = parseInt(nafMatch[2]);
- var nx2 = parseInt(nafMatch[3]);
- var ny2 = parseInt(nafMatch[4]);
- var nw = nx2 - nx1;
- var nh = ny2 - ny1;
-
- if (nw >= 50 && nw <= 300 && nh >= 50 && nh <= 300) {
- if (ny1 >= 400 && ny2 <= 屏幕高 - 400) {
- NAF小圆点列表.push({ x1: nx1, y1: ny1, x2: nx2, y2: ny2, x: (nx1 + nx2) / 2, y: (ny1 + ny2) / 2 });
- }
- }
- }
-
- if (NAF小圆点列表.length > 0) {
- NAF小圆点列表.sort(function(a, b) {
- if (a.y1 !== b.y1) return a.y1 - b.y1;
- return a.x1 - b.x1;
- });
- var 选中小圆点 = NAF小圆点列表[0];
- print.log("✓ ComposeView找到NAF小圆点选择框:坐标(" + Math.round(选中小圆点.x) + "," + Math.round(选中小圆点.y) + "),bounds=[" + 选中小圆点.x1 + "," + 选中小圆点.y1 + "][" + 选中小圆点.x2 + "," + 选中小圆点.y2 + "]");
- return { x: 选中小圆点.x, y: 选中小圆点.y };
- }
-
- var imageDescPattern = /<node[^>]*?content-desc="([^"]+\.(png|jpg|jpeg|gif))"[^>]*?class="android\.view\.View"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/gi;
- var imgMatch;
- var 图片节点列表 = [];
-
- while ((imgMatch = imageDescPattern.exec(xmlStr)) !== null) {
- var 文件名 = imgMatch[1];
- var ix1 = parseInt(imgMatch[3]);
- var iy1 = parseInt(imgMatch[4]);
- var ix2 = parseInt(imgMatch[5]);
- var iy2 = parseInt(imgMatch[6]);
- var iw = ix2 - ix1;
- var ih = iy2 - iy1;
-
- if (iw >= 100 && ih >= 100) {
- 图片节点列表.push({ 文件名: 文件名, x1: ix1, y1: iy1, x2: ix2, y2: iy2, w: iw, h: ih });
- }
- }
-
- if (图片节点列表.length > 0) {
- 图片节点列表.sort(function(a, b) {
- if (a.y1 !== b.y1) return a.y1 - b.y1;
- return a.x1 - b.x1;
- });
- var 第一张图片 = 图片节点列表[0];
- print.log("✓ 找到图片:" + 第一张图片.文件名 + ",bounds=[" + 第一张图片.x1 + "," + 第一张图片.y1 + "][" + 第一张图片.x2 + "," + 第一张图片.y2 + "]");
-
- var 选择框X = 第一张图片.x1 + 第一张图片.w * 0.77;
- var 选择框Y = 第一张图片.y1 + 第一张图片.h * 0.24;
- print.log("✓ 计算小圆点选择框坐标:(" + Math.round(选择框X) + "," + Math.round(选择框Y) + ")");
- return { x: 选择框X, y: 选择框Y };
- }
-
- var clickableViewPattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
- var clickMatch;
- var 可点击区域 = [];
- while ((clickMatch = clickableViewPattern.exec(xmlStr)) !== null) {
- var cx1 = parseInt(clickMatch[1]);
- var cy1 = parseInt(clickMatch[2]);
- var cx2 = parseInt(clickMatch[3]);
- var cy2 = parseInt(clickMatch[4]);
- var cw = cx2 - cx1;
- var ch = cy2 - cy1;
- 可点击区域.push({ x1: cx1, y1: cy1, x2: cx2, y2: cy2, w: cw, h: ch, x: (cx1 + cx2) / 2, y: (cy1 + cy2) / 2 });
- }
-
- var 图片区域内可点击 = [];
- for (var k = 0; k < 可点击区域.length; k++) {
- var item = 可点击区域[k];
- if (item.y >= 400 && item.y <= 屏幕高 - 400) {
- 图片区域内可点击.push(item);
- }
- }
-
- if (图片区域内可点击.length > 0) {
- 图片区域内可点击.sort(function(a, b) {
- if (a.y !== b.y) return a.y - b.y;
- return a.x - b.x;
- });
- var 第一个可点击 = 图片区域内可点击[0];
- print.log("✓ ComposeView图片区域内第一个可点击元素:坐标(" + Math.round(第一个可点击.x) + "," + Math.round(第一个可点击.y) + ")");
- return { x: 第一个可点击.x, y: 第一个可点击.y };
- }
- print.log("⚠ 系统相册未找到图片,使用坐标兜底");
- return { x: 屏幕宽 * 0.25, y: 屏幕高 * 0.3 };
- }
- print.log("⚠ 未找到图片,使用坐标兜底(底部第一行第一列)");
- return { x: 屏幕宽 * 0.15, y: 屏幕高 * 0.85 };
- }
- function 查找发送按钮中心(xml) {
- var xmlStr = "" + xml;
- try {
- var detects = opencv.findImagesEx('图色168638.cv');
- if (detects != null && detects.length > 0) {
- print.log("✓ 发送按钮定位:图色匹配");
- var dStr = "" + detects[0];
- print.log("图色匹配结果:" + dStr);
- var m = dStr.match(/矩形区域:([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+)/);
- if (m) {
- var left = parseFloat(m[1]);
- var top = parseFloat(m[2]);
- var right = parseFloat(m[3]);
- var bottom = parseFloat(m[4]);
- var centerX = (left + right) / 2;
- var centerY = (top + bottom) / 2;
- print.log("图色匹配百分比坐标:left=" + left + ", top=" + top + ", right=" + right + ", bottom=" + bottom);
- print.log("计算点击百分比:(" + centerX + "," + centerY + ")");
- agent.clickPercent(centerX, centerY);
- print.log("✓ 已点击发送按钮(图色)");
- return null;
- }
- print.log("⚠ 图色匹配结果格式解析失败");
- }
- } catch (e) {
- print.log("⚠ 图色匹配失败:" + e.message);
- }
- var inputKeywords = ["给Kimi发消息", "有问题尽管问我"];
- var inputIdx = -1;
- for (var k = 0; k < inputKeywords.length; k++) {
- inputIdx = xmlStr.indexOf('text="' + inputKeywords[k] + '"');
- if (inputIdx !== -1) break;
- }
-
- if (inputIdx !== -1) {
- var 输入框段 = xmlStr.substring(inputIdx);
- var 输入框边界 = 输入框段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
-
- if (输入框边界) {
- var 输入框信息 = {
- x1: parseInt(输入框边界[1]),
- y1: parseInt(输入框边界[2]),
- x2: parseInt(输入框边界[3]),
- y2: parseInt(输入框边界[4]),
- centerY: (parseInt(输入框边界[2]) + parseInt(输入框边界[4])) / 2
- };
- var clickablePattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"[^>]*?\/?>/g;
- var clickMatch;
- var candidates = [];
- while ((clickMatch = clickablePattern.exec(xmlStr)) !== null) {
- var cx1 = parseInt(clickMatch[1]);
- var cy1 = parseInt(clickMatch[2]);
- var cx2 = parseInt(clickMatch[3]);
- var cy2 = parseInt(clickMatch[4]);
- var cw = cx2 - cx1;
- var ch = cy2 - cy1;
- var 是小按钮 = (cw < 300 && ch < 300);
- var 在输入框右侧 = (cx1 > 输入框信息.x2 - 100);
- var 在输入框水平行 = (cy1 >= 输入框信息.y1 - 100 && cy1 <= 输入框信息.y2 + 100);
- if (是小按钮 && 在输入框右侧 && 在输入框水平行) {
- candidates.push({
- x1: cx1, y1: cy1, x2: cx2, y2: cy2,
- x: (cx1 + cx2) / 2,
- y: (cy1 + cy2) / 2
- });
- }
- }
- if (candidates.length > 0) {
- candidates.sort(function(a, b) {
- return b.x1 - a.x1;
- });
- var 选中 = candidates[0];
- print.log("✓ 发送按钮定位:输入框右侧clickable元素,坐标(" + Math.round(选中.x) + "," + Math.round(选中.y) + ")");
- return { x: 选中.x, y: 选中.y };
- }
- var 预估X = 输入框信息.x2 + 100;
- var 预估Y = 输入框信息.centerY;
- print.log("⚠ 发送按钮使用输入框右侧坐标兜底(" + Math.round(预估X) + "," + Math.round(预估Y) + ")");
- return { x: 预估X, y: 预估Y };
- }
- }
- var sendTextIdx = xmlStr.indexOf('text="发送"');
- if (sendTextIdx !== -1) {
- var 段 = xmlStr.substring(sendTextIdx);
- var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m) {
- print.log("✓ 发送按钮定位:文本匹配");
- return {
- x: (parseInt(m[1]) + parseInt(m[3])) / 2,
- y: (parseInt(m[2]) + parseInt(m[4])) / 2
- };
- }
- }
- var sendDescIdx = xmlStr.indexOf('content-desc="发送"');
- if (sendDescIdx !== -1) {
- var 段2 = xmlStr.substring(sendDescIdx);
- var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m2) {
- print.log("✓ 发送按钮定位:content-desc匹配");
- return {
- x: (parseInt(m2[1]) + parseInt(m2[3])) / 2,
- y: (parseInt(m2[2]) + parseInt(m2[4])) / 2
- };
- }
- }
- print.log("⚠ 发送按钮使用屏幕右侧坐标兜底");
- agent.clickPercent(0.9, 0.92);
- print.log("✓ 已点击发送按钮(硬编码兜底)");
- return null;
- }
- function 等待AI回答完成(发送前的最后文本, 发送前回答数量) {
- var 已耗时 = 0;
- var 检查间隔秒 = 3;
- var 连续相同次数 = 0;
- var 上次规范化文本 = "";
- print.log("发送前最后AI回答:'" + 发送前的最后文本 + "',发送前回答数量:" + 发送前回答数量);
- sleep.second(秒 = 5);
- 已耗时 += 5;
- while (已耗时 < 等待回答超时秒) {
- var xml = 获取UI();
- var 回答列表 = 采集AI回答列表(xml);
-
- if (回答列表.length > 0) {
- var 当前最后回答 = 回答列表[回答列表.length - 1];
- var 当前提取数字 = 提取数字(当前最后回答);
- var 当前规范化文本 = 当前最后回答.trim().replace(/\s+/g, " ");
-
- var 有新回答 = false;
- var 回答数量增加 = (回答列表.length > 发送前回答数量);
-
- var 发送前规范化 = 发送前的最后文本.trim().replace(/\s+/g, " ");
- 有新回答 = (当前规范化文本 !== 发送前规范化) || (当前提取数字 !== "");
-
- if (有新回答 || 回答数量增加) {
- print.log("✓ 检测到新回答(" + 已耗时 + "秒):'" + 当前最后回答 + "',提取数字:'" + 当前提取数字 + "'");
-
- if (当前规范化文本 === 上次规范化文本) {
- 连续相同次数++;
- if (连续相同次数 >= 2) {
- print.log("✓ 文本连续2次相同,回答完成");
- return 当前最后回答;
- }
- } else {
- 连续相同次数 = 0;
- 上次规范化文本 = 当前规范化文本;
- }
- }
- }
-
- sleep.second(秒 = 检查间隔秒);
- 已耗时 += 检查间隔秒;
- }
- print.log("⚠ 等待AI回答超时(" + 等待回答超时秒 + "秒),尝试返回当前内容");
- var xml = 获取UI();
- var 兜底列表 = 采集AI回答列表(xml);
- if (兜底列表.length > 0) {
- var 兜底文本 = 兜底列表[兜底列表.length - 1];
- print.log("✓ 超时兜底:返回当前采集到的回答:" + 兜底文本);
- return 兜底文本;
- }
- return null;
- }
- // ========== 主流程开始 ==========
- function 主流程() {
- // 步骤1:全屏截图(B站验证码页面)
- print.log("\n========== 步骤1:全屏截图B站验证码 ==========");
- var 截图成功 = 全屏截图(截图保存路径);
- if (!截图成功) {
- print.log("✗ 截图失败,退出流程");
- print.log("===== KIMI识别验证码拖动B站流程结束 =====");
- return;
- }
- // 步骤2:启动Kimi APP
- print.log("\n========== 步骤2:启动Kimi APP ==========");
- try {
- app.openApp(KIMI包名);
- print.log("✓ 已启动Kimi");
- } catch (e) {
- print.log("⚠ 启动失败:" + e.message);
- }
- sleep.second(秒 = 5);
- // 步骤3:点击右上角新对话按钮
- print.log("\n========== 步骤3:点击右上角新对话按钮 ==========");
-
- xml = 获取UI();
-
- var 新对话X = 屏幕宽 * 0.96;
- var 新对话Y = 屏幕高 * 0.06;
-
- var newChatIdx = xml.indexOf('content-desc="开启新会话"');
- if (newChatIdx !== -1) {
- var 段 = xml.substring(newChatIdx);
- var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m) {
- 新对话X = (parseInt(m[1]) + parseInt(m[3])) / 2;
- 新对话Y = (parseInt(m[2]) + parseInt(m[4])) / 2;
- print.log("✓ 新对话按钮定位:content-desc=开启新会话,坐标(" + Math.round(新对话X) + "," + Math.round(新对话Y) + ")");
- }
- }
-
- agent.click(新对话X, 新对话Y);
- print.log("✓ 已点击新对话按钮,坐标(" + Math.round(新对话X) + "," + Math.round(新对话Y) + ")");
-
- sleep.second(秒 = 5);
- print.log("✓ 新对话操作完成,等待5秒确保界面加载");
- // 步骤4:记录发送前的最后一条AI回答和数量
- print.log("\n========== 步骤4:记录发送前状态 ==========");
- var 发送前回答数量 = 0;
- print.log("✓ 发送前回答数量:" + 发送前回答数量);
- // 步骤5:点击加号按钮打开附件菜单(使用图色匹配,因为点击前XML可能不完整)
- print.log("\n========== 步骤5:点击加号按钮打开附件菜单 ==========");
-
- var 加号点击成功 = false;
- var detects = opencv.findImagesEx('图色414387.cv');
- if (detects != null && detects.length > 0) {
- print.log("✓ 图色匹配找到加号按钮");
- print.log("图色匹配结果:" + detects[0]);
- var dStr = "" + detects[0];
- var m = dStr.match(/矩形区域:([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+)/);
- if (m) {
- var left = parseFloat(m[1]);
- var top = parseFloat(m[2]);
- var right = parseFloat(m[3]);
- var bottom = parseFloat(m[4]);
- var centerX = (left + right) / 2;
- var centerY = (top + bottom) / 2;
- agent.clickPercent(centerX, centerY);
- print.log("✓ 已点击加号按钮(图色匹配),百分比坐标(" + centerX.toFixed(4) + "," + centerY.toFixed(4) + ")");
- 加号点击成功 = true;
- }
- }
-
- if (!加号点击成功) {
- print.log("⚠ 图色匹配未找到加号按钮,使用坐标兜底");
- var 兜底X = 屏幕宽 * 0.92;
- var 兜底Y = 屏幕高 * 0.55;
- agent.click(兜底X, 兜底Y);
- print.log("✓ 已点击加号按钮(坐标兜底),坐标(" + Math.round(兜底X) + "," + Math.round(兜底Y) + ")");
- 加号点击成功 = true;
- }
-
- sleep.second(秒 = 3);
- print.log("✓ 等待3秒让附件菜单完全弹出");
- // 步骤6:点击相册按钮选择图片(点击加号后XML已完整,使用XML定位)
- print.log("\n========== 步骤6:点击相册按钮选择图片 ==========");
-
- var 相册选择成功 = false;
- var 尝试次数 = 0;
-
- while (!相册选择成功 && 尝试次数 < 5) {
- 尝试次数++;
- xml = 获取UI();
-
- if (是否在系统相册页面(xml)) {
- print.log("✓ 已进入系统相册页面");
- 相册选择成功 = true;
- break;
- }
-
- var 相册位置 = 查找相册按钮(xml);
- agent.click(相册位置.x, 相册位置.y);
- print.log("✓ 已点击相册按钮,坐标(" + Math.round(相册位置.x) + "," + Math.round(相册位置.y) + ")");
- sleep.second(秒 = 2);
-
- xml = 获取UI();
- if (是否在系统相册页面(xml)) {
- print.log("✓ 已进入系统相册页面");
- 相册选择成功 = true;
- break;
- }
-
- print.log("⚠ 第" + 尝试次数 + "次尝试:未进入相册页面,重新点击加号");
-
- var 加号Detects = opencv.findImagesEx('图色414387.cv');
- if (加号Detects != null && 加号Detects.length > 0) {
- var dStr2 = "" + 加号Detects[0];
- var m2 = dStr2.match(/矩形区域:([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+)/);
- if (m2) {
- var centerX2 = (parseFloat(m2[1]) + parseFloat(m2[3])) / 2;
- var centerY2 = (parseFloat(m2[2]) + parseFloat(m2[4])) / 2;
- agent.clickPercent(centerX2, centerY2);
- print.log("✓ 重新点击加号按钮(图色匹配),百分比坐标(" + centerX2.toFixed(4) + "," + centerY2.toFixed(4) + ")");
- }
- } else {
- var 兜底X = 屏幕宽 * 0.92;
- var 兜底Y = 屏幕高 * 0.55;
- agent.click(兜底X, 兜底Y);
- print.log("✓ 重新点击加号按钮(坐标兜底),坐标(" + Math.round(兜底X) + "," + Math.round(兜底Y) + ")");
- }
- sleep.second(秒 = 3);
- }
- // 步骤7:选择第一张图片(系统相册用Canvas渲染,XML无节点,直接坐标点击)
- print.log("\n========== 步骤7:选择第一张图片 ==========");
-
- var 图片尝试次数 = 0;
- while (图片尝试次数 < 3) {
- 图片尝试次数++;
- xml = 获取UI();
-
- if (是否在系统相册页面(xml)) {
- print.log("✓ 系统相册页面,点击图片位置");
-
- var 标题栏底部 = 432;
- var actionBarMatch = xml.match(/resource-id="android:id\/action_bar"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (actionBarMatch) {
- 标题栏底部 = parseInt(actionBarMatch[4]);
- }
-
- var 图片区域顶部 = 标题栏底部;
- var 图片区域底部 = 屏幕高;
- var 图片区域高度 = 图片区域底部 - 图片区域顶部;
-
- var 图片X = 屏幕宽 * 0.5;
- var 图片Y = 图片区域顶部 + 图片区域高度 * 0.4;
- agent.click(图片X, 图片Y);
- print.log("✓ 已点击图片位置,坐标(" + Math.round(图片X) + "," + Math.round(图片Y) + ")");
- sleep.second(秒 = 3);
-
- xml = 获取UI();
- if (!是否在系统相册页面(xml)) {
- print.log("✓ 已离开相册页面,图片可能已添加");
- break;
- }
- } else {
- break;
- }
- }
- // 步骤8:等待图片添加到输入区域(等待回到Kimi对话页面)
- print.log("\n========== 步骤8:等待图片添加到输入区域 ==========");
- sleep.second(秒 = 3);
- xml = 获取UI();
-
- var packageMatch = xml.match(/package="([^"]+)"/);
- if (packageMatch && packageMatch[1] === KIMI包名) {
- print.log("✓ 已回到Kimi对话页面");
- }
-
- print.log("✓ 图片已添加到输入区域");
- // 步骤9:粘贴文字询问拖动距离
- print.log("\n========== 步骤9:粘贴文字询问拖动距离 ==========");
- xml = 获取UI();
-
- var 输入框位置 = 查找输入框中心(xml);
- agent.click(输入框位置.x, 输入框位置.y);
- print.log("✓ 已点击输入框,坐标(" + Math.round(输入框位置.x) + "," + Math.round(输入框位置.y) + ")");
- sleep.second(秒 = 2);
-
- try {
- Clipboard.copy("" + 提问话术);
- sleep.millisecond(毫秒 = 500);
- agent.shell("input keyevent 279");
- sleep.second(秒 = 2);
- print.log("✓ 已通过剪贴板粘贴文本");
- } catch (e) {
- print.log("⚠ 剪贴板粘贴失败:" + e.message);
- agent.shell("input text '" + 提问话术 + "'");
- sleep.second(秒 = 2);
- print.log("✓ 已通过input text直接输入文本");
- }
- sleep.second(秒 = 2);
- // 步骤10:发送图片和文字
- print.log("\n========== 步骤10:发送图片和文字 ==========");
-
- var detects = opencv.findImagesEx('图色769678.cv');
- if (detects != null) {
- print.log("✓ 图色匹配找到发送按钮");
- print.log("图色匹配结果:" + detects[0]);
- var dStr = "" + detects[0];
- var sendMatch = dStr.match(/矩形区域:([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+)/);
- if (sendMatch) {
- var left = parseFloat(sendMatch[1]);
- var top = parseFloat(sendMatch[2]);
- var right = parseFloat(sendMatch[3]);
- var bottom = parseFloat(sendMatch[4]);
- var centerX = (left + right) / 2;
- var centerY = (top + bottom) / 2;
- agent.clickPercent(centerX, centerY);
- print.log("✓ 已点击发送按钮(图色匹配),百分比坐标(" + centerX.toFixed(4) + "," + centerY.toFixed(4) + ")");
- }
- } else {
- print.log("⚠ 图色匹配未找到发送按钮,尝试坐标兜底");
- var 发送按钮位置 = 查找发送按钮中心(xml);
- if (发送按钮位置) {
- agent.click(发送按钮位置.x, 发送按钮位置.y);
- print.log("✓ 已点击发送按钮(坐标兜底)");
- }
- }
-
- sleep.second(秒 = 10);
- // 步骤11:等待Kimi AI回答
- print.log("\n========== 步骤11:等待Kimi AI回答 ==========");
- xml = 获取UI();
- var AI回答 = 等待AI回答完成("", 0);
-
- if (!AI回答) {
- print.log("✗ 未获取到AI回答");
- print.log("===== KIMI识别验证码拖动B站流程结束 =====");
- return;
- }
- print.log("\n✓ 采集到AI回答");
-
- print.log("\n========== 步骤11.5:点击加号获取完整源码 ==========");
- var detects = opencv.findImagesEx('图色414387.cv');
- if (detects != null && detects.length > 0) {
- var dStr = "" + detects[0];
- var m = dStr.match(/矩形区域:([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+)/);
- if (m) {
- var centerX = (parseFloat(m[1]) + parseFloat(m[3])) / 2;
- var centerY = (parseFloat(m[2]) + parseFloat(m[4])) / 2;
- agent.clickPercent(centerX, centerY);
- print.log("✓ 已点击加号按钮(图色匹配),百分比坐标(" + centerX.toFixed(4) + "," + centerY.toFixed(4) + ")");
- }
- } else {
- agent.click(屏幕宽 * 0.92, 屏幕高 * 0.55);
- print.log("✓ 已点击加号按钮(坐标兜底)");
- }
- sleep.second(秒 = 2);
- xml = 获取UI();
- print.log("✓ 点击加号后重新获取UI");
-
- AI回答 = 获取当前最后AI回答(xml);
- print.log("✓ 重新采集AI回答:'" + AI回答 + "'");
-
- print.log("--- 采集内容开始 ---");
- print.log(AI回答);
- print.log("--- 采集内容结束 ---");
- // 步骤12:解析拖动距离坐标
- print.log("\n========== 步骤12:解析拖动距离坐标 ==========");
- print.log("✓ AI原始回答:'" + AI回答 + "'");
-
- var 所有数字 = AI回答.match(/\d+/g);
- var 拖动距离像素 = null;
- var AI图像宽度 = null;
-
- if (AI回答.indexOf("距离") !== -1 || AI回答.indexOf("像素") !== -1) {
- var 距离匹配 = AI回答.match(/(\d+)\s*[像相]?素?/);
- if (距离匹配) {
- 拖动距离像素 = parseInt(距离匹配[1]);
- print.log("✓ 识别到距离格式回答,提取数字:" + 拖动距离像素);
- AI图像宽度 = 屏幕宽;
- print.log("✓ 距离格式回答,使用屏幕宽度作为图像宽度,不额外缩放");
- } else {
- var 数字匹配 = AI回答.match(/(\d+)/);
- if (数字匹配) {
- 拖动距离像素 = parseInt(数字匹配[1]);
- print.log("✓ 从距离回答中提取数字:" + 拖动距离像素);
- AI图像宽度 = 屏幕宽;
- }
- }
- } else if (所有数字 && 所有数字.length >= 2) {
- var 数字列表 = [];
- for (var n = 0; n < 所有数字.length; n++) {
- 数字列表.push(parseInt(所有数字[n]));
- }
- print.log("✓ 提取到所有数字:" + 数字列表.join(", "));
-
- if (数字列表.length >= 5) {
- var x1 = 数字列表[0];
- var y1 = 数字列表[1];
- var x2 = 数字列表[2];
- var y2 = 数字列表[3];
- AI图像宽度 = 数字列表[4];
- 拖动距离像素 = Math.abs(x2 - x1);
- print.log("✓ 识别到两组坐标+图像宽度:(" + x1 + "," + y1 + ") 和 (" + x2 + "," + y2 + "),图像宽度=" + AI图像宽度);
- print.log("✓ 计算拖动距离:|x2 - x1| = |" + x2 + " - " + x1 + "| = " + 拖动距离像素);
- } else if (数字列表.length >= 4) {
- var x1 = 数字列表[0];
- var y1 = 数字列表[1];
- var x2 = 数字列表[2];
- var y2 = 数字列表[3];
- 拖动距离像素 = Math.abs(x2 - x1);
- AI图像宽度 = Math.max(x1, x2) + 100;
- print.log("✓ 识别到两组坐标格式:(" + x1 + "," + y1 + ") 和 (" + x2 + "," + y2 + ")");
- print.log("✓ 计算拖动距离:|x2 - x1| = |" + x2 + " - " + x1 + "| = " + 拖动距离像素);
- print.log("✓ 估算图像宽度:max(x1,x2)+100 = " + AI图像宽度);
- } else if (数字列表.length >= 2) {
- var 坐标匹配 = AI回答.match(/(\d+)\s*[,,]\s*(\d+)/);
- if (坐标匹配) {
- var cx1 = parseInt(坐标匹配[1]);
- var cx2 = parseInt(坐标匹配[2]);
- 拖动距离像素 = Math.abs(cx2 - cx1);
- AI图像宽度 = Math.max(cx1, cx2) + 100;
- print.log("✓ 识别到坐标格式:(" + cx1 + "," + cx2 + "),计算距离:" + 拖动距离像素);
- } else {
- 拖动距离像素 = 数字列表[0];
- print.log("✓ 提取到单个数字(拖动距离):" + 拖动距离像素);
- }
- } else {
- 拖动距离像素 = 数字列表[0];
- print.log("✓ 提取到单个数字(拖动距离):" + 拖动距离像素);
- }
- } else if (所有数字 && 所有数字.length === 1) {
- 拖动距离像素 = parseInt(所有数字[0]);
- print.log("✓ 提取到单个数字(拖动距离):" + 拖动距离像素);
- } else {
- print.log("✗ 未找到有效的拖动距离");
- print.log("===== KIMI识别验证码拖动B站流程结束 =====");
- return;
- }
-
- var 图像缩放系数 = 1.0;
- if (拖动距离像素 < 30) {
- print.log("⚠ 提取到的拖动距离过小(" + 拖动距离像素 + "),可能是OCR识别错误,跳过缩放补偿");
- } else if (AI图像宽度 && AI图像宽度 > 0 && AI图像宽度 < 屏幕宽) {
- 图像缩放系数 = 屏幕宽 / AI图像宽度;
- if (图像缩放系数 > 5) {
- 图像缩放系数 = 1.0;
- } else {
- 拖动距离像素 = Math.round(拖动距离像素 * 图像缩放系数);
- print.log("✓ 图像缩放补偿:AI图像宽度=" + AI图像宽度 + ",屏幕宽=" + 屏幕宽);
- print.log("✓ 缩放系数=" + 图像缩放系数.toFixed(2) + ",补偿后拖动距离=" + 拖动距离像素);
- }
- } else {
- 图像缩放系数 = 屏幕宽 / 750;
- 拖动距离像素 = Math.round(拖动距离像素 * 图像缩放系数);
- print.log("✓ 单数字模式补偿:假设AI图像宽度≈750,缩放系数=" + 图像缩放系数.toFixed(2));
- print.log("✓ 补偿后拖动距离=" + 拖动距离像素);
- }
-
- 验证码滑块距离 = {
- x: 拖动距离像素,
- y: 0
- };
- // 步骤13:切换回B站并拖动滑块
- print.log("\n========== 步骤13:切换回B站并拖动滑块 ==========");
-
- agent.shell("input keyevent 187");
- print.log("✓ 已按后台键打开任务列表");
- sleep.second(秒 = 2);
-
- xml = 获取UI();
- var biliIdx = xml.indexOf('哔哩哔哩');
- if (biliIdx === -1) {
- biliIdx = xml.indexOf('bilibili');
- }
- if (biliIdx === -1) {
- biliIdx = xml.indexOf('B站');
- }
-
- if (biliIdx !== -1) {
- var 段 = xml.substring(biliIdx);
- var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
- if (m) {
- var clickX = (parseInt(m[1]) + parseInt(m[3])) / 2;
- var clickY = (parseInt(m[2]) + parseInt(m[4])) / 2;
- agent.click(clickX, clickY);
- print.log("✓ 已点击B站任务卡片,坐标(" + Math.round(clickX) + "," + Math.round(clickY) + ")");
- }
- } else {
- print.log("⚠ 未找到B站任务卡片,尝试直接打开");
- try {
- app.openApp(B站包名);
- print.log("✓ 已打开B站");
- } catch (e) {
- print.log("⚠ 打开B站失败:" + e.message);
- }
- }
- sleep.second(秒 = 3);
- xml = 获取UI();
-
- var startX = 屏幕宽 * 0.15 + 50;
- var startY = 屏幕高 * 0.42;
-
- var detects = opencv.findImagesEx('图色975253.cv');
- if (detects != null && detects.length > 0) {
- print.log("✓ 图色匹配找到滑块初始位置");
- print.log("图色匹配结果:" + detects[0]);
- var dStr = "" + detects[0];
- var m = dStr.match(/矩形区域:([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+)/);
- if (m) {
- var left = parseFloat(m[1]);
- var top = parseFloat(m[2]);
- var right = parseFloat(m[3]);
- var bottom = parseFloat(m[4]);
- startX = (left + right) / 2 * 屏幕宽;
- startY = (top + bottom) / 2 * 屏幕高;
- print.log("✓ 滑块初始位置:(" + Math.round(startX) + "," + Math.round(startY) + ")");
- }
- } else {
- print.log("⚠ 图色匹配未找到滑块,使用坐标兜底");
- }
- var 拖动距离 = 验证码滑块距离.x * 滑块校准系数;
- var endX = startX + 拖动距离;
- var endY = startY;
- print.log("✓ 滑块起点: (" + Math.round(startX) + "," + Math.round(startY) + "), 拖动距离: " + 拖动距离);
- agent.swip(startX, startY, endX, endY, 2000);
- print.log("✓ 已拖动滑块,起点(" + Math.round(startX) + "," + Math.round(startY) + "),终点(" + Math.round(endX) + "," + Math.round(endY) + ")");
- }
- 主流程();
- print.log("\n===== KIMI识别验证码拖动B站流程结束 =====");
复制代码
| |  | |  |
|