自动发帖软件

标题: AIWROK软件测试文心识别识别验证码示例 [打印本页]

作者: 发帖软件    时间: 13 小时前
标题: AIWROK软件测试文心识别识别验证码示例

AIWROK软件测试文心识别识别验证码示例
AIWROK软件测试文心识别识别验证码示例 群发软件发帖工具

  1. // AIWROK 自动化流程:截图B站验证码 → 启动文心助手 → 发送截图询问拖动距离 → 采集回答 → 切回B站拖动滑块
  2. // 包名:com.baidu.newapp(百度文心助手)
  3. //
  4. // 使用说明:
  5. //   1. 在B站验证码页面运行脚本
  6. //   2. 脚本自动截图并发送给文心识别
  7. //   3. 解析文心返回的拖动距离,切回B站拖动滑块

  8. print.log("===== 文心识别验证码拖动B站流程启动 =====");
  9. print.time();

  10. // ========== 配置区 ==========
  11. var 文心包名 = "com.baidu.newapp";
  12. var B站包名 = "tv.danmaku.bili";
  13. var 截图保存路径 = "/sdcard/验证码截图.png";

  14. var 等待回答超时秒 = 20;
  15. var 回答输出等待秒 = 20;
  16. var 滑块校准系数 = 1.0;

  17. var 提问话术 = "请帮我分析这张图片,告诉我左边的方块需要向右移动多少像素才能和右边的缺口对齐,只输出:距离加数字";

  18. // ========== 获取设备信息 ==========
  19. var 屏幕宽 = screen.getScreenWidth();
  20. var 屏幕高 = screen.getScreenHeight();
  21. var 验证码滑块距离 = null;
  22. print.log("屏幕尺寸:" + 屏幕宽 + " x " + 屏幕高);
  23. print.log("代理状态:" + (agent.isOpen() ? "已开启" : "未开启"));

  24. // ========== 工具函数 ==========

  25. function 获取UI() {
  26.     var xml = agent.getXml();
  27.     return "" + xml;
  28. }

  29. function 字符串长度(s) {
  30.     var str = "" + s;
  31.     return str.length;
  32. }

  33. function 解码HTML实体(s) {
  34.     var str = "" + s;
  35.     str = str.replace(/
  36. /g, "\n");
  37.     str = str.replace(/
  38. /g, "\r");
  39.     str = str.replace(/        /g, "\t");
  40.     str = str.replace(/'/g, "'");
  41.     str = str.replace(/"/g, '"');
  42.     str = str.replace(/"/g, '"');
  43.     str = str.replace(/'/g, "'");
  44.     str = str.replace(/&/g, "&");
  45.     str = str.replace(/</g, "<");
  46.     str = str.replace(/>/g, ">");
  47.     return str;
  48. }

  49. function 获取当前最后AI回答(xml) {
  50.     var 回答列表 = 采集AI回答列表(xml);
  51.     if (回答列表.length === 0) return "";
  52.     return 回答列表[回答列表.length - 1];
  53. }

  54. function 获取WebView区域(xml) {
  55.     var xmlStr = "" + xml;
  56.     var webViewPattern = /<node[^>]*?class="com\.baidu\.webkit\.sdk\.WebView"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/;
  57.     var wvMatch = webViewPattern.exec(xmlStr);
  58.     if (wvMatch) {
  59.         return {
  60.             x1: parseInt(wvMatch[1]),
  61.             y1: parseInt(wvMatch[2]),
  62.             x2: parseInt(wvMatch[3]),
  63.             y2: parseInt(wvMatch[4])
  64.         };
  65.     }
  66.     return { x1: 0, y1: 348, x2: 屏幕宽, y2: 屏幕高 * 0.5 };
  67. }

  68. function OCR识别WebView区域(xml) {
  69.     try {
  70.         var img = screen.screenShotFull();
  71.         
  72.         var ocrres = img.MLKitOcr('zhs');
  73.         var ocrText = "";
  74.         
  75.         if (ocrres && typeof ocrres.getAllString === 'function') {
  76.             ocrText = "" + ocrres.getAllString();
  77.         } else if (ocrres && typeof ocrres.getJsonString === 'function') {
  78.             var jsonStr = "" + ocrres.getJsonString();
  79.             var textPattern = /"text"\s*:\s*"([^"]+)"/g;
  80.             var match;
  81.             var allText = [];
  82.             while ((match = textPattern.exec(jsonStr)) !== null) {
  83.                 if (match[1] && match[1].length > 0) {
  84.                     allText.push(match[1]);
  85.                 }
  86.             }
  87.             ocrText = allText.join("\n");
  88.         } else {
  89.             var str = "" + ocrres;
  90.             var textPattern2 = /"text"\s*:\s*"([^"]+)"/g;
  91.             var match2;
  92.             var allText2 = [];
  93.             while ((match2 = textPattern2.exec(str)) !== null) {
  94.                 if (match2[1] && match2[1].length > 0) {
  95.                     allText2.push(match2[1]);
  96.                 }
  97.             }
  98.             ocrText = allText2.join("\n");
  99.         }
  100.         
  101.         img.recycle();
  102.         
  103.         if (ocrText && ocrText.length > 0) {
  104.             print.log("✓ MLKitOcr识别成功");
  105.             print.log("--- OCR结果开始 ---");
  106.             print.log(ocrText);
  107.             print.log("--- OCR结果结束 ---");
  108.             return "" + ocrText;
  109.         }
  110.         
  111.         print.log("⚠ MLKitOcr未识别到内容");
  112.         return "";
  113.     } catch (e) {
  114.         print.log("⚠ OCR识别异常:" + e.message);
  115.         return "";
  116.     }
  117. }

  118. function 提取数字(文本) {
  119.     var str = "" + 文本;
  120.     var 精确匹配 = str.match(/距离加(\d+)/);
  121.     if (精确匹配) {
  122.         var num = parseInt(精确匹配[1]);
  123.         if (num >= 30) {
  124.             return "" + num;
  125.         }
  126.     }
  127.     var 备选匹配 = str.match(/距离精[\u51c6\u79ef\u786e]加?(\d+)/);
  128.     if (备选匹配) {
  129.         var num2 = parseInt(备选匹配[1]);
  130.         if (num2 >= 30) {
  131.             return "" + num2;
  132.         }
  133.     }
  134.     var allMatches = str.match(/\d+/g);
  135.     if (allMatches) {
  136.         var 候选数字 = [];
  137.         for (var i = 0; i < allMatches.length; i++) {
  138.             var n = parseInt(allMatches[i]);
  139.             if (n >= 30 && n < 1000) {
  140.                 候选数字.push(n);
  141.             }
  142.         }
  143.         if (候选数字.length > 0) {
  144.             候选数字.sort(function(a, b) { return b - a; });
  145.             return "" + 候选数字[0];
  146.         }
  147.         var allNums = [];
  148.         for (var j = 0; j < allMatches.length; j++) {
  149.             allNums.push(parseInt(allMatches[j]));
  150.         }
  151.         allNums.sort(function(a, b) { return b - a; });
  152.         return "" + allNums[0];
  153.     }
  154.     return "";
  155. }

  156. function 采集AI回答列表(xml) {
  157.     var xmlStr = "" + xml;
  158.     var 回答列表 = [];

  159.     var hasWebView = xmlStr.indexOf('com.baidu.webkit.sdk.WebView') !== -1;
  160.    
  161.     if (hasWebView) {
  162.         var ocr文本 = OCR识别WebView区域(xml);
  163.         if (ocr文本 && 字符串长度(ocr文本) > 1) {
  164.             回答列表.push(ocr文本);
  165.             print.log("✓ OCR识别到WebView文本");
  166.             print.log("--- OCR结果开始 ---");
  167.             print.log(ocr文本);
  168.             print.log("--- OCR结果结束 ---");
  169.             
  170.             var ocr数字 = 提取数字(ocr文本);
  171.             if (ocr数字) {
  172.                 print.log("✓ 从OCR结果中提取到数字:" + ocr数字);
  173.                 回答列表.push(ocr数字);
  174.             }
  175.         }
  176.     }

  177.     var textViewPattern = /<node[^>]*?text="([^"]+)"[^>]*?class="android\.widget\.TextView"[^>]*?\/?>/g;
  178.     var tvMatch;
  179.     var 跳过工具栏 = true;
  180.     while ((tvMatch = textViewPattern.exec(xmlStr)) !== null) {
  181.         if (tvMatch[1] && 字符串长度(tvMatch[1]) > 1) {
  182.             var 原始文本 = tvMatch[1];
  183.             var 解码文本 = 解码HTML实体(原始文本);
  184.             
  185.             if (解码文本.includes("任务") || 解码文本.includes("创意") ||
  186.                 解码文本.includes("放心") || 解码文本.includes("魔法")) {
  187.                 跳过工具栏 = false;
  188.                 continue;
  189.             }
  190.             
  191.             if (!跳过工具栏 && !解码文本.includes("接着问") &&
  192.                 !解码文本.includes("内容由AI生成") &&
  193.                 !回答列表.includes(解码文本)) {
  194.                 回答列表.push(解码文本);
  195.                 print.log("✓ 在TextView中找到文本: '" + 解码文本 + "'");
  196.             }
  197.         }
  198.     }

  199.     var editTextPattern = /<node[^>]*?text="([^"]+)"[^>]*?class="android\.widget\.EditText"[^>]*?\/?>/g;
  200.     var etMatch;
  201.     while ((etMatch = editTextPattern.exec(xmlStr)) !== null) {
  202.         if (etMatch[1] && 字符串长度(etMatch[1]) > 1 && !etMatch[1].includes("接着问")) {
  203.             var 原始文本 = etMatch[1];
  204.             var 解码文本 = 解码HTML实体(原始文本);
  205.             if (!解码文本.includes("内容由AI生成") && !回答列表.includes(解码文本)) {
  206.                 回答列表.push(解码文本);
  207.                 print.log("✓ 在EditText中找到文本: '" + 解码文本 + "'");
  208.             }
  209.         }
  210.     }

  211.     if (回答列表.length === 0) {
  212.         print.log("⚠ 未找到AI回答节点");
  213.     } else {
  214.         print.log("✓ 采集到" + 回答列表.length + "条AI回答");
  215.     }

  216.     return 回答列表;
  217. }

  218. function 全屏截图(保存路径) {
  219.     try {
  220.         var result = agent.shell("screencap -p " + 保存路径);
  221.         print.log("✓ 截图命令执行:" + result);
  222.         
  223.         var lsResult = agent.shell("ls -la " + 保存路径);
  224.         print.log("✓ 截图文件检查:" + lsResult);
  225.         
  226.         return true;
  227.     } catch (e) {
  228.         print.log("⚠ 截图失败:" + e.message);
  229.         return false;
  230.     }
  231. }

  232. function 判断文心打开形式(xml) {
  233.     var xmlStr = "" + xml;
  234.    
  235.     var hasWebView = xmlStr.indexOf('com.baidu.webkit.sdk.WebView') !== -1;
  236.     var hasInput = xmlStr.indexOf('text="发消息或按住说话"') !== -1 ||
  237.                    xmlStr.indexOf('text="在这里提问"') !== -1 ||
  238.                    xmlStr.indexOf('text="接着问"') !== -1;
  239.    
  240.     if (hasWebView || hasInput) {
  241.         print.log("✓ 文心APP打开形式:直接对话页面");
  242.         return "对话页";
  243.     }
  244.    
  245.     var hasDialogTab = xmlStr.indexOf('text="对话"') !== -1;
  246.     var hasWenxinText = xmlStr.indexOf('text="文心"') !== -1;
  247.     var hasAssistantText = xmlStr.indexOf('text="助手"') !== -1;
  248.     var hasRecyclerView = xmlStr.indexOf('class="androidx.recyclerview.widget.RecyclerView"') !== -1;
  249.     var hasBottomNav = xmlStr.indexOf('text="工具"') !== -1 && xmlStr.indexOf('text="发现"') !== -1 && xmlStr.indexOf('text="我的"') !== -1;
  250.    
  251.     if ((hasDialogTab && hasRecyclerView) || (hasWenxinText && hasAssistantText) || hasBottomNav) {
  252.         print.log("✓ 文心APP打开形式:对话列表页面");
  253.         return "列表页";
  254.     }
  255.    
  256.     print.log("⚠ 文心APP打开形式:未知页面");
  257.     return "未知";
  258. }

  259. function 查找输入框中心(xml) {
  260.     var xmlStr = "" + xml;
  261.    
  262.     var inputKeywords = ["发消息或按住说话", "在这里提问", "接着问"];
  263.     for (var k = 0; k < inputKeywords.length; k++) {
  264.         var inputIdx = xmlStr.indexOf('text="' + inputKeywords[k] + '"');
  265.         if (inputIdx !== -1) {
  266.             var 段 = xmlStr.substring(inputIdx);
  267.             var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  268.             if (m) {
  269.                 var x1 = parseInt(m[1]);
  270.                 var y1 = parseInt(m[2]);
  271.                 var x2 = parseInt(m[3]);
  272.                 var y2 = parseInt(m[4]);
  273.                 print.log("✓ 输入框定位:text=" + inputKeywords[k] + ",bounds=[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "]");
  274.                 return {
  275.                     x: (x1 + x2) / 2,
  276.                     y: (y1 + y2) / 2
  277.                 };
  278.             }
  279.         }
  280.     }

  281.     var editTextIdx = xmlStr.indexOf('class="android.widget.EditText"');
  282.     if (editTextIdx !== -1) {
  283.         var 段2 = xmlStr.substring(editTextIdx);
  284.         var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  285.         if (m2) {
  286.             var x1 = parseInt(m2[1]);
  287.             var y1 = parseInt(m2[2]);
  288.             var x2 = parseInt(m2[3]);
  289.             var y2 = parseInt(m2[4]);
  290.             print.log("✓ 输入框定位(EditText):bounds=[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "]");
  291.             return {
  292.                 x: (x1 + x2) / 2,
  293.                 y: (y1 + y2) / 2
  294.             };
  295.         }
  296.     }

  297.     print.log("⚠ 未找到输入框,使用兜底坐标");
  298.     return {
  299.         x: 屏幕宽 * 0.4,
  300.         y: 屏幕高 * 0.85
  301.     };
  302. }

  303. function 查找加号按钮(xml) {
  304.     var xmlStr = "" + xml;
  305.    
  306.     var inputKeywords = ["发消息或按住说话", "在这里提问", "接着问"];
  307.     var 输入框边界 = null;
  308.    
  309.     for (var k = 0; k < inputKeywords.length; k++) {
  310.         var inputBoxIdx = xmlStr.indexOf('text="' + inputKeywords[k] + '"');
  311.         if (inputBoxIdx !== -1) {
  312.             var 输入框段 = xmlStr.substring(inputBoxIdx);
  313.             输入框边界 = 输入框段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  314.             if (输入框边界) break;
  315.         }
  316.     }
  317.    
  318.     if (!输入框边界) {
  319.         var editTextIdx = xmlStr.indexOf('class="android.widget.EditText"');
  320.         if (editTextIdx !== -1) {
  321.             var 段 = xmlStr.substring(editTextIdx);
  322.             输入框边界 = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  323.         }
  324.     }
  325.    
  326.     if (输入框边界) {
  327.         var 输入框X2 = parseInt(输入框边界[3]);
  328.         var 输入框Y = parseInt(输入框边界[2]);
  329.         var 输入框底部Y = parseInt(输入框边界[4]);
  330.         var 输入框中心Y = (输入框Y + 输入框底部Y) / 2;
  331.         
  332.         var plusPattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  333.         var plusMatch;
  334.         var 候选按钮 = [];
  335.         
  336.         while ((plusMatch = plusPattern.exec(xmlStr)) !== null) {
  337.             var bx1 = parseInt(plusMatch[1]);
  338.             var by1 = parseInt(plusMatch[2]);
  339.             var bx2 = parseInt(plusMatch[3]);
  340.             var by2 = parseInt(plusMatch[4]);
  341.             
  342.             if (by1 >= 输入框中心Y - 100 && by2 <= 输入框中心Y + 200 && bx1 > 输入框X2 - 50) {
  343.                 候选按钮.push({ x: (bx1 + bx2) / 2, y: (by1 + by2) / 2 });
  344.             }
  345.         }
  346.         
  347.         if (候选按钮.length > 0) {
  348.             候选按钮.sort(function(a, b) { return a.x - b.x; });
  349.             print.log("✓ 加号按钮定位:输入框右侧clickable元素,坐标(" + Math.round(候选按钮[0].x) + "," + Math.round(候选按钮[0].y) + ")");
  350.             return 候选按钮[0];
  351.         }
  352.     }

  353.     print.log("⚠ 加号按钮使用兜底坐标(输入框右侧)");
  354.     var 输入框 = 查找输入框中心(xml);
  355.     return {
  356.         x: 屏幕宽 * 0.9,
  357.         y: 输入框.y
  358.     };
  359. }

  360. function 粘贴文本(文本) {
  361.     try {
  362.         Clipboard.copy("" + 文本);
  363.     } catch (e) {
  364.         print.log("⚠ Clipboard.copy 失败:" + e.message);
  365.     }
  366.     sleep.millisecond(毫秒 = 300);

  367.     try {
  368.         agent.shell("service call clipboard 3 i32 1 s16 '" + 文本 + "' i32 0");
  369.     } catch (e2) {
  370.         // 忽略错误
  371.     }
  372.     sleep.millisecond(毫秒 = 300);

  373.     agent.shell("input keyevent 279");
  374.     sleep.second(秒 = 1);
  375.     print.log("✓ 已粘贴文本:" + 文本);
  376. }

  377. function 查找相册选项(xml) {
  378.     var xmlStr = "" + xml;
  379.    
  380.     var text关键词 = ["相册", "图片", "照片", "所有照片", "从相册选择", "选择图片"];
  381.     for (var i = 0; i < text关键词.length; i++) {
  382.         var kw = text关键词[i];
  383.         var idx = xmlStr.indexOf('text="' + kw + '"');
  384.         if (idx !== -1) {
  385.             var 段 = xmlStr.substring(idx);
  386.             var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  387.             if (m) {
  388.                 print.log("✓ 相册选项定位:text=" + kw);
  389.                 return {
  390.                     x: (parseInt(m[1]) + parseInt(m[3])) / 2,
  391.                     y: (parseInt(m[2]) + parseInt(m[4])) / 2
  392.                 };
  393.             }
  394.         }
  395.     }

  396.     var desc关键词 = ["相册", "图片", "照片"];
  397.     for (var j = 0; j < desc关键词.length; j++) {
  398.         var kw2 = desc关键词[j];
  399.         var idx2 = xmlStr.indexOf('content-desc="' + kw2 + '"');
  400.         if (idx2 !== -1) {
  401.             var 段2 = xmlStr.substring(idx2);
  402.             var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  403.             if (m2) {
  404.                 print.log("✓ 相册选项定位:content-desc=" + kw2);
  405.                 return {
  406.                     x: (parseInt(m2[1]) + parseInt(m2[3])) / 2,
  407.                     y: (parseInt(m2[2]) + parseInt(m2[4])) / 2
  408.                 };
  409.             }
  410.         }
  411.     }

  412.     return null;
  413. }

  414. function 是否在系统相册页面(xml) {
  415.     var xmlStr = "" + xml;
  416.    
  417.     var packageMatch = xmlStr.match(/package="([^"]+)"/);
  418.     var 当前包名 = packageMatch ? packageMatch[1] : "";
  419.    
  420.     if (当前包名 && 当前包名 !== 文心包名) {
  421.         print.log("✓ 检测到系统相册页面,包名:" + 当前包名);
  422.         return true;
  423.     }
  424.    
  425.     if (当前包名 === 文心包名) {
  426.         var 有拍照关键词 = xmlStr.indexOf('text="拍照"') !== -1;
  427.         var 有本地文件关键词 = xmlStr.indexOf('text="本地文件"') !== -1;
  428.         var 有微信文件关键词 = xmlStr.indexOf('text="微信文件"') !== -1;
  429.         
  430.         if (有拍照关键词 || 有本地文件关键词 || 有微信文件关键词) {
  431.             var 有图片网格 = xmlStr.indexOf('ugc_item_gridview') !== -1;
  432.             var 有所有图片 = xmlStr.indexOf('text="所有图片"') !== -1;
  433.             var 有取消按钮 = xmlStr.indexOf('text="取消"') !== -1;
  434.             
  435.             if (有图片网格 || 有所有图片 || 有取消按钮) {
  436.                 print.log("✓ 检测到文心助手内部图片选择页面");
  437.                 return true;
  438.             }
  439.             
  440.             print.log("⚠ 文心助手内部附件菜单,不是系统相册");
  441.             return false;
  442.         }
  443.     }
  444.    
  445.     var gallery关键词 = ["最近", "图库", "Camera", "所有图片", "照片", "相册", "All photos", "Photos"];
  446.     for (var i = 0; i < gallery关键词.length; i++) {
  447.         if (xmlStr.indexOf('text="' + gallery关键词[i] + '"') !== -1 ||
  448.             xmlStr.indexOf('content-desc="' + gallery关键词[i] + '"') !== -1) {
  449.             var 有聊天输入 = xmlStr.indexOf("接着问") !== -1 || xmlStr.indexOf("在这里提问") !== -1 || xmlStr.indexOf("发消息或按住说话") !== -1;
  450.             if (!有聊天输入) {
  451.                 print.log("✓ 检测到相册页面(关键词:" + gallery关键词[i] + ")");
  452.                 return true;
  453.             }
  454.         }
  455.     }
  456.    
  457.     var 有图片文件 = xmlStr.indexOf('.png"') !== -1 || xmlStr.indexOf('.jpg"') !== -1 ||
  458.                      xmlStr.indexOf('.jpeg"') !== -1 || xmlStr.indexOf('.gif"') !== -1;
  459.     var 有选择按钮 = xmlStr.indexOf('text="选择"') !== -1;
  460.     var 有聊天输入2 = xmlStr.indexOf("接着问") !== -1 || xmlStr.indexOf("在这里提问") !== -1 || xmlStr.indexOf("发消息或按住说话") !== -1;
  461.    
  462.     if (有图片文件 && 有选择按钮 && !有聊天输入2) {
  463.         print.log("✓ 检测到相册页面(有图片文件和选择按钮)");
  464.         return true;
  465.     }
  466.    
  467.     return false;
  468. }

  469. function 是否在图片预览页面(xml) {
  470.     var xmlStr = "" + xml;
  471.     if (xmlStr.indexOf('text="完成"') !== -1 || xmlStr.indexOf('text="发送"') !== -1) {
  472.         return true;
  473.     }
  474.     if (xmlStr.indexOf('content-desc="完成"') !== -1 || xmlStr.indexOf('content-desc="发送"') !== -1) {
  475.         return true;
  476.     }
  477.     return false;
  478. }

  479. function 查找图片预览确认按钮(xml) {
  480.     var xmlStr = "" + xml;
  481.    
  482.     var 关键词 = ["完成", "发送", "确认"];
  483.     for (var i = 0; i < 关键词.length; i++) {
  484.         var kw = 关键词[i];
  485.         var textIdx = xmlStr.indexOf('text="' + kw + '"');
  486.         if (textIdx !== -1) {
  487.             var 段 = xmlStr.substring(textIdx);
  488.             var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  489.             if (m) {
  490.                 var x = (parseInt(m[1]) + parseInt(m[3])) / 2;
  491.                 var y = (parseInt(m[2]) + parseInt(m[4])) / 2;
  492.                 print.log("✓ 图片预览确认按钮定位:text=" + kw + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  493.                 return { x: x, y: y };
  494.             }
  495.         }
  496.     }
  497.    
  498.     for (var j = 0; j < 关键词.length; j++) {
  499.         var kw2 = 关键词[j];
  500.         var descIdx = xmlStr.indexOf('content-desc="' + kw2 + '"');
  501.         if (descIdx !== -1) {
  502.             var 段2 = xmlStr.substring(descIdx);
  503.             var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  504.             if (m2) {
  505.                 var x = (parseInt(m2[1]) + parseInt(m2[3])) / 2;
  506.                 var y = (parseInt(m2[2]) + parseInt(m2[4])) / 2;
  507.                 print.log("✓ 图片预览确认按钮定位:content-desc=" + kw2 + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  508.                 return { x: x, y: y };
  509.             }
  510.         }
  511.     }
  512.    
  513.     print.log("⚠ 图片预览确认按钮使用兜底坐标(底部中间)");
  514.     return { x: 屏幕宽 * 0.5, y: 屏幕高 * 0.92 };
  515. }

  516. function 查找相册选择按钮(xml) {
  517.     var xmlStr = "" + xml;
  518.    
  519.     var 关键词列表 = ["选择", "完成", "确认", "发送", "确定"];
  520.     for (var i = 0; i < 关键词列表.length; i++) {
  521.         var kw = 关键词列表[i];
  522.         
  523.         var textPattern = new RegExp('text="' + kw + '[^"]*"[^>]*?bounds="\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]"', 'gi');
  524.         var textMatch = textPattern.exec(xmlStr);
  525.         if (textMatch) {
  526.             var x = (parseInt(textMatch[1]) + parseInt(textMatch[3])) / 2;
  527.             var y = (parseInt(textMatch[2]) + parseInt(textMatch[4])) / 2;
  528.             print.log("✓ 相册选择按钮定位:text=" + kw + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  529.             return { x: x, y: y };
  530.         }
  531.         
  532.         var descIdx = xmlStr.indexOf('content-desc="' + kw + '"');
  533.         if (descIdx !== -1) {
  534.             var 段2 = xmlStr.substring(descIdx);
  535.             var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  536.             if (m2) {
  537.                 var x = (parseInt(m2[1]) + parseInt(m2[3])) / 2;
  538.                 var y = (parseInt(m2[2]) + parseInt(m2[4])) / 2;
  539.                 print.log("✓ 相册选择按钮定位:content-desc=" + kw + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  540.                 return { x: x, y: y };
  541.             }
  542.         }
  543.     }
  544.    
  545.     var bottomButtonPattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  546.     var bottomMatch;
  547.     var 底部按钮列表 = [];
  548.     while ((bottomMatch = bottomButtonPattern.exec(xmlStr)) !== null) {
  549.         var bx1 = parseInt(bottomMatch[1]);
  550.         var by1 = parseInt(bottomMatch[2]);
  551.         var bx2 = parseInt(bottomMatch[3]);
  552.         var by2 = parseInt(bottomMatch[4]);
  553.         if (by1 >= 屏幕高 * 0.85) {
  554.             底部按钮列表.push({ x: (bx1 + bx2) / 2, y: (by1 + by2) / 2 });
  555.         }
  556.     }
  557.    
  558.     if (底部按钮列表.length > 0) {
  559.         底部按钮列表.sort(function(a, b) { return b.x - a.x; });
  560.         var 最右边按钮 = 底部按钮列表[0];
  561.         print.log("✓ 相册选择按钮定位:底部最右边按钮,坐标(" + Math.round(最右边按钮.x) + "," + Math.round(最右边按钮.y) + ")");
  562.         return { x: 最右边按钮.x, y: 最右边按钮.y };
  563.     }
  564.    
  565.     print.log("⚠ 相册选择按钮使用兜底坐标(底部)");
  566.     return { x: 屏幕宽 * 0.78, y: 屏幕高 * 0.92 };
  567. }

  568. function 查找第一张图片(xml) {
  569.     var xmlStr = "" + xml;
  570.    
  571.     if (是否在系统相册页面(xmlStr)) {
  572.         agent.shell("echo '" + xmlStr.substring(0, 5000) + "' > /sdcard/相册UI_dump.xml");
  573.         print.log("✓ 已保存相册UI XML到/sdcard/相册UI_dump.xml");
  574.         
  575.         var packageMatch = xmlStr.match(/package="([^"]+)"/);
  576.         var 当前包名 = packageMatch ? packageMatch[1] : "";
  577.         
  578.         if (当前包名 === 文心包名) {
  579.             var ugcPattern = /<node[^>]*?resource-id="[^"]*?ugc_img"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  580.             var ugcMatch;
  581.             var ugc图片列表 = [];
  582.             
  583.             while ((ugcMatch = ugcPattern.exec(xmlStr)) !== null) {
  584.                 var ix1 = parseInt(ugcMatch[1]);
  585.                 var iy1 = parseInt(ugcMatch[2]);
  586.                 var ix2 = parseInt(ugcMatch[3]);
  587.                 var iy2 = parseInt(ugcMatch[4]);
  588.                 var iw = ix2 - ix1;
  589.                 var ih = iy2 - iy1;
  590.                
  591.                 if (iw >= 100 && ih >= 100) {
  592.                     ugc图片列表.push({ x1: ix1, y1: iy1, x2: ix2, y2: iy2, x: (ix1 + ix2) / 2, y: (iy1 + iy2) / 2 });
  593.                 }
  594.             }
  595.             
  596.             if (ugc图片列表.length > 0) {
  597.                 ugc图片列表.sort(function(a, b) {
  598.                     if (a.y1 !== b.y1) return a.y1 - b.y1;
  599.                     return a.x1 - b.x1;
  600.                 });
  601.                 var 第一张图片 = ugc图片列表[0];
  602.                 print.log("✓ 文心助手内部相册找到第一张图片:坐标(" + Math.round(第一张图片.x) + "," + Math.round(第一张图片.y) + "),bounds=[" + 第一张图片.x1 + "," + 第一张图片.y1 + "][" + 第一张图片.x2 + "," + 第一张图片.y2 + "]");
  603.                 return { x: 第一张图片.x, y: 第一张图片.y };
  604.             }
  605.         }
  606.         
  607.         var nafPattern = /<node[^>]*?NAF="true"[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  608.         var nafMatch;
  609.         var NAF小圆点列表 = [];
  610.         
  611.         while ((nafMatch = nafPattern.exec(xmlStr)) !== null) {
  612.             var nx1 = parseInt(nafMatch[1]);
  613.             var ny1 = parseInt(nafMatch[2]);
  614.             var nx2 = parseInt(nafMatch[3]);
  615.             var ny2 = parseInt(nafMatch[4]);
  616.             var nw = nx2 - nx1;
  617.             var nh = ny2 - ny1;
  618.             
  619.             if (nw >= 50 && nw <= 300 && nh >= 50 && nh <= 300) {
  620.                 if (ny1 >= 400 && ny2 <= 屏幕高 - 400) {
  621.                     NAF小圆点列表.push({ x1: nx1, y1: ny1, x2: nx2, y2: ny2, x: (nx1 + nx2) / 2, y: (ny1 + ny2) / 2 });
  622.                 }
  623.             }
  624.         }
  625.         
  626.         if (NAF小圆点列表.length > 0) {
  627.             NAF小圆点列表.sort(function(a, b) {
  628.                 if (a.y1 !== b.y1) return a.y1 - b.y1;
  629.                 return a.x1 - b.x1;
  630.             });
  631.             var 选中小圆点 = NAF小圆点列表[0];
  632.             print.log("✓ ComposeView找到NAF小圆点选择框:坐标(" + Math.round(选中小圆点.x) + "," + Math.round(选中小圆点.y) + "),bounds=[" + 选中小圆点.x1 + "," + 选中小圆点.y1 + "][" + 选中小圆点.x2 + "," + 选中小圆点.y2 + "]");
  633.             return { x: 选中小圆点.x, y: 选中小圆点.y };
  634.         }
  635.         
  636.         var imageDescPattern = /<node[^>]*?content-desc="([^"]+\.(png|jpg|jpeg|gif))"[^>]*?class="android\.view\.View"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/gi;
  637.         var imgMatch;
  638.         var 图片节点列表 = [];
  639.         
  640.         while ((imgMatch = imageDescPattern.exec(xmlStr)) !== null) {
  641.             var 文件名 = imgMatch[1];
  642.             var ix1 = parseInt(imgMatch[3]);
  643.             var iy1 = parseInt(imgMatch[4]);
  644.             var ix2 = parseInt(imgMatch[5]);
  645.             var iy2 = parseInt(imgMatch[6]);
  646.             var iw = ix2 - ix1;
  647.             var ih = iy2 - iy1;
  648.             
  649.             if (iw >= 100 && ih >= 100) {
  650.                 图片节点列表.push({ 文件名: 文件名, x1: ix1, y1: iy1, x2: ix2, y2: iy2, w: iw, h: ih });
  651.             }
  652.         }
  653.         
  654.         if (图片节点列表.length > 0) {
  655.             图片节点列表.sort(function(a, b) {
  656.                 if (a.y1 !== b.y1) return a.y1 - b.y1;
  657.                 return a.x1 - b.x1;
  658.             });
  659.             var 第一张图片 = 图片节点列表[0];
  660.             print.log("✓ 找到图片:" + 第一张图片.文件名 + ",bounds=[" + 第一张图片.x1 + "," + 第一张图片.y1 + "][" + 第一张图片.x2 + "," + 第一张图片.y2 + "]");
  661.             
  662.             var 选择框X = 第一张图片.x1 + 第一张图片.w * 0.77;
  663.             var 选择框Y = 第一张图片.y1 + 第一张图片.h * 0.24;
  664.             print.log("✓ 计算小圆点选择框坐标:(" + Math.round(选择框X) + "," + Math.round(选择框Y) + ")");
  665.             return { x: 选择框X, y: 选择框Y };
  666.         }
  667.         
  668.         var clickableViewPattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  669.         var clickMatch;
  670.         var 可点击区域 = [];
  671.         while ((clickMatch = clickableViewPattern.exec(xmlStr)) !== null) {
  672.             var cx1 = parseInt(clickMatch[1]);
  673.             var cy1 = parseInt(clickMatch[2]);
  674.             var cx2 = parseInt(clickMatch[3]);
  675.             var cy2 = parseInt(clickMatch[4]);
  676.             var cw = cx2 - cx1;
  677.             var ch = cy2 - cy1;
  678.             可点击区域.push({ x1: cx1, y1: cy1, x2: cx2, y2: cy2, w: cw, h: ch, x: (cx1 + cx2) / 2, y: (cy1 + cy2) / 2 });
  679.         }
  680.         
  681.         var 图片区域内可点击 = [];
  682.         for (var k = 0; k < 可点击区域.length; k++) {
  683.             var item = 可点击区域[k];
  684.             if (item.y >= 400 && item.y <= 屏幕高 - 400) {
  685.                 图片区域内可点击.push(item);
  686.             }
  687.         }
  688.         
  689.         if (图片区域内可点击.length > 0) {
  690.             图片区域内可点击.sort(function(a, b) {
  691.                 if (a.y !== b.y) return a.y - b.y;
  692.                 return a.x - b.x;
  693.             });
  694.             var 第一个可点击 = 图片区域内可点击[0];
  695.             print.log("✓ ComposeView图片区域内第一个可点击元素:坐标(" + Math.round(第一个可点击.x) + "," + Math.round(第一个可点击.y) + ")");
  696.             return { x: 第一个可点击.x, y: 第一个可点击.y };
  697.         }

  698.         print.log("⚠ 系统相册未找到图片,输出调试信息:");
  699.         print.log("  当前包名:" + xmlStr.match(/package="([^"]+)"/)[1]);
  700.         print.log("  XML前1000字符:" + xmlStr.substring(0, 1000));
  701.         print.log("  NAF小圆点数量:" + NAF小圆点列表.length);
  702.         print.log("  图片节点数量:" + 图片节点列表.length);
  703.         
  704.         var allImgViews = xmlStr.match(/class="android\.widget\.ImageView"/g);
  705.         print.log("  全部ImageView数量:" + (allImgViews ? allImgViews.length : 0));
  706.         
  707.         return { x: 屏幕宽 * 0.25, y: 屏幕高 * 0.3 };
  708.     }

  709.     var rvPattern = /<node[^>]*?class="androidx\.recyclerview\.widget\.RecyclerView"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  710.     var rvMatch;
  711.     var 图片列表区域 = null;

  712.     while ((rvMatch = rvPattern.exec(xmlStr)) !== null) {
  713.         var rx1 = parseInt(rvMatch[1]);
  714.         var ry1 = parseInt(rvMatch[2]);
  715.         var rx2 = parseInt(rvMatch[3]);
  716.         var ry2 = parseInt(rvMatch[4]);
  717.         var 高度 = ry2 - ry1;

  718.         if (ry1 > 屏幕高 * 0.7 && 高度 > 300) {
  719.             图片列表区域 = {x1: rx1, y1: ry1, x2: rx2, y2: ry2};
  720.             print.log("✓ 找到底部图片列表RecyclerView:[" + rx1 + "," + ry1 + "][" + rx2 + "," + ry2 + "]");
  721.             break;
  722.         }
  723.     }

  724.     if (图片列表区域) {
  725.         var imgPattern = /<node[^>]*?class="android\.widget\.ImageView"[^>]*?\/?>/g;
  726.         var imgMatch;
  727.         var 候选 = [];
  728.         while ((imgMatch = imgPattern.exec(xmlStr)) !== null) {
  729.             var imgNode = imgMatch[0];
  730.             var boundsMatch = imgNode.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  731.             if (!boundsMatch) continue;
  732.             var ix1 = parseInt(boundsMatch[1]);
  733.             var iy1 = parseInt(boundsMatch[2]);
  734.             var ix2 = parseInt(boundsMatch[3]);
  735.             var iy2 = parseInt(boundsMatch[4]);
  736.             var iw = ix2 - ix1;
  737.             var ih = iy2 - iy1;

  738.             var 在区域内 = (ix1 >= 图片列表区域.x1 && ix2 <= 图片列表区域.x2 &&
  739.                             iy1 >= 图片列表区域.y1 && iy2 <= 图片列表区域.y2);
  740.             var 是大图 = (iw > 100 && ih > 100);

  741.             if (在区域内 && 是大图) {
  742.                 候选.push({
  743.                     x: (ix1 + ix2) / 2,
  744.                     y: (iy1 + iy2) / 2,
  745.                     y1: iy1,
  746.                     x1: ix1
  747.                 });
  748.             }
  749.         }

  750.         if (候选.length > 0) {
  751.             候选.sort(function(a, b) {
  752.                 if (a.y1 !== b.y1) return a.y1 - b.y1;
  753.                 return a.x1 - b.x1;
  754.             });
  755.             var 选中 = 候选[0];
  756.             print.log("✓ 第一张图片定位:底部图片列表内的ImageView,坐标(" + Math.round(选中.x) + "," + Math.round(选中.y) + ")");
  757.             return { x: 选中.x, y: 选中.y };
  758.         }
  759.     }

  760.     var imgPattern2 = /<node[^>]*?class="android\.widget\.ImageView"[^>]*?\/?>/g;
  761.     var imgMatch2;
  762.     var 候选2 = [];
  763.     while ((imgMatch2 = imgPattern2.exec(xmlStr)) !== null) {
  764.         var imgNode = imgMatch2[0];
  765.         var boundsMatch = imgNode.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  766.         if (!boundsMatch) continue;
  767.         var ix1 = parseInt(boundsMatch[1]);
  768.         var iy1 = parseInt(boundsMatch[2]);
  769.         var ix2 = parseInt(boundsMatch[3]);
  770.         var iy2 = parseInt(boundsMatch[4]);
  771.         var iw = ix2 - ix1;
  772.         var ih = iy2 - iy1;

  773.         if (iy1 > 屏幕高 * 0.7 && iw > 100 && ih > 100) {
  774.             候选2.push({
  775.                 x: (ix1 + ix2) / 2,
  776.                 y: (iy1 + iy2) / 2,
  777.                 y1: iy1,
  778.                 x1: ix1
  779.             });
  780.         }
  781.     }

  782.     if (候选2.length > 0) {
  783.         候选2.sort(function(a, b) {
  784.             if (a.y1 !== b.y1) return a.y1 - b.y1;
  785.             return a.x1 - b.x1;
  786.         });
  787.         var 选中2 = 候选2[0];
  788.         print.log("✓ 第一张图片定位:底部区域ImageView,坐标(" + Math.round(选中2.x) + "," + Math.round(选中2.y) + ")");
  789.         return { x: 选中2.x, y: 选中2.y };
  790.     }

  791.     print.log("⚠ 未找到图片,使用兜底坐标(底部第一行第一列)");
  792.     return { x: 屏幕宽 * 0.15, y: 屏幕高 * 0.85 };
  793. }

  794. function 查找发送按钮中心(xml) {
  795.     var xmlStr = "" + xml;

  796.     try {
  797.         var detects = opencv.findImagesEx('图色168638.cv');
  798.         if (detects != null && detects.length > 0) {
  799.             print.log("✓ 发送按钮定位:图色匹配");
  800.             var dStr = "" + detects[0];
  801.             print.log("图色匹配结果:" + dStr);
  802.             var m = dStr.match(/矩形区域:([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+)/);
  803.             if (m) {
  804.                 var left = parseFloat(m[1]);
  805.                 var top = parseFloat(m[2]);
  806.                 var right = parseFloat(m[3]);
  807.                 var bottom = parseFloat(m[4]);
  808.                 var centerX = (left + right) / 2;
  809.                 var centerY = (top + bottom) / 2;
  810.                 print.log("图色匹配百分比坐标:left=" + left + ", top=" + top + ", right=" + right + ", bottom=" + bottom);
  811.                 print.log("计算点击百分比:(" + centerX + "," + centerY + ")");
  812.                 agent.clickPercent(centerX, centerY);
  813.                 print.log("✓ 已点击发送按钮(图色)");
  814.                 return null;
  815.             }
  816.             print.log("⚠ 图色匹配结果格式解析失败");
  817.         }
  818.     } catch (e) {
  819.         print.log("⚠ 图色匹配失败:" + e.message);
  820.     }

  821.     var sendImgPattern = /class="android\.widget\.ImageView"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  822.     var imgMatches = [];
  823.     var imgMatch;
  824.    
  825.     while ((imgMatch = sendImgPattern.exec(xmlStr)) !== null) {
  826.         var ix1 = parseInt(imgMatch[1]);
  827.         var iy1 = parseInt(imgMatch[2]);
  828.         var ix2 = parseInt(imgMatch[3]);
  829.         var iy2 = parseInt(imgMatch[4]);
  830.         var iw = ix2 - ix1;
  831.         var ih = iy2 - iy1;
  832.         
  833.         if (iw > 50 && ih > 50 && ix1 > 屏幕宽 * 0.7 && iy1 > 屏幕高 * 0.7) {
  834.             imgMatches.push({
  835.                 x1: ix1, y1: iy1, x2: ix2, y2: iy2,
  836.                 x: (ix1 + ix2) / 2,
  837.                 y: (iy1 + iy2) / 2
  838.             });
  839.         }
  840.     }
  841.    
  842.     if (imgMatches.length > 0) {
  843.         imgMatches.sort(function(a, b) {
  844.             return b.y1 - a.y1;
  845.         });
  846.         var 发送按钮 = imgMatches[0];
  847.         print.log("✓ 发送按钮定位:输入框下方ImageView,坐标(" + Math.round(发送按钮.x) + "," + Math.round(发送按钮.y) + ")");
  848.         return 发送按钮;
  849.     }

  850.     var sendTextIdx = xmlStr.indexOf('text="发送"');
  851.     if (sendTextIdx !== -1) {
  852.         var 段 = xmlStr.substring(sendTextIdx);
  853.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  854.         if (m) {
  855.             print.log("✓ 发送按钮定位:文本匹配");
  856.             return {
  857.                 x: (parseInt(m[1]) + parseInt(m[3])) / 2,
  858.                 y: (parseInt(m[2]) + parseInt(m[4])) / 2
  859.             };
  860.         }
  861.     }

  862.     var sendDescIdx = xmlStr.indexOf('content-desc="发送"');
  863.     if (sendDescIdx !== -1) {
  864.         var 段2 = xmlStr.substring(sendDescIdx);
  865.         var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  866.         if (m2) {
  867.             print.log("✓ 发送按钮定位:content-desc匹配");
  868.             return {
  869.                 x: (parseInt(m2[1]) + parseInt(m2[3])) / 2,
  870.                 y: (parseInt(m2[2]) + parseInt(m2[4])) / 2
  871.             };
  872.         }
  873.     }

  874.     var inputKeywords = ["发消息或按住说话", "在这里提问", "接着问", "分析图片内容"];
  875.     var 输入框边界 = null;
  876.    
  877.     for (var k = 0; k < inputKeywords.length; k++) {
  878.         var inputIdx = xmlStr.indexOf('text="' + inputKeywords[k] + '"');
  879.         if (inputIdx !== -1) {
  880.             var 输入框段 = xmlStr.substring(inputIdx);
  881.             输入框边界 = 输入框段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  882.             if (输入框边界) break;
  883.         }
  884.     }
  885.    
  886.     if (!输入框边界) {
  887.         var editTextIdx = xmlStr.indexOf('class="android.widget.EditText"');
  888.         if (editTextIdx !== -1) {
  889.             var 段 = xmlStr.substring(editTextIdx);
  890.             输入框边界 = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  891.         }
  892.     }
  893.    
  894.     if (输入框边界) {
  895.         var 输入框信息 = {
  896.             x1: parseInt(输入框边界[1]),
  897.             y1: parseInt(输入框边界[2]),
  898.             x2: parseInt(输入框边界[3]),
  899.             y2: parseInt(输入框边界[4]),
  900.             centerY: (parseInt(输入框边界[2]) + parseInt(输入框边界[4])) / 2
  901.         };

  902.         var toolbarKeywords = ["魔法修图", "视频通话", "放心写", "魔法漫画"];
  903.         var 工具栏Y范围 = null;
  904.         for (var t = 0; t < toolbarKeywords.length; t++) {
  905.             var tbIdx = xmlStr.indexOf('text="' + toolbarKeywords[t] + '"');
  906.             if (tbIdx !== -1) {
  907.                 var tb段 = xmlStr.substring(tbIdx);
  908.                 var tbMatch = tb段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  909.                 if (tbMatch) {
  910.                     工具栏Y范围 = {
  911.                         y1: parseInt(tbMatch[2]),
  912.                         y2: parseInt(tbMatch[4])
  913.                     };
  914.                     break;
  915.                 }
  916.             }
  917.         }

  918.         var clickablePattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"[^>]*?\/?>/g;
  919.         var clickMatch;
  920.         var candidates = [];

  921.         while ((clickMatch = clickablePattern.exec(xmlStr)) !== null) {
  922.             var cx1 = parseInt(clickMatch[1]);
  923.             var cy1 = parseInt(clickMatch[2]);
  924.             var cx2 = parseInt(clickMatch[3]);
  925.             var cy2 = parseInt(clickMatch[4]);
  926.             var cw = cx2 - cx1;
  927.             var ch = cy2 - cy1;

  928.             var 是小按钮 = (cw < 300 && ch < 300);
  929.             var 在输入框右侧 = (cx1 > 输入框信息.x2 - 100);
  930.             var 在输入框水平行 = (cy1 >= 输入框信息.y1 - 100 && cy1 <= 输入框信息.y2 + 100);
  931.             
  932.             var 在工具栏区域 = false;
  933.             if (工具栏Y范围 && cy1 >= 工具栏Y范围.y1 && cy2 <= 工具栏Y范围.y2 + 100) {
  934.                 在工具栏区域 = true;
  935.             }

  936.             if (是小按钮 && 在输入框右侧 && 在输入框水平行 && !在工具栏区域) {
  937.                 candidates.push({
  938.                     x1: cx1, y1: cy1, x2: cx2, y2: cy2,
  939.                     x: (cx1 + cx2) / 2,
  940.                     y: (cy1 + cy2) / 2
  941.                 });
  942.             }
  943.         }

  944.         if (candidates.length > 0) {
  945.             candidates.sort(function(a, b) {
  946.                 return b.x1 - a.x1;
  947.             });
  948.             var 选中 = candidates[0];
  949.             print.log("✓ 发送按钮定位:输入框右侧clickable元素,坐标(" + Math.round(选中.x) + "," + Math.round(选中.y) + ")");
  950.             return { x: 选中.x, y: 选中.y };
  951.         }

  952.         var 预估X = 输入框信息.x2 + 100;
  953.         var 预估Y = 输入框信息.centerY;
  954.         print.log("⚠ 发送按钮使用输入框右侧兜底坐标(" + Math.round(预估X) + "," + Math.round(预估Y) + ")");
  955.         return { x: 预估X, y: 预估Y };
  956.     }

  957.     print.log("⚠ 发送按钮使用屏幕右侧兜底策略");
  958.     agent.clickPercent(0.9, 0.91);
  959.     print.log("✓ 已点击发送按钮(硬编码兜底)");
  960.     return null;
  961. }

  962. function 等待AI回答完成(发送前的最后文本, 发送前回答数量) {
  963.     var 已耗时 = 0;
  964.     var 检查间隔秒 = 1;

  965.     print.log("发送前最后AI回答:'" + 发送前的最后文本 + "',发送前回答数量:" + 发送前回答数量);

  966.     var 工具栏关键词 = ["魔法修图", "视频通话", "放心写", "魔法漫画"];
  967.     var 发送前是工具栏 = 工具栏关键词.indexOf(发送前的最后文本) !== -1;

  968.     var 检查间隔秒 = 3;
  969.     var 连续相同次数 = 0;
  970.     var 上次规范化文本 = "";

  971.     sleep.second(秒 = 5);
  972.     已耗时 += 5;

  973.     while (已耗时 < 等待回答超时秒) {
  974.         var xml = 获取UI();
  975.         var 回答列表 = 采集AI回答列表(xml);
  976.         
  977.         if (回答列表.length > 0) {
  978.             var 当前最后回答 = 回答列表[回答列表.length - 1];
  979.             var 当前提取数字 = 提取数字(当前最后回答);
  980.             var 当前规范化文本 = 当前最后回答.trim().replace(/\s+/g, " ");
  981.             
  982.             var 有新回答 = false;
  983.             var 回答数量增加 = (回答列表.length > 发送前回答数量);
  984.             
  985.             if (发送前是工具栏) {
  986.                 var 当前不是工具栏 = 工具栏关键词.indexOf(当前最后回答) === -1;
  987.                 var 有OCR内容 = 当前最后回答.length > 10;
  988.                 有新回答 = 当前不是工具栏 || 有OCR内容 || 当前提取数字 !== "";
  989.             } else {
  990.                 var 发送前规范化 = 发送前的最后文本.trim().replace(/\s+/g, " ");
  991.                 有新回答 = (当前规范化文本 !== 发送前规范化) || (当前提取数字 !== "");
  992.             }
  993.             
  994.             if (有新回答 || 回答数量增加) {
  995.                 print.log("✓ 检测到新回答(" + 已耗时 + "秒):'" + 当前最后回答 + "',提取数字:'" + 当前提取数字 + "'");
  996.                
  997.                 if (当前提取数字 !== "") {
  998.                     print.log("✓ 提取到数字,直接返回:" + 当前提取数字);
  999.                     return 当前提取数字;
  1000.                 }
  1001.                
  1002.                 if (当前规范化文本 === 上次规范化文本) {
  1003.                     连续相同次数++;
  1004.                     if (连续相同次数 >= 2) {
  1005.                         print.log("✓ 文本连续2次相同,回答完成");
  1006.                         var 最终数字 = 提取数字(当前最后回答);
  1007.                         if (最终数字 !== "") {
  1008.                             return 最终数字;
  1009.                         }
  1010.                         return 当前最后回答;
  1011.                     }
  1012.                 } else {
  1013.                     连续相同次数 = 0;
  1014.                     上次规范化文本 = 当前规范化文本;
  1015.                 }
  1016.             }
  1017.         }
  1018.         
  1019.         sleep.second(秒 = 检查间隔秒);
  1020.         已耗时 += 检查间隔秒;
  1021.     }

  1022.     print.log("⚠ 等待AI回答超时(" + 等待回答超时秒 + "秒),尝试返回当前内容");
  1023.     var xml = 获取UI();
  1024.     var 兜底列表 = 采集AI回答列表(xml);
  1025.     if (兜底列表.length > 0) {
  1026.         var 兜底文本 = 兜底列表[兜底列表.length - 1];
  1027.         print.log("✓ 超时兜底:返回当前采集到的回答:" + 兜底文本);
  1028.         return 兜底文本;
  1029.     }
  1030.     return null;
  1031. }

  1032. // ========== 主流程开始 ==========

  1033. function 主流程() {
  1034.     // 步骤1:全屏截图(B站验证码页面)
  1035.     print.log("\n========== 步骤1:全屏截图B站验证码 ==========");
  1036.     var 截图成功 = 全屏截图(截图保存路径);
  1037.     if (!截图成功) {
  1038.         print.log("✗ 截图失败,退出流程");
  1039.         print.log("===== 文心识别验证码拖动B站流程结束 =====");
  1040.         return;
  1041.     }

  1042.     // 步骤2:启动文心助手APP
  1043.     print.log("\n========== 步骤2:启动文心助手APP ==========");
  1044.     try {
  1045.         app.openApp(文心包名);
  1046.         print.log("✓ 已启动文心助手");
  1047.     } catch (e) {
  1048.         print.log("⚠ 启动失败:" + e.message);
  1049.     }
  1050.     sleep.second(秒 = 5);

  1051.     // 步骤3:确认进入对话页面(支持两种打开形式)
  1052.     print.log("\n========== 步骤3:确认进入对话页面 ==========");
  1053.     var xml = 获取UI();
  1054.     var 打开形式 = 判断文心打开形式(xml);
  1055.     var 进入对话成功 = false;
  1056.    
  1057.     if (打开形式 === "对话页") {
  1058.         print.log("✓ 文心APP直接打开到对话页面,无需额外操作");
  1059.         进入对话成功 = true;
  1060.     } else if (打开形式 === "列表页") {
  1061.         print.log("✓ 文心APP打开到对话列表页面,需要点击进入对话");
  1062.         var wenxinIdx = xml.indexOf('text="文心"');
  1063.         if (wenxinIdx !== -1) {
  1064.             var 文心段 = xml.substring(wenxinIdx);
  1065.             var wxBounds = 文心段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  1066.             if (wxBounds) {
  1067.                 var wxX = (parseInt(wxBounds[1]) + parseInt(wxBounds[3])) / 2;
  1068.                 var wxY = (parseInt(wxBounds[2]) + parseInt(wxBounds[4])) / 2;
  1069.                 agent.click(wxX, wxY);
  1070.                 print.log("✓ 已点击文心对话,坐标(" + Math.round(wxX) + "," + Math.round(wxY) + ")");
  1071.                 sleep.second(秒 = 3);
  1072.             } else {
  1073.                 agent.clickPercent(0.3, 0.15);
  1074.                 print.log("✓ 已点击文心对话(兜底坐标)");
  1075.                 sleep.second(秒 = 3);
  1076.             }
  1077.         } else {
  1078.             agent.clickPercent(0.3, 0.15);
  1079.             print.log("✓ 已点击文心对话(兜底坐标)");
  1080.             sleep.second(秒 = 3);
  1081.         }
  1082.         
  1083.         xml = 获取UI();
  1084.         打开形式 = 判断文心打开形式(xml);
  1085.         if (打开形式 === "对话页") {
  1086.             print.log("✓ 成功进入对话页面");
  1087.             进入对话成功 = true;
  1088.         } else {
  1089.             print.log("⚠ 点击后仍未进入对话页面,再次尝试");
  1090.             agent.clickPercent(0.3, 0.15);
  1091.             sleep.second(秒 = 3);
  1092.             xml = 获取UI();
  1093.             打开形式 = 判断文心打开形式(xml);
  1094.             if (打开形式 === "对话页") {
  1095.                 print.log("✓ 第二次尝试成功进入对话页面");
  1096.                 进入对话成功 = true;
  1097.             }
  1098.         }
  1099.     } else {
  1100.         print.log("⚠ 文心APP打开到未知页面,等待3秒后重试");
  1101.         sleep.second(秒 = 3);
  1102.         xml = 获取UI();
  1103.         打开形式 = 判断文心打开形式(xml);
  1104.         
  1105.         if (打开形式 === "对话页") {
  1106.             print.log("✓ 等待后自动进入对话页面");
  1107.             进入对话成功 = true;
  1108.         } else if (打开形式 === "列表页") {
  1109.             print.log("✓ 等待后进入对话列表页面,点击进入对话");
  1110.             agent.clickPercent(0.3, 0.15);
  1111.             print.log("✓ 已点击文心对话(兜底坐标)");
  1112.             sleep.second(秒 = 3);
  1113.             xml = 获取UI();
  1114.             if (判断文心打开形式(xml) === "对话页") {
  1115.                 print.log("✓ 点击后成功进入对话页面");
  1116.                 进入对话成功 = true;
  1117.             }
  1118.         }
  1119.     }
  1120.    
  1121.     if (进入对话成功) {
  1122.         print.log("✓ 已成功进入文心对话页面");
  1123.     } else {
  1124.         print.log("⚠ 多次尝试仍未进入对话页面,继续后续步骤");
  1125.     }

  1126.     // 步骤4:记录发送前的最后一条AI回答和数量
  1127.     var 发送前回答列表 = 采集AI回答列表(xml);
  1128.     var 发送前回答数量 = 发送前回答列表.length;
  1129.     var 发送前最后文本 = "";
  1130.     if (发送前回答列表.length > 0) {
  1131.         发送前最后文本 = 发送前回答列表[发送前回答列表.length - 1];
  1132.     }
  1133.     print.log("✓ 发送前回答数量:" + 发送前回答数量 + ",最后文本:'" + 发送前最后文本 + "'");

  1134.     // 步骤5:点击加号按钮打开附件菜单
  1135.     print.log("\n========== 步骤5:点击加号按钮打开附件菜单 ==========");
  1136.     var 加号按钮 = 查找加号按钮(xml);
  1137.     agent.click(加号按钮.x, 加号按钮.y);
  1138.     print.log("✓ 已点击加号按钮,坐标(" + Math.round(加号按钮.x) + "," + Math.round(加号按钮.y) + ")");
  1139.     sleep.second(秒 = 2);

  1140.     // 步骤6:选择相册或图片
  1141.     print.log("\n========== 步骤6:选择相册或图片 ==========");
  1142.     var 相册选择成功 = false;
  1143.     var 尝试次数 = 0;
  1144.     while (!相册选择成功 && 尝试次数 < 5) {
  1145.         尝试次数++;
  1146.         xml = 获取UI();
  1147.         
  1148.         if (是否在系统相册页面(xml)) {
  1149.             print.log("✓ 已进入系统相册页面");
  1150.             相册选择成功 = true;
  1151.             break;
  1152.         }
  1153.         
  1154.         var 相册选项 = 查找相册选项(xml);
  1155.         if (相册选项) {
  1156.             agent.click(相册选项.x, 相册选项.y);
  1157.             print.log("✓ 已点击相册选项,坐标(" + Math.round(相册选项.x) + "," + Math.round(相册选项.y) + ")");
  1158.             sleep.second(秒 = 2);
  1159.             相册选择成功 = true;
  1160.             break;
  1161.         }
  1162.         
  1163.         var imgCount = (xml.match(/class="android\.widget\.ImageView"/g) || []).length;
  1164.         if (imgCount >= 4) {
  1165.             print.log("✓ 加号菜单底部已显示图片列表(检测到" + imgCount + "个图片)");
  1166.             相册选择成功 = true;
  1167.             break;
  1168.         }
  1169.         
  1170.         print.log("⚠ 第" + 尝试次数 + "次尝试:未找到相册选项,等待重试");
  1171.         sleep.second(秒 = 1);
  1172.     }

  1173.     // 步骤7:选择第一张图片(处理系统相册和图片预览页面)
  1174.     print.log("\n========== 步骤7:选择第一张图片 ==========");
  1175.     var 图片选择成功 = false;
  1176.     var 图片尝试次数 = 0;
  1177.     while (!图片选择成功 && 图片尝试次数 < 10) {
  1178.         图片尝试次数++;
  1179.         xml = 获取UI();
  1180.         
  1181.         if (图片尝试次数 === 1) {
  1182.             var pkgMatch = xml.match(/package="([^"]+)"/);
  1183.             print.log("调试:当前包名=" + (pkgMatch ? pkgMatch[1] : "未知"));
  1184.             print.log("调试:XML前300字符=" + xml.substring(0, 300));
  1185.             print.log("调试:是否有接着问=" + (xml.indexOf("接着问") !== -1));
  1186.             var dbgImgCount = (xml.match(/class="android\.widget\.ImageView"/g) || []).length;
  1187.             print.log("调试:ImageView数量=" + dbgImgCount);
  1188.         }
  1189.         
  1190.         if (是否在图片预览页面(xml)) {
  1191.             var 确认按钮 = 查找图片预览确认按钮(xml);
  1192.             agent.click(确认按钮.x, 确认按钮.y);
  1193.             print.log("✓ 已点击图片预览确认按钮,坐标(" + Math.round(确认按钮.x) + "," + Math.round(确认按钮.y) + ")");
  1194.             图片选择成功 = true;
  1195.             sleep.second(秒 = 3);
  1196.             break;
  1197.         }
  1198.         
  1199.         if (是否在系统相册页面(xml)) {
  1200.             var 第一张图片 = 查找第一张图片(xml);
  1201.             if (第一张图片) {
  1202.                 agent.click(第一张图片.x, 第一张图片.y);
  1203.                 print.log("✓ 已点击第一张图片,坐标(" + Math.round(第一张图片.x) + "," + Math.round(第一张图片.y) + ")");
  1204.                 sleep.second(秒 = 2);
  1205.                
  1206.                 var pkgMatch = xml.match(/package="([^"]+)"/);
  1207.                 var 当前包名 = pkgMatch ? pkgMatch[1] : "";
  1208.                
  1209.                 if (当前包名 === 文心包名) {
  1210.                     xml = 获取UI();
  1211.                     
  1212.                     var 确认按钮 = 查找图片预览确认按钮(xml);
  1213.                     if (确认按钮) {
  1214.                         agent.click(确认按钮.x, 确认按钮.y);
  1215.                         print.log("✓ 文心助手内部相册:点击确认按钮,坐标(" + Math.round(确认按钮.x) + "," + Math.round(确认按钮.y) + ")");
  1216.                     } else {
  1217.                         var 完成按钮Idx = xml.indexOf('text="完成"');
  1218.                         if (完成按钮Idx !== -1) {
  1219.                             var 完成段 = xml.substring(完成按钮Idx);
  1220.                             var 完成匹配 = 完成段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  1221.                             if (完成匹配) {
  1222.                                 var 完成X = (parseInt(完成匹配[1]) + parseInt(完成匹配[3])) / 2;
  1223.                                 var 完成Y = (parseInt(完成匹配[2]) + parseInt(完成匹配[4])) / 2;
  1224.                                 agent.click(完成X, 完成Y);
  1225.                                 print.log("✓ 文心助手内部相册:点击完成按钮,坐标(" + Math.round(完成X) + "," + Math.round(完成Y) + ")");
  1226.                             }
  1227.                         }
  1228.                     }
  1229.                     
  1230.                     图片选择成功 = true;
  1231.                     sleep.second(秒 = 3);
  1232.                     break;
  1233.                 }
  1234.                
  1235.                 xml = 获取UI();
  1236.                 var 选择按钮 = 查找相册选择按钮(xml);
  1237.                 if (选择按钮) {
  1238.                     agent.click(选择按钮.x, 选择按钮.y);
  1239.                     print.log("✓ 已点击选择按钮,坐标(" + Math.round(选择按钮.x) + "," + Math.round(选择按钮.y) + ")");
  1240.                     图片选择成功 = true;
  1241.                     sleep.second(秒 = 3);
  1242.                     break;
  1243.                 } else {
  1244.                     print.log("⚠ 第" + 图片尝试次数 + "次:未找到选择按钮,重新获取XML重试");
  1245.                     sleep.second(秒 = 1);
  1246.                     continue;
  1247.                 }
  1248.             } else {
  1249.                 print.log("⚠ 系统相册未找到图片");
  1250.                 sleep.second(秒 = 1);
  1251.                 continue;
  1252.             }
  1253.         }
  1254.         
  1255.         print.log("⚠ 第" + 图片尝试次数 + "次尝试:未检测到相册页面,等待重试");
  1256.         sleep.second(秒 = 1);
  1257.     }

  1258.     // 步骤8:等待图片添加到输入区域(等待回到文心对话页面)
  1259.     print.log("\n========== 步骤8:等待图片添加到输入区域 ==========");
  1260.     var 图片添加成功 = false;
  1261.     var 等待尝试次数 = 0;
  1262.     while (!图片添加成功 && 等待尝试次数 < 10) {
  1263.         等待尝试次数++;
  1264.         xml = 获取UI();
  1265.         
  1266.         var packageMatch = xml.match(/package="([^"]+)"/);
  1267.         if (packageMatch && packageMatch[1] === 文心包名) {
  1268.             print.log("✓ 已回到文心对话页面");
  1269.             
  1270.             var hasInput = xml.indexOf('text="在这里提问"') !== -1 ||
  1271.                           xml.indexOf('text="接着问"') !== -1 ||
  1272.                           xml.indexOf('text="分析图片内容"') !== -1;
  1273.             
  1274.             var hasImagePreview = xml.indexOf('class="android.widget.HorizontalScrollView"') !== -1 &&
  1275.                                 xml.indexOf('class="android.widget.FrameLayout"') !== -1;
  1276.             
  1277.             if (hasInput || hasImagePreview) {
  1278.                 print.log("✓ 图片已添加到输入区域");
  1279.                 图片添加成功 = true;
  1280.                 break;
  1281.             }
  1282.         }
  1283.         
  1284.         print.log("⚠ 第" + 等待尝试次数 + "次尝试:图片尚未添加,等待重试");
  1285.         sleep.second(秒 = 1);
  1286.     }
  1287.    
  1288.     if (!图片添加成功) {
  1289.         print.log("⚠ 多次等待图片未添加,继续后续步骤");
  1290.     }

  1291.     // 步骤9:粘贴文字询问拖动距离
  1292.     print.log("\n========== 步骤9:粘贴文字询问拖动距离 ==========");
  1293.     xml = 获取UI();
  1294.     var 输入框 = 查找输入框中心(xml);
  1295.     var AI回答 = null;
  1296.     if (输入框) {
  1297.         agent.click(输入框.x, 输入框.y);
  1298.         sleep.second(秒 = 1);
  1299.         
  1300.         var hasDefaultText = xml.indexOf('text="分析图片内容"') !== -1;
  1301.         if (hasDefaultText) {
  1302.             agent.shell("input keyevent 112");
  1303.             sleep.millisecond(毫秒 = 500);
  1304.             agent.shell("input keyevent 112");
  1305.             sleep.millisecond(毫秒 = 500);
  1306.             agent.shell("input keyevent 112");
  1307.             sleep.millisecond(毫秒 = 500);
  1308.             agent.shell("input keyevent 67");
  1309.             sleep.millisecond(毫秒 = 300);
  1310.             agent.shell("input keyevent 67");
  1311.             sleep.millisecond(毫秒 = 300);
  1312.             agent.shell("input keyevent 67");
  1313.             sleep.millisecond(毫秒 = 300);
  1314.             agent.shell("input keyevent 67");
  1315.             sleep.millisecond(毫秒 = 300);
  1316.             agent.shell("input keyevent 67");
  1317.             sleep.millisecond(毫秒 = 300);
  1318.             print.log("✓ 已清除默认文本'分析图片内容'");
  1319.         }
  1320.         
  1321.         粘贴文本(提问话术);
  1322.         print.log("✓ 已粘贴文本:" + 提问话术);
  1323.         sleep.second(秒 = 2);

  1324.         // 步骤10:发送图片和文字
  1325.         print.log("\n========== 步骤10:发送图片和文字 ==========");
  1326.         xml = 获取UI();
  1327.         var 发送按钮 = 查找发送按钮中心(xml);
  1328.         if (发送按钮) {
  1329.             agent.click(发送按钮.x, 发送按钮.y);
  1330.             print.log("✓ 已点击发送按钮,坐标(" + Math.round(发送按钮.x) + "," + Math.round(发送按钮.y) + ")");
  1331.             agent.shell("input keyevent 66");
  1332.             print.log("✓ 已按回车键发送");
  1333.         }
  1334.         if (!发送按钮) {
  1335.             agent.shell("input keyevent 66");
  1336.             print.log("✓ 已按回车键发送");
  1337.         }
  1338.         sleep.second(秒 = 25);

  1339.         // 步骤11:等待文心AI回答
  1340.         print.log("\n========== 步骤11:等待文心AI回答 ==========");
  1341.         xml = 获取UI();
  1342.         var 发送前实际回答 = 获取当前最后AI回答(xml);
  1343.         var 发送前实际数量 = 采集AI回答列表(xml).length;
  1344.         print.log("发送前重新检测:最后回答='" + 发送前实际回答 + "',数量=" + 发送前实际数量);
  1345.         AI回答 = 等待AI回答完成(发送前实际回答, 发送前实际数量);
  1346.     } else {
  1347.         print.log("⚠ 未找到输入框");
  1348.     }
  1349.    
  1350.     if (!AI回答) {
  1351.         print.log("✗ 未获取到AI回答");
  1352.         print.log("===== 文心识别验证码拖动B站流程结束 =====");
  1353.         return;
  1354.     }

  1355.     print.log("\n✓ 采集到AI回答");
  1356.     print.log("--- 采集内容开始 ---");
  1357.     print.log(AI回答);
  1358.     print.log("--- 采集内容结束 ---");

  1359.     // 步骤12:解析拖动距离坐标
  1360.     print.log("\n========== 步骤12:解析拖动距离坐标 ==========");
  1361.     print.log("✓ AI原始回答:'" + AI回答 + "'");
  1362.    
  1363.     var 所有数字 = AI回答.match(/\d+/g);
  1364.     var 拖动距离像素 = null;
  1365.     var AI图像宽度 = null;
  1366.    
  1367.     if (所有数字 && 所有数字.length >= 2) {
  1368.         var 数字列表 = [];
  1369.         for (var i = 0; i < 所有数字.length; i++) {
  1370.             数字列表.push(parseInt(所有数字[i]));
  1371.         }
  1372.         print.log("✓ 提取到所有数字:" + 数字列表.join(", "));
  1373.         
  1374.         if (数字列表.length >= 5) {
  1375.             var x1 = 数字列表[0];
  1376.             var y1 = 数字列表[1];
  1377.             var x2 = 数字列表[2];
  1378.             var y2 = 数字列表[3];
  1379.             AI图像宽度 = 数字列表[4];
  1380.             拖动距离像素 = Math.abs(x2 - x1);
  1381.             print.log("✓ 识别到两组坐标+图像宽度:(" + x1 + "," + y1 + ") 和 (" + x2 + "," + y2 + "),图像宽度=" + AI图像宽度);
  1382.             print.log("✓ 计算拖动距离:|x2 - x1| = |" + x2 + " - " + x1 + "| = " + 拖动距离像素);
  1383.         } else if (数字列表.length >= 4) {
  1384.             var x1 = 数字列表[0];
  1385.             var y1 = 数字列表[1];
  1386.             var x2 = 数字列表[2];
  1387.             var y2 = 数字列表[3];
  1388.             拖动距离像素 = Math.abs(x2 - x1);
  1389.             AI图像宽度 = Math.max(x1, x2) + 100;
  1390.             print.log("✓ 识别到两组坐标格式:(" + x1 + "," + y1 + ") 和 (" + x2 + "," + y2 + ")");
  1391.             print.log("✓ 计算拖动距离:|x2 - x1| = |" + x2 + " - " + x1 + "| = " + 拖动距离像素);
  1392.             print.log("✓ 估算图像宽度:max(x1,x2)+100 = " + AI图像宽度);
  1393.         } else if (数字列表.length >= 2) {
  1394.             var 坐标匹配 = AI回答.match(/(\d+)\s*[,,]\s*(\d+)/);
  1395.             if (坐标匹配) {
  1396.                 var cx1 = parseInt(坐标匹配[1]);
  1397.                 var cx2 = parseInt(坐标匹配[2]);
  1398.                 拖动距离像素 = Math.abs(cx2 - cx1);
  1399.                 AI图像宽度 = Math.max(cx1, cx2) + 100;
  1400.                 print.log("✓ 识别到坐标格式:(" + cx1 + "," + cx2 + "),计算距离:" + 拖动距离像素);
  1401.             } else {
  1402.                 拖动距离像素 = 数字列表[0];
  1403.                 print.log("✓ 提取到单个数字(拖动距离):" + 拖动距离像素);
  1404.             }
  1405.         } else {
  1406.             拖动距离像素 = 数字列表[0];
  1407.             print.log("✓ 提取到单个数字(拖动距离):" + 拖动距离像素);
  1408.         }
  1409.     } else if (所有数字 && 所有数字.length === 1) {
  1410.         拖动距离像素 = parseInt(所有数字[0]);
  1411.         print.log("✓ 提取到单个数字(拖动距离):" + 拖动距离像素);
  1412.     } else {
  1413.         print.log("✗ 未找到有效的拖动距离");
  1414.         print.log("===== 文心识别验证码拖动B站流程结束 =====");
  1415.         return;
  1416.     }
  1417.    
  1418.     var 图像缩放系数 = 1.0;
  1419.     if (拖动距离像素 < 30) {
  1420.         print.log("⚠ 提取到的拖动距离过小(" + 拖动距离像素 + "),可能是OCR识别错误,跳过缩放补偿");
  1421.     } else if (AI图像宽度 && AI图像宽度 > 0 && AI图像宽度 < 屏幕宽) {
  1422.         图像缩放系数 = 屏幕宽 / AI图像宽度;
  1423.         if (图像缩放系数 > 5) {
  1424.             图像缩放系数 = 1.0;
  1425.         } else {
  1426.             拖动距离像素 = Math.round(拖动距离像素 * 图像缩放系数);
  1427.             print.log("✓ 图像缩放补偿:AI图像宽度=" + AI图像宽度 + ",屏幕宽=" + 屏幕宽);
  1428.             print.log("✓ 缩放系数=" + 图像缩放系数.toFixed(2) + ",补偿后拖动距离=" + 拖动距离像素);
  1429.         }
  1430.     } else {
  1431.         图像缩放系数 = 屏幕宽 / 750;
  1432.         拖动距离像素 = Math.round(拖动距离像素 * 图像缩放系数);
  1433.         print.log("✓ 单数字模式补偿:假设AI图像宽度≈750,缩放系数=" + 图像缩放系数.toFixed(2));
  1434.         print.log("✓ 补偿后拖动距离=" + 拖动距离像素);
  1435.     }
  1436.    
  1437.     验证码滑块距离 = {
  1438.         x: 拖动距离像素,
  1439.         y: 0
  1440.     };

  1441.     // 步骤13:切换回B站并拖动滑块
  1442.     print.log("\n========== 步骤13:切换回B站并拖动滑块 ==========");
  1443.    
  1444.     agent.shell("input keyevent 187");
  1445.     print.log("✓ 已按后台键打开任务列表");
  1446.     sleep.second(秒 = 2);
  1447.    
  1448.     xml = 获取UI();
  1449.     var biliIdx = xml.indexOf('哔哩哔哩');
  1450.     if (biliIdx === -1) {
  1451.         biliIdx = xml.indexOf('bilibili');
  1452.     }
  1453.     if (biliIdx === -1) {
  1454.         biliIdx = xml.indexOf('B站');
  1455.     }
  1456.    
  1457.     if (biliIdx !== -1) {
  1458.         var 段 = xml.substring(biliIdx);
  1459.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  1460.         if (m) {
  1461.             var clickX = (parseInt(m[1]) + parseInt(m[3])) / 2;
  1462.             var clickY = (parseInt(m[2]) + parseInt(m[4])) / 2;
  1463.             agent.click(clickX, clickY);
  1464.             print.log("✓ 已点击B站任务卡片,坐标(" + Math.round(clickX) + "," + Math.round(clickY) + ")");
  1465.         }
  1466.     } else {
  1467.         print.log("⚠ 未找到B站任务卡片,尝试直接打开");
  1468.         try {
  1469.             app.openApp(B站包名);
  1470.             print.log("✓ 已打开B站");
  1471.         } catch (e) {
  1472.             print.log("⚠ 打开B站失败:" + e.message);
  1473.         }
  1474.     }
  1475.     sleep.second(秒 = 3);

  1476.     xml = 获取UI();
  1477.     var 验证码区域左边界 = 屏幕宽 * 0.15;
  1478.    
  1479.     var 滑块轨道匹配 = xml.match(/<node[^>]*?text="拖动滑块完成拼图"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  1480.     if (滑块轨道匹配) {
  1481.         验证码区域左边界 = parseInt(滑块轨道匹配[1]);
  1482.     }

  1483.     var 拖动距离 = 验证码滑块距离.x * 滑块校准系数;

  1484.     var startX = 验证码区域左边界 + 50;
  1485.     var startY = 屏幕高 * 0.42;
  1486.     var endX = startX + 拖动距离;
  1487.     var endY = startY;

  1488.     print.log("✓ 验证码区域左边界: " + 验证码区域左边界 + ", 拖动距离: " + 拖动距离);
  1489.     agent.swip(startX, startY, endX, endY, 2000);
  1490.     print.log("✓ 已拖动滑块,起点(" + Math.round(startX) + "," + Math.round(startY) + "),终点(" + Math.round(endX) + "," + Math.round(endY) + ")");
  1491. }

  1492. 主流程();

  1493. print.log("\n===== 文心识别验证码拖动B站流程结束 =====");
复制代码







欢迎光临 自动发帖软件 (http://www.fatiegongju.com/) Powered by Discuz! X3.2