自动截图并发送给DEEPSEEK识别示例过程

380

主题

193

回帖

2397

积分

管理员

积分
2397
自动截图并发送给DEEPSEEK识别示例过程

1.png

2.png

3.png

4.png

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

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

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

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

  17. var 提问话术 = "请帮我分析这张图片,告诉我左边的方块需要向右移动多少像素才能和右边的缺口对齐,只回复座标数字就行了。";

  18. // ========== 获取设备信息 ==========
  19. var 屏幕宽 = screen.getScreenWidth();
  20. var 屏幕高 = screen.getScreenHeight();
  21. var 验证码滑块距离 = null;
  22. print.log("屏幕尺寸:" + 屏幕宽 + " x " + 屏幕高);
  23. try {
  24.     var 代理状态 = agent.isOpen();
  25.     print.log("代理状态:" + (代理状态 ? "已开启" : "未开启"));
  26. } catch (e) {
  27.     print.log("代理状态检查失败:" + e.message);
  28. }

  29. // ========== 工具函数 ==========

  30. function 获取UI() {
  31.     var xml = agent.getXml();
  32.     return "" + xml;
  33. }

  34. function 字符串长度(s) {
  35.     var str = "" + s;
  36.     return str.length;
  37. }

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

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

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

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

  145. function 采集AI回答列表(xml) {
  146.     var xmlStr = "" + xml;
  147.     var 回答列表 = [];

  148.     var ocr文本 = OCR识别屏幕区域(xml);
  149.     if (ocr文本 && 字符串长度(ocr文本) > 1) {
  150.         回答列表.push(ocr文本);
  151.         print.log("✓ OCR识别到屏幕文本");
  152.         print.log("--- OCR结果开始 ---");
  153.         print.log(ocr文本);
  154.         print.log("--- OCR结果结束 ---");
  155.         
  156.         var ocr数字 = 提取数字(ocr文本);
  157.         if (ocr数字) {
  158.             print.log("✓ 从OCR结果中提取到数字:" + ocr数字);
  159.             回答列表.push(ocr数字);
  160.         }
  161.     }

  162.     var textViewPattern = /<node[^>]*?text="([^"]+)"[^>]*?class="android\.widget\.TextView"[^>]*?\/?>/g;
  163.     var tvMatch;
  164.     var 跳过顶部区域 = true;
  165.     while ((tvMatch = textViewPattern.exec(xmlStr)) !== null) {
  166.         if (tvMatch[1] && 字符串长度(tvMatch[1]) > 1) {
  167.             var 原始文本 = tvMatch[1];
  168.             var 解码文本 = 解码HTML实体(原始文本);
  169.             
  170.             if (解码文本.includes("使用识图模式开始对话") ||
  171.                 解码文本.includes("图片理解功能内测中") ||
  172.                 解码文本.includes("快速模式") ||
  173.                 解码文本.includes("专家模式") ||
  174.                 解码文本.includes("识图模式") ||
  175.                 解码文本.includes("拍照") ||
  176.                 解码文本.includes("相册") ||
  177.                 解码文本.includes("文件") ||
  178.                 解码文本.includes("发消息或按住说话") ||
  179.                 解码文本.includes("深度思考")) {
  180.                 continue;
  181.             }
  182.             
  183.             if (!回答列表.includes(解码文本)) {
  184.                 回答列表.push(解码文本);
  185.                 print.log("✓ 在TextView中找到文本: '" + 解码文本 + "'");
  186.             }
  187.         }
  188.     }

  189.     if (回答列表.length === 0) {
  190.         print.log("⚠ 未找到AI回答节点");
  191.     } else {
  192.         print.log("✓ 采集到" + 回答列表.length + "条AI回答");
  193.     }

  194.     return 回答列表;
  195. }

  196. function 全屏截图(保存路径) {
  197.     try {
  198.         var result = agent.shell("screencap -p " + 保存路径);
  199.         print.log("✓ 截图命令执行:" + result);
  200.         
  201.         var lsResult = agent.shell("ls -la " + 保存路径);
  202.         print.log("✓ 截图文件检查:" + lsResult);
  203.         
  204.         return true;
  205.     } catch (e) {
  206.         print.log("⚠ 截图失败:" + e.message);
  207.         return false;
  208.     }
  209. }

  210. function 判断DEEPK打开形式(xml) {
  211.     var xmlStr = "" + xml;
  212.    
  213.     var hasInput = xmlStr.indexOf('text="发消息或按住说话"') !== -1;
  214.     var hasPhoto = xmlStr.indexOf('text="拍照"') !== -1;
  215.     var hasAlbum = xmlStr.indexOf('text="相册"') !== -1;
  216.     var hasFile = xmlStr.indexOf('text="文件"') !== -1;
  217.    
  218.     if (hasInput && (hasPhoto || hasAlbum || hasFile)) {
  219.         print.log("✓ DEEPSEEK APP打开形式:对话页面");
  220.         return "对话页";
  221.     }
  222.    
  223.     print.log("⚠ DEEPSEEK APP打开形式:未知页面");
  224.     return "未知";
  225. }

  226. function 开启新对话(xml) {
  227.     var xmlStr = "" + xml;
  228.    
  229.     var newChatIdx = xmlStr.indexOf('content-desc="开启新对话"');
  230.     if (newChatIdx !== -1) {
  231.         var 段 = xmlStr.substring(newChatIdx);
  232.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  233.         if (m) {
  234.             var x = (parseInt(m[1]) + parseInt(m[3])) / 2;
  235.             var y = (parseInt(m[2]) + parseInt(m[4])) / 2;
  236.             agent.click(x, y);
  237.             print.log("✓ 已点击开启新对话按钮,坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  238.             sleep.second(秒 = 3);
  239.             return true;
  240.         }
  241.     }
  242.    
  243.     var rightButtonPattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  244.     var rbMatch;
  245.     var 右上角按钮 = [];
  246.     while ((rbMatch = rightButtonPattern.exec(xmlStr)) !== null) {
  247.         var bx1 = parseInt(rbMatch[1]);
  248.         var by1 = parseInt(rbMatch[2]);
  249.         if (bx1 > 屏幕宽 * 0.85 && by1 > 100 && by1 < 400) {
  250.             右上角按钮.push({ x: (bx1 + parseInt(rbMatch[3])) / 2, y: (by1 + parseInt(rbMatch[4])) / 2 });
  251.         }
  252.     }
  253.    
  254.     if (右上角按钮.length > 0) {
  255.         右上角按钮.sort(function(a, b) { return a.x - b.x; });
  256.         var 最右边按钮 = 右上角按钮[右上角按钮.length - 1];
  257.         agent.click(最右边按钮.x, 最右边按钮.y);
  258.         print.log("✓ 已点击右上角按钮开启新对话,坐标(" + Math.round(最右边按钮.x) + "," + Math.round(最右边按钮.y) + ")");
  259.         sleep.second(秒 = 3);
  260.         return true;
  261.     }
  262.    
  263.     print.log("⚠ 未找到开启新对话按钮");
  264.     return false;
  265. }

  266. function 确保识图模式开启(xml) {
  267.     var xmlStr = "" + xml;
  268.    
  269.     var pattern = /text="识图模式"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/;
  270.     var match = pattern.exec(xmlStr);
  271.     if (match) {
  272.         var x1 = parseInt(match[1]);
  273.         var y1 = parseInt(match[2]);
  274.         var x2 = parseInt(match[3]);
  275.         var y2 = parseInt(match[4]);
  276.         var x = (x1 + x2) / 2;
  277.         var y = (y1 + y2) / 2;
  278.         
  279.         var checkedPattern = /text="识图模式"[^>]*?checked="([^"]+)"/;
  280.         var checkedMatch = checkedPattern.exec(xmlStr);
  281.         if (checkedMatch && checkedMatch[1] === "true") {
  282.             print.log("✓ 识图模式已开启");
  283.             return true;
  284.         } else {
  285.             agent.click(x, y);
  286.             print.log("✓ 已点击识图模式按钮开启识图功能,坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  287.             sleep.second(秒 = 2);
  288.             return true;
  289.         }
  290.     }
  291.    
  292.     var visualModePattern = /<node[^>]*?checkable="true"[^>]*?checked="([^"]+)"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  293.     var vmMatch;
  294.     var 模式按钮列表 = [];
  295.     while ((vmMatch = visualModePattern.exec(xmlStr)) !== null) {
  296.         var 已选中 = vmMatch[1];
  297.         var mx1 = parseInt(vmMatch[2]);
  298.         var my1 = parseInt(vmMatch[3]);
  299.         var mx2 = parseInt(vmMatch[4]);
  300.         var my2 = parseInt(vmMatch[5]);
  301.         if (my1 > 屏幕高 * 0.3 && my2 < 屏幕高 * 0.5) {
  302.             模式按钮列表.push({ checked: 已选中 === "true", x: (mx1 + mx2) / 2, y: (my1 + my2) / 2, x1: mx1 });
  303.         }
  304.     }
  305.    
  306.     if (模式按钮列表.length >= 3) {
  307.         模式按钮列表.sort(function(a, b) { return a.x1 - b.x1; });
  308.         var 第三个按钮 = 模式按钮列表[2];
  309.         if (第三个按钮.checked) {
  310.             print.log("✓ 识图模式(第三个按钮)已开启");
  311.             return true;
  312.         } else {
  313.             agent.click(第三个按钮.x, 第三个按钮.y);
  314.             print.log("✓ 已点击第三个模式按钮开启识图功能,坐标(" + Math.round(第三个按钮.x) + "," + Math.round(第三个按钮.y) + ")");
  315.             sleep.second(秒 = 2);
  316.             return true;
  317.         }
  318.     }
  319.    
  320.     print.log("⚠ 未找到识图模式按钮,跳过此步骤");
  321.     return false;
  322. }

  323. function 查找输入框中心(xml) {
  324.     var xmlStr = "" + xml;
  325.    
  326.     var inputIdx = xmlStr.indexOf('text="发消息或按住说话"');
  327.     if (inputIdx !== -1) {
  328.         var 段 = xmlStr.substring(inputIdx);
  329.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  330.         if (m) {
  331.             var x1 = parseInt(m[1]);
  332.             var y1 = parseInt(m[2]);
  333.             var x2 = parseInt(m[3]);
  334.             var y2 = parseInt(m[4]);
  335.             print.log("✓ 输入框定位:text=发消息或按住说话,bounds=[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "]");
  336.             return {
  337.                 x: (x1 + x2) / 2,
  338.                 y: (y1 + y2) / 2
  339.             };
  340.         }
  341.     }

  342.     var editTextIdx = xmlStr.indexOf('class="android.widget.EditText"');
  343.     if (editTextIdx !== -1) {
  344.         var 段2 = xmlStr.substring(editTextIdx);
  345.         var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  346.         if (m2) {
  347.             var x1 = parseInt(m2[1]);
  348.             var y1 = parseInt(m2[2]);
  349.             var x2 = parseInt(m2[3]);
  350.             var y2 = parseInt(m2[4]);
  351.             print.log("✓ 输入框定位(EditText):bounds=[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "]");
  352.             return {
  353.                 x: (x1 + x2) / 2,
  354.                 y: (y1 + y2) / 2
  355.             };
  356.         }
  357.     }

  358.     var viewFactoryHolderIdx = xmlStr.indexOf('class="androidx.compose.ui.viewinterop.ViewFactoryHolder"');
  359.     if (viewFactoryHolderIdx !== -1) {
  360.         var 段3 = xmlStr.substring(viewFactoryHolderIdx);
  361.         var m3 = 段3.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  362.         if (m3) {
  363.             var x1 = parseInt(m3[1]);
  364.             var y1 = parseInt(m3[2]);
  365.             var x2 = parseInt(m3[3]);
  366.             var y2 = parseInt(m3[4]);
  367.             print.log("✓ 输入框定位(ViewFactoryHolder):bounds=[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "]");
  368.             return {
  369.                 x: (x1 + x2) / 2,
  370.                 y: (y1 + y2) / 2
  371.             };
  372.         }
  373.     }

  374.     print.log("⚠ 未找到输入框,使用兜底坐标");
  375.     return {
  376.         x: 屏幕宽 * 0.35,
  377.         y: 屏幕高 * 0.75
  378.     };
  379. }

  380. function 查找加号按钮(xml) {
  381.     var xmlStr = "" + xml;
  382.    
  383.     var plusDescIdx = xmlStr.indexOf('content-desc="切换至语音"');
  384.     if (plusDescIdx !== -1) {
  385.         var 段 = xmlStr.substring(plusDescIdx);
  386.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  387.         if (m) {
  388.             var x1 = parseInt(m[1]);
  389.             var y1 = parseInt(m[2]);
  390.             var x2 = parseInt(m[3]);
  391.             var y2 = parseInt(m[4]);
  392.             var centerX = (x1 + x2) / 2;
  393.             var centerY = (y1 + y2) / 2;
  394.             print.log("✓ 加号按钮定位:content-desc=切换至语音,坐标(" + Math.round(centerX) + "," + Math.round(centerY) + ")");
  395.             return { x: centerX, y: centerY };
  396.         }
  397.     }

  398.     var inputIdx = xmlStr.indexOf('text="发消息或按住说话"');
  399.     if (inputIdx !== -1) {
  400.         var 输入框段 = xmlStr.substring(inputIdx);
  401.         var 输入框边界 = 输入框段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  402.         if (输入框边界) {
  403.             var 输入框X2 = parseInt(输入框边界[3]);
  404.             var 输入框Y = parseInt(输入框边界[2]);
  405.             var 输入框底部Y = parseInt(输入框边界[4]);
  406.             var 输入框中心Y = (输入框Y + 输入框底部Y) / 2;
  407.             
  408.             var clickablePattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  409.             var clickMatch;
  410.             var 候选按钮 = [];
  411.             
  412.             while ((clickMatch = clickablePattern.exec(xmlStr)) !== null) {
  413.                 var bx1 = parseInt(clickMatch[1]);
  414.                 var by1 = parseInt(clickMatch[2]);
  415.                 var bx2 = parseInt(clickMatch[3]);
  416.                 var by2 = parseInt(clickMatch[4]);
  417.                
  418.                 if (by1 >= 输入框中心Y - 100 && by2 <= 输入框中心Y + 200 && bx1 > 输入框X2 - 50) {
  419.                     候选按钮.push({ x: (bx1 + bx2) / 2, y: (by1 + by2) / 2 });
  420.                 }
  421.             }
  422.             
  423.             if (候选按钮.length > 0) {
  424.                 候选按钮.sort(function(a, b) { return a.x - b.x; });
  425.                 print.log("✓ 加号按钮定位:输入框右侧clickable元素,坐标(" + Math.round(候选按钮[0].x) + "," + Math.round(候选按钮[0].y) + ")");
  426.                 return 候选按钮[0];
  427.             }
  428.         }
  429.     }

  430.     print.log("⚠ 加号按钮使用兜底坐标(输入框右侧)");
  431.     var 输入框 = 查找输入框中心(xml);
  432.     return {
  433.         x: 屏幕宽 * 0.9,
  434.         y: 输入框.y
  435.     };
  436. }

  437. function 查找相册按钮(xml) {
  438.     var xmlStr = "" + xml;
  439.    
  440.     var albumIdx = xmlStr.indexOf('text="相册"');
  441.     if (albumIdx !== -1) {
  442.         var 段 = xmlStr.substring(albumIdx);
  443.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  444.         if (m) {
  445.             var x1 = parseInt(m[1]);
  446.             var y1 = parseInt(m[2]);
  447.             var x2 = parseInt(m[3]);
  448.             var y2 = parseInt(m[4]);
  449.             var centerX = (x1 + x2) / 2;
  450.             var centerY = (y1 + y2) / 2;
  451.             print.log("✓ 相册按钮定位:text=相册,bounds=[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "],坐标(" + Math.round(centerX) + "," + Math.round(centerY) + ")");
  452.             return { x: centerX, y: centerY };
  453.         }
  454.     }

  455.     var clickableViewPattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  456.     var clickMatch;
  457.     var 候选按钮 = [];
  458.    
  459.     while ((clickMatch = clickableViewPattern.exec(xmlStr)) !== null) {
  460.         var bx1 = parseInt(clickMatch[1]);
  461.         var by1 = parseInt(clickMatch[2]);
  462.         var bx2 = parseInt(clickMatch[3]);
  463.         var by2 = parseInt(clickMatch[4]);
  464.         
  465.         if (by1 >= 屏幕高 * 0.8 && by2 <= 屏幕高 * 0.95) {
  466.             候选按钮.push({ x: (bx1 + bx2) / 2, y: (by1 + by2) / 2 });
  467.         }
  468.     }
  469.    
  470.     if (候选按钮.length >= 3) {
  471.         候选按钮.sort(function(a, b) { return a.x - b.x; });
  472.         var 中间按钮 = 候选按钮[1];
  473.         print.log("✓ 相册按钮定位:底部中间clickable元素,坐标(" + Math.round(中间按钮.x) + "," + Math.round(中间按钮.y) + ")");
  474.         return 中间按钮;
  475.     }

  476.     print.log("⚠ 相册按钮使用兜底坐标(底部中间)");
  477.     return {
  478.         x: 屏幕宽 * 0.5,
  479.         y: 屏幕高 * 0.88
  480.     };
  481. }

  482. function 查找相册选项(xml) {
  483.     var xmlStr = "" + xml;
  484.    
  485.     var text关键词 = ["相册", "图片", "照片", "所有照片", "从相册选择", "选择图片"];
  486.     for (var i = 0; i < text关键词.length; i++) {
  487.         var kw = text关键词[i];
  488.         var idx = xmlStr.indexOf('text="' + kw + '"');
  489.         if (idx !== -1) {
  490.             var 段 = xmlStr.substring(idx);
  491.             var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  492.             if (m) {
  493.                 print.log("✓ 相册选项定位:text=" + kw);
  494.                 return {
  495.                     x: (parseInt(m[1]) + parseInt(m[3])) / 2,
  496.                     y: (parseInt(m[2]) + parseInt(m[4])) / 2
  497.                 };
  498.             }
  499.         }
  500.     }

  501.     var desc关键词 = ["相册", "图片", "照片"];
  502.     for (var j = 0; j < desc关键词.length; j++) {
  503.         var kw2 = desc关键词[j];
  504.         var idx2 = xmlStr.indexOf('content-desc="' + kw2 + '"');
  505.         if (idx2 !== -1) {
  506.             var 段2 = xmlStr.substring(idx2);
  507.             var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  508.             if (m2) {
  509.                 print.log("✓ 相册选项定位:content-desc=" + kw2);
  510.                 return {
  511.                     x: (parseInt(m2[1]) + parseInt(m2[3])) / 2,
  512.                     y: (parseInt(m2[2]) + parseInt(m2[4])) / 2
  513.                 };
  514.             }
  515.         }
  516.     }
  517.    
  518.     return null;
  519. }

  520. function 粘贴文本(文本) {
  521.     try {
  522.         Clipboard.copy("" + 文本);
  523.     } catch (e) {
  524.         print.log("⚠ Clipboard.copy 失败:" + e.message);
  525.     }
  526.     sleep.millisecond(毫秒 = 300);

  527.     try {
  528.         agent.shell("service call clipboard 3 i32 1 s16 '" + 文本 + "' i32 0");
  529.     } catch (e2) {
  530.         // 忽略错误
  531.     }
  532.     sleep.millisecond(毫秒 = 300);

  533.     agent.shell("input keyevent 279");
  534.     sleep.millisecond(毫秒 = 500);
  535.    
  536.     try {
  537.         agent.shell("input text '" + 文本 + "'");
  538.         print.log("✓ 已通过input text直接输入文本");
  539.     } catch (e3) {
  540.         print.log("⚠ input text失败:" + e3.message);
  541.     }
  542.    
  543.     sleep.second(秒 = 1);
  544.     print.log("✓ 已粘贴文本:" + 文本);
  545. }

  546. function 是否在系统相册页面(xml) {
  547.     var xmlStr = "" + xml;
  548.    
  549.     var packageMatch = xmlStr.match(/package="([^"]+)"/);
  550.     var 当前包名 = packageMatch ? packageMatch[1] : "";
  551.    
  552.     if (当前包名 && 当前包名 !== DEEPK包名) {
  553.         print.log("✓ 检测到系统相册页面,包名:" + 当前包名);
  554.         return true;
  555.     }
  556.    
  557.     return false;
  558. }

  559. function 是否在图片预览页面(xml) {
  560.     var xmlStr = "" + xml;
  561.     if (xmlStr.indexOf('text="完成"') !== -1 || xmlStr.indexOf('text="发送"') !== -1) {
  562.         return true;
  563.     }
  564.     if (xmlStr.indexOf('content-desc="完成"') !== -1 || xmlStr.indexOf('content-desc="发送"') !== -1) {
  565.         return true;
  566.     }
  567.     return false;
  568. }

  569. function 查找图片预览确认按钮(xml) {
  570.     var xmlStr = "" + xml;
  571.    
  572.     var 关键词 = ["完成", "发送", "确认"];
  573.     for (var i = 0; i < 关键词.length; i++) {
  574.         var kw = 关键词[i];
  575.         var textIdx = xmlStr.indexOf('text="' + kw + '"');
  576.         if (textIdx !== -1) {
  577.             var 段 = xmlStr.substring(textIdx);
  578.             var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  579.             if (m) {
  580.                 var x = (parseInt(m[1]) + parseInt(m[3])) / 2;
  581.                 var y = (parseInt(m[2]) + parseInt(m[4])) / 2;
  582.                 print.log("✓ 图片预览确认按钮定位:text=" + kw + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  583.                 return { x: x, y: y };
  584.             }
  585.         }
  586.     }
  587.    
  588.     for (var j = 0; j < 关键词.length; j++) {
  589.         var kw2 = 关键词[j];
  590.         var descIdx = xmlStr.indexOf('content-desc="' + kw2 + '"');
  591.         if (descIdx !== -1) {
  592.             var 段2 = xmlStr.substring(descIdx);
  593.             var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  594.             if (m2) {
  595.                 var x = (parseInt(m2[1]) + parseInt(m2[3])) / 2;
  596.                 var y = (parseInt(m2[2]) + parseInt(m2[4])) / 2;
  597.                 print.log("✓ 图片预览确认按钮定位:content-desc=" + kw2 + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  598.                 return { x: x, y: y };
  599.             }
  600.         }
  601.     }
  602.    
  603.     print.log("⚠ 图片预览确认按钮使用兜底坐标(底部中间)");
  604.     return { x: 屏幕宽 * 0.5, y: 屏幕高 * 0.92 };
  605. }

  606. function 查找相册选择按钮(xml) {
  607.     var xmlStr = "" + xml;
  608.    
  609.     var 关键词列表 = ["选择", "完成", "确认", "发送", "确定"];
  610.     for (var i = 0; i < 关键词列表.length; i++) {
  611.         var kw = 关键词列表[i];
  612.         
  613.         var textPattern = new RegExp('text="' + kw + '[^"]*"[^>]*?bounds="\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]"', 'gi');
  614.         var textMatch = textPattern.exec(xmlStr);
  615.         if (textMatch) {
  616.             var x = (parseInt(textMatch[1]) + parseInt(textMatch[3])) / 2;
  617.             var y = (parseInt(textMatch[2]) + parseInt(textMatch[4])) / 2;
  618.             print.log("✓ 相册选择按钮定位:text=" + kw + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  619.             return { x: x, y: y };
  620.         }
  621.         
  622.         var descIdx = xmlStr.indexOf('content-desc="' + kw + '"');
  623.         if (descIdx !== -1) {
  624.             var 段2 = xmlStr.substring(descIdx);
  625.             var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  626.             if (m2) {
  627.                 var x = (parseInt(m2[1]) + parseInt(m2[3])) / 2;
  628.                 var y = (parseInt(m2[2]) + parseInt(m2[4])) / 2;
  629.                 print.log("✓ 相册选择按钮定位:content-desc=" + kw + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  630.                 return { x: x, y: y };
  631.             }
  632.         }
  633.     }
  634.    
  635.     var bottomButtonPattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  636.     var bottomMatch;
  637.     var 底部按钮列表 = [];
  638.     while ((bottomMatch = bottomButtonPattern.exec(xmlStr)) !== null) {
  639.         var bx1 = parseInt(bottomMatch[1]);
  640.         var by1 = parseInt(bottomMatch[2]);
  641.         var bx2 = parseInt(bottomMatch[3]);
  642.         var by2 = parseInt(bottomMatch[4]);
  643.         if (by1 >= 屏幕高 * 0.85) {
  644.             底部按钮列表.push({ x: (bx1 + bx2) / 2, y: (by1 + by2) / 2 });
  645.         }
  646.     }
  647.    
  648.     if (底部按钮列表.length > 0) {
  649.         底部按钮列表.sort(function(a, b) { return b.x - a.x; });
  650.         var 最右边按钮 = 底部按钮列表[0];
  651.         print.log("✓ 相册选择按钮定位:底部最右边按钮,坐标(" + Math.round(最右边按钮.x) + "," + Math.round(最右边按钮.y) + ")");
  652.         return { x: 最右边按钮.x, y: 最右边按钮.y };
  653.     }
  654.    
  655.     print.log("⚠ 相册选择按钮使用兜底坐标(底部)");
  656.     return { x: 屏幕宽 * 0.78, y: 屏幕高 * 0.92 };
  657. }

  658. function 查找第一张图片(xml) {
  659.     var xmlStr = "" + xml;
  660.    
  661.     if (是否在系统相册页面(xmlStr)) {
  662.         agent.shell("echo '" + xmlStr.substring(0, 5000) + "' > /sdcard/相册UI_dump.xml");
  663.         print.log("✓ 已保存相册UI XML到/sdcard/相册UI_dump.xml");
  664.         
  665.         var nafPattern = /<node[^>]*?NAF="true"[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  666.         var nafMatch;
  667.         var NAF小圆点列表 = [];
  668.         
  669.         while ((nafMatch = nafPattern.exec(xmlStr)) !== null) {
  670.             var nx1 = parseInt(nafMatch[1]);
  671.             var ny1 = parseInt(nafMatch[2]);
  672.             var nx2 = parseInt(nafMatch[3]);
  673.             var ny2 = parseInt(nafMatch[4]);
  674.             var nw = nx2 - nx1;
  675.             var nh = ny2 - ny1;
  676.             
  677.             if (nw >= 50 && nw <= 300 && nh >= 50 && nh <= 300) {
  678.                 if (ny1 >= 400 && ny2 <= 屏幕高 - 400) {
  679.                     NAF小圆点列表.push({ x1: nx1, y1: ny1, x2: nx2, y2: ny2, x: (nx1 + nx2) / 2, y: (ny1 + ny2) / 2 });
  680.                 }
  681.             }
  682.         }
  683.         
  684.         if (NAF小圆点列表.length > 0) {
  685.             NAF小圆点列表.sort(function(a, b) {
  686.                 if (a.y1 !== b.y1) return a.y1 - b.y1;
  687.                 return a.x1 - b.x1;
  688.             });
  689.             var 选中小圆点 = NAF小圆点列表[0];
  690.             print.log("✓ ComposeView找到NAF小圆点选择框:坐标(" + Math.round(选中小圆点.x) + "," + Math.round(选中小圆点.y) + "),bounds=[" + 选中小圆点.x1 + "," + 选中小圆点.y1 + "][" + 选中小圆点.x2 + "," + 选中小圆点.y2 + "]");
  691.             return { x: 选中小圆点.x, y: 选中小圆点.y };
  692.         }
  693.         
  694.         var imageDescPattern = /<node[^>]*?content-desc="([^"]+\.(png|jpg|jpeg|gif))"[^>]*?class="android\.view\.View"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/gi;
  695.         var imgMatch;
  696.         var 图片节点列表 = [];
  697.         
  698.         while ((imgMatch = imageDescPattern.exec(xmlStr)) !== null) {
  699.             var 文件名 = imgMatch[1];
  700.             var ix1 = parseInt(imgMatch[3]);
  701.             var iy1 = parseInt(imgMatch[4]);
  702.             var ix2 = parseInt(imgMatch[5]);
  703.             var iy2 = parseInt(imgMatch[6]);
  704.             var iw = ix2 - ix1;
  705.             var ih = iy2 - iy1;
  706.             
  707.             if (iw >= 100 && ih >= 100) {
  708.                 图片节点列表.push({ 文件名: 文件名, x1: ix1, y1: iy1, x2: ix2, y2: iy2, w: iw, h: ih });
  709.             }
  710.         }
  711.         
  712.         if (图片节点列表.length > 0) {
  713.             图片节点列表.sort(function(a, b) {
  714.                 if (a.y1 !== b.y1) return a.y1 - b.y1;
  715.                 return a.x1 - b.x1;
  716.             });
  717.             var 第一张图片 = 图片节点列表[0];
  718.             print.log("✓ 找到图片:" + 第一张图片.文件名 + ",bounds=[" + 第一张图片.x1 + "," + 第一张图片.y1 + "][" + 第一张图片.x2 + "," + 第一张图片.y2 + "]");
  719.             
  720.             var 选择框X = 第一张图片.x1 + 第一张图片.w * 0.77;
  721.             var 选择框Y = 第一张图片.y1 + 第一张图片.h * 0.24;
  722.             print.log("✓ 计算小圆点选择框坐标:(" + Math.round(选择框X) + "," + Math.round(选择框Y) + ")");
  723.             return { x: 选择框X, y: 选择框Y };
  724.         }
  725.         
  726.         var clickableViewPattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  727.         var clickMatch;
  728.         var 可点击区域 = [];
  729.         while ((clickMatch = clickableViewPattern.exec(xmlStr)) !== null) {
  730.             var cx1 = parseInt(clickMatch[1]);
  731.             var cy1 = parseInt(clickMatch[2]);
  732.             var cx2 = parseInt(clickMatch[3]);
  733.             var cy2 = parseInt(clickMatch[4]);
  734.             var cw = cx2 - cx1;
  735.             var ch = cy2 - cy1;
  736.             可点击区域.push({ x1: cx1, y1: cy1, x2: cx2, y2: cy2, w: cw, h: ch, x: (cx1 + cx2) / 2, y: (cy1 + cy2) / 2 });
  737.         }
  738.         
  739.         var 图片区域内可点击 = [];
  740.         for (var k = 0; k < 可点击区域.length; k++) {
  741.             var item = 可点击区域[k];
  742.             if (item.y >= 400 && item.y <= 屏幕高 - 400) {
  743.                 图片区域内可点击.push(item);
  744.             }
  745.         }
  746.         
  747.         if (图片区域内可点击.length > 0) {
  748.             图片区域内可点击.sort(function(a, b) {
  749.                 if (a.y !== b.y) return a.y - b.y;
  750.                 return a.x - b.x;
  751.             });
  752.             var 第一个可点击 = 图片区域内可点击[0];
  753.             print.log("✓ ComposeView图片区域内第一个可点击元素:坐标(" + Math.round(第一个可点击.x) + "," + Math.round(第一个可点击.y) + ")");
  754.             return { x: 第一个可点击.x, y: 第一个可点击.y };
  755.         }

  756.         print.log("⚠ 系统相册未找到图片,使用兜底坐标");
  757.         return { x: 屏幕宽 * 0.25, y: 屏幕高 * 0.3 };
  758.     }

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

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

  764.     try {
  765.         var detects = opencv.findImagesEx('图色168638.cv');
  766.         if (detects != null && detects.length > 0) {
  767.             print.log("✓ 发送按钮定位:图色匹配");
  768.             var dStr = "" + detects[0];
  769.             print.log("图色匹配结果:" + dStr);
  770.             var m = dStr.match(/矩形区域:([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+)/);
  771.             if (m) {
  772.                 var left = parseFloat(m[1]);
  773.                 var top = parseFloat(m[2]);
  774.                 var right = parseFloat(m[3]);
  775.                 var bottom = parseFloat(m[4]);
  776.                 var centerX = (left + right) / 2;
  777.                 var centerY = (top + bottom) / 2;
  778.                 print.log("图色匹配百分比坐标:left=" + left + ", top=" + top + ", right=" + right + ", bottom=" + bottom);
  779.                 print.log("计算点击百分比:(" + centerX + "," + centerY + ")");
  780.                 agent.clickPercent(centerX, centerY);
  781.                 print.log("✓ 已点击发送按钮(图色)");
  782.                 return null;
  783.             }
  784.             print.log("⚠ 图色匹配结果格式解析失败");
  785.         }
  786.     } catch (e) {
  787.         print.log("⚠ 图色匹配失败:" + e.message);
  788.     }

  789.     var inputIdx = xmlStr.indexOf('text="发消息或按住说话"');
  790.     if (inputIdx !== -1) {
  791.         var 输入框段 = xmlStr.substring(inputIdx);
  792.         var 输入框边界 = 输入框段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  793.         
  794.         if (输入框边界) {
  795.             var 输入框信息 = {
  796.                 x1: parseInt(输入框边界[1]),
  797.                 y1: parseInt(输入框边界[2]),
  798.                 x2: parseInt(输入框边界[3]),
  799.                 y2: parseInt(输入框边界[4]),
  800.                 centerY: (parseInt(输入框边界[2]) + parseInt(输入框边界[4])) / 2
  801.             };

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

  805.             while ((clickMatch = clickablePattern.exec(xmlStr)) !== null) {
  806.                 var cx1 = parseInt(clickMatch[1]);
  807.                 var cy1 = parseInt(clickMatch[2]);
  808.                 var cx2 = parseInt(clickMatch[3]);
  809.                 var cy2 = parseInt(clickMatch[4]);
  810.                 var cw = cx2 - cx1;
  811.                 var ch = cy2 - cy1;

  812.                 var 是小按钮 = (cw < 300 && ch < 300);
  813.                 var 在输入框右侧 = (cx1 > 输入框信息.x2 - 100);
  814.                 var 在输入框水平行 = (cy1 >= 输入框信息.y1 - 100 && cy1 <= 输入框信息.y2 + 100);

  815.                 if (是小按钮 && 在输入框右侧 && 在输入框水平行) {
  816.                     candidates.push({
  817.                         x1: cx1, y1: cy1, x2: cx2, y2: cy2,
  818.                         x: (cx1 + cx2) / 2,
  819.                         y: (cy1 + cy2) / 2
  820.                     });
  821.                 }
  822.             }

  823.             if (candidates.length > 0) {
  824.                 candidates.sort(function(a, b) {
  825.                     return b.x1 - a.x1;
  826.                 });
  827.                 var 选中 = candidates[0];
  828.                 print.log("✓ 发送按钮定位:输入框右侧clickable元素,坐标(" + Math.round(选中.x) + "," + Math.round(选中.y) + ")");
  829.                 return { x: 选中.x, y: 选中.y };
  830.             }

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

  837.     var sendTextIdx = xmlStr.indexOf('text="发送"');
  838.     if (sendTextIdx !== -1) {
  839.         var 段 = xmlStr.substring(sendTextIdx);
  840.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  841.         if (m) {
  842.             print.log("✓ 发送按钮定位:文本匹配");
  843.             return {
  844.                 x: (parseInt(m[1]) + parseInt(m[3])) / 2,
  845.                 y: (parseInt(m[2]) + parseInt(m[4])) / 2
  846.             };
  847.         }
  848.     }

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

  861.     print.log("⚠ 发送按钮使用屏幕右侧兜底策略");
  862.     agent.clickPercent(0.9, 0.75);
  863.     print.log("✓ 已点击发送按钮(硬编码兜底)");
  864.     return null;
  865. }

  866. function 等待AI回答完成(发送前的最后文本, 发送前回答数量) {
  867.     var 已耗时 = 0;
  868.     var 检查间隔秒 = 3;
  869.     var 连续相同次数 = 0;
  870.     var 上次规范化文本 = "";

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

  872.     sleep.second(秒 = 5);
  873.     已耗时 += 5;

  874.     while (已耗时 < 等待回答超时秒) {
  875.         var xml = 获取UI();
  876.         var 回答列表 = 采集AI回答列表(xml);
  877.         
  878.         if (回答列表.length > 0) {
  879.             var 当前最后回答 = 回答列表[回答列表.length - 1];
  880.             var 当前提取数字 = 提取数字(当前最后回答);
  881.             var 当前规范化文本 = 当前最后回答.trim().replace(/\s+/g, " ");
  882.             
  883.             var 有新回答 = false;
  884.             var 回答数量增加 = (回答列表.length > 发送前回答数量);
  885.             
  886.             var 发送前规范化 = 发送前的最后文本.trim().replace(/\s+/g, " ");
  887.             有新回答 = (当前规范化文本 !== 发送前规范化) || (当前提取数字 !== "");
  888.             
  889.             if (有新回答 || 回答数量增加) {
  890.                 print.log("✓ 检测到新回答(" + 已耗时 + "秒):'" + 当前最后回答 + "',提取数字:'" + 当前提取数字 + "'");
  891.                
  892.                 if (当前提取数字 !== "") {
  893.                     print.log("✓ 提取到数字,直接返回:" + 当前提取数字);
  894.                     return 当前提取数字;
  895.                 }
  896.                
  897.                 if (当前规范化文本 === 上次规范化文本) {
  898.                     连续相同次数++;
  899.                     if (连续相同次数 >= 2) {
  900.                         print.log("✓ 文本连续2次相同,回答完成");
  901.                         var 最终数字 = 提取数字(当前最后回答);
  902.                         if (最终数字 !== "") {
  903.                             return 最终数字;
  904.                         }
  905.                         return 当前最后回答;
  906.                     }
  907.                 } else {
  908.                     连续相同次数 = 0;
  909.                     上次规范化文本 = 当前规范化文本;
  910.                 }
  911.             }
  912.         }
  913.         
  914.         sleep.second(秒 = 检查间隔秒);
  915.         已耗时 += 检查间隔秒;
  916.     }

  917.     print.log("⚠ 等待AI回答超时(" + 等待回答超时秒 + "秒),尝试返回当前内容");
  918.     var xml = 获取UI();
  919.     var 兜底列表 = 采集AI回答列表(xml);
  920.     if (兜底列表.length > 0) {
  921.         var 兜底文本 = 兜底列表[兜底列表.length - 1];
  922.         print.log("✓ 超时兜底:返回当前采集到的回答:" + 兜底文本);
  923.         return 兜底文本;
  924.     }
  925.     return null;
  926. }

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

  928. function 主流程() {
  929.     // 步骤1:全屏截图(B站验证码页面)
  930.     print.log("\n========== 步骤1:全屏截图B站验证码 ==========");
  931.     var 截图成功 = 全屏截图(截图保存路径);
  932.     if (!截图成功) {
  933.         print.log("✗ 截图失败,退出流程");
  934.         print.log("===== DEEPSEEK识别验证码拖动B站流程结束 =====");
  935.         return;
  936.     }

  937.     // 步骤2:启动DEEPSEEK APP
  938.     print.log("\n========== 步骤2:启动DEEPSEEK APP ==========");
  939.     try {
  940.         app.openApp(DEEPK包名);
  941.         print.log("✓ 已启动DEEPSEEK");
  942.     } catch (e) {
  943.         print.log("⚠ 启动失败:" + e.message);
  944.     }
  945.     sleep.second(秒 = 5);

  946.     // 步骤3:点击右上角新对话按钮
  947.     print.log("\n========== 步骤3:点击右上角新对话按钮 ==========");
  948.    
  949.     xml = 获取UI();
  950.    
  951.     var 新对话X = 屏幕宽 * 0.96;
  952.     var 新对话Y = 屏幕高 * 0.06;
  953.    
  954.     var newChatIdx = xml.indexOf('content-desc="开启新对话"');
  955.     if (newChatIdx !== -1) {
  956.         var 段 = xml.substring(newChatIdx);
  957.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  958.         if (m) {
  959.             新对话X = (parseInt(m[1]) + parseInt(m[3])) / 2;
  960.             新对话Y = (parseInt(m[2]) + parseInt(m[4])) / 2;
  961.             print.log("✓ 新对话按钮定位:content-desc=开启新对话,坐标(" + Math.round(新对话X) + "," + Math.round(新对话Y) + ")");
  962.         }
  963.     }
  964.    
  965.     agent.click(新对话X, 新对话Y);
  966.     print.log("✓ 已点击新对话按钮,坐标(" + Math.round(新对话X) + "," + Math.round(新对话Y) + ")");
  967.    
  968.     sleep.second(秒 = 3);
  969.     print.log("✓ 新对话操作完成");

  970.     // 步骤5:确保识图模式已开启
  971.     print.log("\n========== 步骤5:确保识图模式已开启 ==========");
  972.    
  973.     var 识图模式X = 屏幕宽 * 0.8;
  974.     var 识图模式Y = 屏幕高 * 0.53;
  975.    
  976.     var visualModeIdx = xml.indexOf('text="识图模式"');
  977.     if (visualModeIdx !== -1) {
  978.         var 段 = xml.substring(visualModeIdx);
  979.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  980.         if (m) {
  981.             识图模式X = (parseInt(m[1]) + parseInt(m[3])) / 2;
  982.             识图模式Y = (parseInt(m[2]) + parseInt(m[4])) / 2;
  983.             print.log("✓ 识图模式按钮定位:text=识图模式,坐标(" + Math.round(识图模式X) + "," + Math.round(识图模式Y) + ")");
  984.         }
  985.     } else {
  986.         print.log("⚠ XML中未找到识图模式按钮,使用兜底坐标");
  987.     }
  988.    
  989.     agent.click(识图模式X, 识图模式Y);
  990.     print.log("✓ 已点击识图模式按钮,坐标(" + Math.round(识图模式X) + "," + Math.round(识图模式Y) + ")");
  991.     sleep.second(秒 = 2);
  992.     xml = 获取UI();

  993.     // 步骤6:记录发送前的最后一条AI回答和数量
  994.     print.log("\n========== 步骤6:记录发送前状态 ==========");
  995.     var 发送前回答数量 = 0;
  996.     print.log("✓ 发送前回答数量:" + 发送前回答数量);

  997.     // 步骤7:点击加号按钮打开附件菜单
  998.     print.log("\n========== 步骤7:点击加号按钮打开附件菜单 ==========");
  999.    
  1000.     var 加号X = 屏幕宽 * 0.83;
  1001.     var 加号Y = 屏幕高 * 0.97;
  1002.    
  1003.     var plusDescIdx = xml.indexOf('content-desc="上传文件"');
  1004.     if (plusDescIdx !== -1) {
  1005.         var 段 = xml.substring(plusDescIdx);
  1006.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  1007.         if (m) {
  1008.             加号X = (parseInt(m[1]) + parseInt(m[3])) / 2;
  1009.             加号Y = (parseInt(m[2]) + parseInt(m[4])) / 2;
  1010.             print.log("✓ 加号按钮定位:content-desc=上传文件,坐标(" + Math.round(加号X) + "," + Math.round(加号Y) + ")");
  1011.         }
  1012.     } else {
  1013.         print.log("⚠ XML中未找到加号按钮,使用兜底坐标");
  1014.     }
  1015.    
  1016.     agent.click(加号X, 加号Y);
  1017.     print.log("✓ 已点击加号按钮,坐标(" + Math.round(加号X) + "," + Math.round(加号Y) + ")");
  1018.     sleep.second(秒 = 2);

  1019.     // 步骤8:点击相册按钮选择图片
  1020.     print.log("\n========== 步骤8:点击相册按钮选择图片 ==========");
  1021.    
  1022.     var 相册选择成功 = false;
  1023.     var 尝试次数 = 0;
  1024.    
  1025.     while (!相册选择成功 && 尝试次数 < 5) {
  1026.         尝试次数++;
  1027.         xml = 获取UI();
  1028.         
  1029.         if (是否在系统相册页面(xml)) {
  1030.             print.log("✓ 已进入系统相册页面");
  1031.             相册选择成功 = true;
  1032.             break;
  1033.         }
  1034.         
  1035.         var 相册X = 屏幕宽 * 0.5;
  1036.         var 相册Y = 屏幕高 * 0.88;
  1037.         
  1038.         var albumIdx = xml.indexOf('text="相册"');
  1039.         if (albumIdx !== -1) {
  1040.             var 段 = xml.substring(albumIdx);
  1041.             var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  1042.             if (m) {
  1043.                 相册X = (parseInt(m[1]) + parseInt(m[3])) / 2;
  1044.                 相册Y = (parseInt(m[2]) + parseInt(m[4])) / 2;
  1045.                 print.log("✓ 相册按钮定位:text=相册,坐标(" + Math.round(相册X) + "," + Math.round(相册Y) + ")");
  1046.             }
  1047.         }
  1048.         
  1049.         agent.click(相册X, 相册Y);
  1050.         print.log("✓ 已点击相册按钮,坐标(" + Math.round(相册X) + "," + Math.round(相册Y) + ")");
  1051.         sleep.second(秒 = 2);
  1052.         
  1053.         xml = 获取UI();
  1054.         if (是否在系统相册页面(xml)) {
  1055.             print.log("✓ 已进入系统相册页面");
  1056.             相册选择成功 = true;
  1057.             break;
  1058.         }
  1059.         
  1060.         print.log("⚠ 第" + 尝试次数 + "次尝试:未进入相册页面,重新点击加号");
  1061.         agent.click(屏幕宽 * 0.77, 屏幕高 * 0.94);
  1062.         sleep.second(秒 = 2);
  1063.     }

  1064.     // 步骤9:选择第一张图片(系统相册用Canvas渲染,XML无节点,直接坐标点击)
  1065.     print.log("\n========== 步骤9:选择第一张图片 ==========");
  1066.    
  1067.     var 图片尝试次数 = 0;
  1068.     while (图片尝试次数 < 3) {
  1069.         图片尝试次数++;
  1070.         xml = 获取UI();
  1071.         
  1072.         if (是否在系统相册页面(xml)) {
  1073.             print.log("✓ 系统相册页面,点击图片位置");
  1074.             
  1075.             var 标题栏底部 = 432;
  1076.             var actionBarMatch = xml.match(/resource-id="android:id\/action_bar"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  1077.             if (actionBarMatch) {
  1078.                 标题栏底部 = parseInt(actionBarMatch[4]);
  1079.             }
  1080.             
  1081.             var 图片区域顶部 = 标题栏底部;
  1082.             var 图片区域底部 = 屏幕高;
  1083.             var 图片区域高度 = 图片区域底部 - 图片区域顶部;
  1084.             
  1085.             var 图片X = 屏幕宽 * 0.5;
  1086.             var 图片Y = 图片区域顶部 + 图片区域高度 * 0.4;
  1087.             agent.click(图片X, 图片Y);
  1088.             print.log("✓ 已点击图片位置,坐标(" + Math.round(图片X) + "," + Math.round(图片Y) + ")");
  1089.             sleep.second(秒 = 3);
  1090.             
  1091.             xml = 获取UI();
  1092.             if (!是否在系统相册页面(xml)) {
  1093.                 print.log("✓ 已离开相册页面,图片可能已添加");
  1094.                 break;
  1095.             }
  1096.         } else {
  1097.             break;
  1098.         }
  1099.     }

  1100.     // 步骤10:等待图片添加到输入区域(等待回到DEEPSEEK对话页面)
  1101.     print.log("\n========== 步骤10:等待图片添加到输入区域 ==========");
  1102.     sleep.second(秒 = 3);
  1103.     xml = 获取UI();
  1104.    
  1105.     var packageMatch = xml.match(/package="([^"]+)"/);
  1106.     if (packageMatch && packageMatch[1] === DEEPK包名) {
  1107.         print.log("✓ 已回到DEEPSEEK对话页面");
  1108.     }
  1109.    
  1110.     print.log("✓ 图片已添加到输入区域");
  1111.    
  1112.     var isQuickMode = xml.indexOf('快速模式') !== -1;
  1113.     if (isQuickMode) {
  1114.         print.log("✓ 当前是快速模式,切换到识图模式");
  1115.         var 识图模式X = 屏幕宽 * 0.75;
  1116.         var 识图模式Y = 屏幕高 * 0.72;
  1117.         agent.click(识图模式X, 识图模式Y);
  1118.         print.log("✓ 已点击识图模式按钮,坐标(" + Math.round(识图模式X) + "," + Math.round(识图模式Y) + ")");
  1119.         sleep.second(秒 = 2);
  1120.     }

  1121.     // 步骤11:粘贴文字询问拖动距离
  1122.     print.log("\n========== 步骤11:粘贴文字询问拖动距离 ==========");
  1123.     xml = 获取UI();
  1124.    
  1125.     var 输入框X = 屏幕宽 * 0.2;
  1126.     var 输入框Y = 屏幕高 * 0.72;
  1127.    
  1128.     var editTextIdx = xml.indexOf('class="android.widget.EditText"');
  1129.     if (editTextIdx !== -1) {
  1130.         var 段 = xml.substring(editTextIdx);
  1131.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  1132.         if (m) {
  1133.             输入框X = (parseInt(m[1]) + parseInt(m[3])) / 2;
  1134.             输入框Y = (parseInt(m[2]) + parseInt(m[4])) / 2;
  1135.             print.log("✓ 输入框定位:class=EditText,坐标(" + Math.round(输入框X) + "," + Math.round(输入框Y) + ")");
  1136.         }
  1137.     } else {
  1138.         var inputKeywords = ["text="发消息"", "text="发消息或按住说话"", "text="在这里提问"", "text="接着问""];
  1139.         for (var k = 0; k < inputKeywords.length; k++) {
  1140.             var idx = xml.indexOf(inputKeywords[k]);
  1141.             if (idx !== -1) {
  1142.                 var 段 = xml.substring(idx);
  1143.                 var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  1144.                 if (m) {
  1145.                     输入框X = (parseInt(m[1]) + parseInt(m[3])) / 2;
  1146.                     输入框Y = (parseInt(m[2]) + parseInt(m[4])) / 2;
  1147.                     print.log("✓ 输入框定位:" + inputKeywords[k].replace('text="', '').replace('"', '') + ",坐标(" + Math.round(输入框X) + "," + Math.round(输入框Y) + ")");
  1148.                     break;
  1149.                 }
  1150.             }
  1151.         }
  1152.     }
  1153.    
  1154.     agent.click(输入框X, 输入框Y);
  1155.     print.log("✓ 已点击输入框,坐标(" + Math.round(输入框X) + "," + Math.round(输入框Y) + ")");
  1156.     sleep.second(秒 = 2);
  1157.    
  1158.     try {
  1159.         Clipboard.copy("" + 提问话术);
  1160.         sleep.millisecond(毫秒 = 500);
  1161.         agent.shell("input keyevent 279");
  1162.         sleep.second(秒 = 2);
  1163.         print.log("✓ 已通过剪贴板粘贴文本");
  1164.     } catch (e) {
  1165.         print.log("⚠ 剪贴板粘贴失败:" + e.message);
  1166.         agent.shell("input text '" + 提问话术 + "'");
  1167.         sleep.second(秒 = 2);
  1168.         print.log("✓ 已通过input text直接输入文本");
  1169.     }
  1170.     sleep.second(秒 = 2);

  1171.     // 步骤12:发送图片和文字
  1172.     print.log("\n========== 步骤12:发送图片和文字 ==========");
  1173.    
  1174.     var detects = opencv.findImagesEx('图色769678.cv');
  1175.     if (detects != null) {
  1176.         print.log("✓ 图色匹配找到发送按钮");
  1177.         print.log("图色匹配结果:" + detects[0]);
  1178.         var dStr = "" + detects[0];
  1179.         var m = dStr.match(/矩形区域:([\d.]+),\s*([\d.]+),\s*([\d.]+),\s*([\d.]+)/);
  1180.         if (m) {
  1181.             var left = parseFloat(m[1]);
  1182.             var top = parseFloat(m[2]);
  1183.             var right = parseFloat(m[3]);
  1184.             var bottom = parseFloat(m[4]);
  1185.             var centerX = (left + right) / 2;
  1186.             var centerY = (top + bottom) / 2;
  1187.             agent.clickPercent(centerX, centerY);
  1188.             print.log("✓ 已点击发送按钮(图色匹配),百分比坐标(" + centerX.toFixed(4) + "," + centerY.toFixed(4) + ")");
  1189.         }
  1190.     } else {
  1191.         print.log("⚠ 图色匹配未找到发送按钮");
  1192.     }
  1193.    
  1194.     sleep.second(秒 = 35);

  1195.     // 步骤13:等待DEEPSEEK AI回答
  1196.     print.log("\n========== 步骤13:等待DEEPSEEK AI回答 ==========");
  1197.     xml = 获取UI();
  1198.     var AI回答 = 等待AI回答完成("", 0);
  1199.    
  1200.     if (!AI回答) {
  1201.         print.log("✗ 未获取到AI回答");
  1202.         print.log("===== DEEPSEEK识别验证码拖动B站流程结束 =====");
  1203.         return;
  1204.     }

  1205.     print.log("\n✓ 采集到AI回答");
  1206.     print.log("--- 采集内容开始 ---");
  1207.     print.log(AI回答);
  1208.     print.log("--- 采集内容结束 ---");

  1209.     // 步骤14:解析拖动距离坐标
  1210.     print.log("\n========== 步骤14:解析拖动距离坐标 ==========");
  1211.     print.log("✓ AI原始回答:'" + AI回答 + "'");
  1212.    
  1213.     var 所有数字 = AI回答.match(/\d+/g);
  1214.     var 拖动距离像素 = null;
  1215.     var AI图像宽度 = null;
  1216.    
  1217.     if (所有数字 && 所有数字.length >= 2) {
  1218.         var 数字列表 = [];
  1219.         for (var i = 0; i < 所有数字.length; i++) {
  1220.             数字列表.push(parseInt(所有数字[i]));
  1221.         }
  1222.         print.log("✓ 提取到所有数字:" + 数字列表.join(", "));
  1223.         
  1224.         if (数字列表.length >= 5) {
  1225.             var x1 = 数字列表[0];
  1226.             var y1 = 数字列表[1];
  1227.             var x2 = 数字列表[2];
  1228.             var y2 = 数字列表[3];
  1229.             AI图像宽度 = 数字列表[4];
  1230.             拖动距离像素 = Math.abs(x2 - x1);
  1231.             print.log("✓ 识别到两组坐标+图像宽度:(" + x1 + "," + y1 + ") 和 (" + x2 + "," + y2 + "),图像宽度=" + AI图像宽度);
  1232.             print.log("✓ 计算拖动距离:|x2 - x1| = |" + x2 + " - " + x1 + "| = " + 拖动距离像素);
  1233.         } else if (数字列表.length >= 4) {
  1234.             var x1 = 数字列表[0];
  1235.             var y1 = 数字列表[1];
  1236.             var x2 = 数字列表[2];
  1237.             var y2 = 数字列表[3];
  1238.             拖动距离像素 = Math.abs(x2 - x1);
  1239.             AI图像宽度 = Math.max(x1, x2) + 100;
  1240.             print.log("✓ 识别到两组坐标格式:(" + x1 + "," + y1 + ") 和 (" + x2 + "," + y2 + ")");
  1241.             print.log("✓ 计算拖动距离:|x2 - x1| = |" + x2 + " - " + x1 + "| = " + 拖动距离像素);
  1242.             print.log("✓ 估算图像宽度:max(x1,x2)+100 = " + AI图像宽度);
  1243.         } else if (数字列表.length >= 2) {
  1244.             var 坐标匹配 = AI回答.match(/(\d+)\s*[,,]\s*(\d+)/);
  1245.             if (坐标匹配) {
  1246.                 var cx1 = parseInt(坐标匹配[1]);
  1247.                 var cx2 = parseInt(坐标匹配[2]);
  1248.                 拖动距离像素 = Math.abs(cx2 - cx1);
  1249.                 AI图像宽度 = Math.max(cx1, cx2) + 100;
  1250.                 print.log("✓ 识别到坐标格式:(" + cx1 + "," + cx2 + "),计算距离:" + 拖动距离像素);
  1251.             } else {
  1252.                 拖动距离像素 = 数字列表[0];
  1253.                 print.log("✓ 提取到单个数字(拖动距离):" + 拖动距离像素);
  1254.             }
  1255.         } else {
  1256.             拖动距离像素 = 数字列表[0];
  1257.             print.log("✓ 提取到单个数字(拖动距离):" + 拖动距离像素);
  1258.         }
  1259.     } else if (所有数字 && 所有数字.length === 1) {
  1260.         拖动距离像素 = parseInt(所有数字[0]);
  1261.         print.log("✓ 提取到单个数字(拖动距离):" + 拖动距离像素);
  1262.     } else {
  1263.         print.log("✗ 未找到有效的拖动距离");
  1264.         print.log("===== DEEPSEEK识别验证码拖动B站流程结束 =====");
  1265.         return;
  1266.     }
  1267.    
  1268.     var 图像缩放系数 = 1.0;
  1269.     if (拖动距离像素 < 30) {
  1270.         print.log("⚠ 提取到的拖动距离过小(" + 拖动距离像素 + "),可能是OCR识别错误,跳过缩放补偿");
  1271.     } else if (AI图像宽度 && AI图像宽度 > 0 && AI图像宽度 < 屏幕宽) {
  1272.         图像缩放系数 = 屏幕宽 / AI图像宽度;
  1273.         if (图像缩放系数 > 5) {
  1274.             图像缩放系数 = 1.0;
  1275.         } else {
  1276.             拖动距离像素 = Math.round(拖动距离像素 * 图像缩放系数);
  1277.             print.log("✓ 图像缩放补偿:AI图像宽度=" + AI图像宽度 + ",屏幕宽=" + 屏幕宽);
  1278.             print.log("✓ 缩放系数=" + 图像缩放系数.toFixed(2) + ",补偿后拖动距离=" + 拖动距离像素);
  1279.         }
  1280.     } else {
  1281.         图像缩放系数 = 屏幕宽 / 750;
  1282.         拖动距离像素 = Math.round(拖动距离像素 * 图像缩放系数);
  1283.         print.log("✓ 单数字模式补偿:假设AI图像宽度≈750,缩放系数=" + 图像缩放系数.toFixed(2));
  1284.         print.log("✓ 补偿后拖动距离=" + 拖动距离像素);
  1285.     }
  1286.    
  1287.     验证码滑块距离 = {
  1288.         x: 拖动距离像素,
  1289.         y: 0
  1290.     };

  1291.     // 步骤15:切换回B站并拖动滑块
  1292.     print.log("\n========== 步骤15:切换回B站并拖动滑块 ==========");
  1293.    
  1294.     agent.shell("input keyevent 187");
  1295.     print.log("✓ 已按后台键打开任务列表");
  1296.     sleep.second(秒 = 2);
  1297.    
  1298.     xml = 获取UI();
  1299.     var biliIdx = xml.indexOf('哔哩哔哩');
  1300.     if (biliIdx === -1) {
  1301.         biliIdx = xml.indexOf('bilibili');
  1302.     }
  1303.     if (biliIdx === -1) {
  1304.         biliIdx = xml.indexOf('B站');
  1305.     }
  1306.    
  1307.     if (biliIdx !== -1) {
  1308.         var 段 = xml.substring(biliIdx);
  1309.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  1310.         if (m) {
  1311.             var clickX = (parseInt(m[1]) + parseInt(m[3])) / 2;
  1312.             var clickY = (parseInt(m[2]) + parseInt(m[4])) / 2;
  1313.             agent.click(clickX, clickY);
  1314.             print.log("✓ 已点击B站任务卡片,坐标(" + Math.round(clickX) + "," + Math.round(clickY) + ")");
  1315.         }
  1316.     } else {
  1317.         print.log("⚠ 未找到B站任务卡片,尝试直接打开");
  1318.         try {
  1319.             app.openApp(B站包名);
  1320.             print.log("✓ 已打开B站");
  1321.         } catch (e) {
  1322.             print.log("⚠ 打开B站失败:" + e.message);
  1323.         }
  1324.     }
  1325.     sleep.second(秒 = 3);

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

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

  1334.     var startX = 验证码区域左边界 + 50;
  1335.     var startY = 屏幕高 * 0.42;
  1336.     var endX = startX + 拖动距离;
  1337.     var endY = startY;

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

  1342. 主流程();

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


举报 回复