diff --git a/.idea/iOSAI.iml b/.idea/iOSAI.iml
index 6cb8b9a..894b6b0 100644
--- a/.idea/iOSAI.iml
+++ b/.idea/iOSAI.iml
@@ -4,7 +4,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index db8786c..c27b771 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 7549b82..24dd257 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -8,8 +8,12 @@
-
+
+
+
+
+
@@ -52,30 +56,32 @@
- {
- "keyToString": {
- "ASKED_ADD_EXTERNAL_FILES": "true",
- "Python.12.executor": "Run",
- "Python.123.executor": "Run",
- "Python.Main.executor": "Run",
- "Python.tidevice_entry.executor": "Run",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
- "RunOnceActivity.git.unshallow": "true",
- "SHARE_PROJECT_CONFIGURATION_FILES": "true",
- "git-widget-placeholder": "main",
- "javascript.nodejs.core.library.configured.version": "20.17.0",
- "javascript.nodejs.core.library.typings.version": "20.17.58",
- "last_opened_file_path": "F:/company code/AI item/20250820/iOSAI",
- "node.js.detected.package.eslint": "true",
- "node.js.detected.package.tslint": "true",
- "node.js.selected.package.eslint": "(autodetect)",
- "node.js.selected.package.tslint": "(autodetect)",
- "nodejs_package_manager_path": "npm",
- "settings.editor.selected.configurable": "preferences.editor.code.editing",
- "vue.rearranger.settings.migration": "true"
+
+}]]>
@@ -144,6 +150,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -169,15 +221,18 @@
-
+
+
+
-
+
+
@@ -242,6 +297,7 @@
+
@@ -311,15 +367,18 @@
-
+
-
-
-
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Module/FlaskService.py b/Module/FlaskService.py
index b1fe646..f437238 100644
--- a/Module/FlaskService.py
+++ b/Module/FlaskService.py
@@ -2,6 +2,7 @@ import json
import os
import socket
import threading
+import time
from pathlib import Path
from queue import Queue
from typing import Any, Dict
@@ -87,6 +88,7 @@ def start_socket_listener():
listener_thread = threading.Thread(target=start_socket_listener, daemon=True)
listener_thread.start()
+
# 获取设备列表
@app.route('/deviceList', methods=['GET'])
def deviceList():
@@ -358,6 +360,7 @@ def queryAnchorList():
data = []
return ResultData(data=data).toJson()
+
# 删除主播
@app.route("/deleteAnchorWithIds", methods=['POST'])
def deleteAnchorWithIds():
@@ -366,6 +369,7 @@ def deleteAnchorWithIds():
deleted = AiUtils.delete_anchors_by_ids(ids)
return ResultData(data={"deleted": deleted}).toJson()
+
@app.route("/aiConfig", methods=['POST'])
def aiConfig():
data = request.get_json()
@@ -384,6 +388,7 @@ def aiConfig():
JsonUtils.write_json("aiConfig", dict)
return ResultData(data="").toJson()
+
# 查询主播聊天发送的最后一条信息
@app.route("/select_last_message", methods=['GET'])
def select_last_message():
@@ -427,5 +432,19 @@ def delete_last_message():
return ResultData(data=updated_count, msg="修改失败").toJson()
+# @app.route("/killWda", methods=['POST'])
+# def killWda():
+# data = request.get_json() # 解析 JSON
+# udid = data.get("device")
+# print(udid)
+#
+#
+# AiUtils.kill_wda(udid)
+# time.sleep(10)
+# AiUtils.launch_wda(udid)
+#
+# return ResultData(data="", msg="WDA重新启动").toJson()
+
+
if __name__ == '__main__':
app.run("0.0.0.0", port=5000, debug=True, use_reloader=False)
diff --git a/Utils/AiUtils.py b/Utils/AiUtils.py
index f4f7934..89052b8 100644
--- a/Utils/AiUtils.py
+++ b/Utils/AiUtils.py
@@ -1,11 +1,16 @@
import json
import os
+import shlex
+import subprocess
+import time
from pathlib import Path
import cv2
import numpy as np
import unicodedata
import wda
+
+from Entity.Variables import WdaAppBundleId
from Utils.LogManager import LogManager
import xml.etree.ElementTree as ET
import re, html
@@ -709,4 +714,72 @@ class AiUtils(object):
json.dump(data, f, ensure_ascii=False, indent=2)
except Exception as e:
LogManager.error(f"[delete_anchors_by_ids] 写入失败: {e}")
- return deleted
\ No newline at end of file
+ return deleted
+
+ @staticmethod
+ def run_tidevice_command(udid, action, bundle_id, timeout=30):
+ """
+ 执行tidevice命令的辅助函数
+
+ :param udid: 设备UDID
+ :param action: 动作类型 ('kill' 或 'launch')
+ :param bundle_id: 应用的Bundle ID
+ :param timeout: 命令执行超时时间(秒)
+ :return: (bool) 成功返回True,失败返回False
+ """
+ # 构建命令列表
+ cmd = ["tidevice", "--udid", udid, action, bundle_id]
+ try:
+ # 执行命令并捕获输出
+ result = subprocess.run(
+ cmd,
+ capture_output=True,
+ text=True,
+ timeout=timeout
+ )
+ # 检查命令是否成功执行(返回码为0通常表示成功)
+ if result.returncode == 0:
+ LogManager.info(f"Successfully {action}ed {bundle_id} on device {udid}.")
+ return True
+ else:
+ # 记录错误信息
+ LogManager.error(f"Failed to {action} {bundle_id} on device {udid}. Error: {result.stderr}")
+ return False
+
+ except subprocess.TimeoutExpired:
+ # 处理命令执行超时
+ LogManager.error(f"Command 'tidevice {action}' timed out after {timeout} seconds for device {udid}.")
+ return False
+ except FileNotFoundError:
+ # 处理tidevice命令未找到的情况(通常意味着tidevice未安装或不在PATH中)
+ LogManager.error("The 'tidevice' command was not found. Please ensure it is installed and in your system PATH.")
+ return False
+ except Exception as e:
+ # 捕获其他可能异常
+ LogManager.error(f"An unexpected error occurred while trying to {action} the app: {e}")
+ return False
+
+ @classmethod
+ def kill_wda(cls, udid, bundle_id="com.yolozsAgent.wda.xctrunner"):
+ """
+ 杀死指定设备上的WDA应用
+
+ :param udid: 设备UDID
+ :param bundle_id: WDA的Bundle ID,默认为 com.yolozsAgent.wda.xctrunner
+ :return: (bool) 成功返回True,失败返回False
+ """
+ return cls.run_tidevice_command(udid, "kill", bundle_id)
+
+ @classmethod
+ def launch_wda(cls, udid, bundle_id="com.yolozsAgent.wda.xctrunner", timeout=60):
+ """
+ 启动指定设备上的WDA应用
+
+ :param udid: 设备UDID
+ :param bundle_id: WDA的Bundle ID,默认为 com.yolozsAgent.wda.xctrunner
+ :param timeout: 启动命令超时时间,默认为60秒(启动可能较慢)
+ :return: (bool) 成功返回True,失败返回False
+ """
+ return cls.run_tidevice_command(udid, "launch", bundle_id, timeout)
+
+
diff --git a/Utils/JsonUtils.py b/Utils/JsonUtils.py
index 0dda46c..d63dcc3 100644
--- a/Utils/JsonUtils.py
+++ b/Utils/JsonUtils.py
@@ -179,17 +179,31 @@ class JsonUtils:
return updated
+ # @classmethod
+ # def query_all_json_items(cls, filename="log/last_message.json") -> list:
+ # """
+ # 查询 JSON 文件(数组)中的所有项
+ # :param filename: JSON 文件路径
+ # :return: list,可能为空
+ # """
+ # file_path = Path(filename)
+ # print(file_path)
+ # data = cls._read_json_list(file_path)
+ # return data if isinstance(data, list) else []
+
@classmethod
def query_all_json_items(cls, filename="log/last_message.json") -> list:
"""
- 查询 JSON 文件(数组)中的所有项
+ 查询 JSON 文件(数组)中的所有项,并剔除 sender 为空的记录
:param filename: JSON 文件路径
:return: list,可能为空
"""
file_path = Path(filename)
- print(file_path)
data = cls._read_json_list(file_path)
- return data if isinstance(data, list) else []
+ if not isinstance(data, list):
+ return []
+ # 过滤 sender 为空字符串的项
+ return [item for item in data if isinstance(item, dict) and item.get("sender", "").strip()]
@classmethod
def delete_json_items(cls,
diff --git a/Utils/LogManager.py b/Utils/LogManager.py
index a39050c..67e8a24 100644
--- a/Utils/LogManager.py
+++ b/Utils/LogManager.py
@@ -240,7 +240,7 @@ def _force_utf8_everywhere():
except Exception:
pass
-_force_utf8_everywhere()
+# _force_utf8_everywhere()
# ========= 全局:强制 UTF-8 + 关闭缓冲(运行期立刻生效) =========
diff --git a/Utils/Requester.py b/Utils/Requester.py
index 2e0dbe0..4dd6fe1 100644
--- a/Utils/Requester.py
+++ b/Utils/Requester.py
@@ -29,15 +29,19 @@ class Requester():
@classmethod
def translation(cls, msg, country="英国"):
try:
- parame = {
+ param = {
"msg": msg,
"country": country,
}
url = "https://ai.yolozs.com/translation"
- result = requests.request(url=url, json=parame, method="POST")
+ result = requests.post(url=url, json=param)
+
+ if result.status_code != 200:
+ LogManager.error(f"翻译失败,状态码:{result.status_code},服务器返回的内容:{result.text}")
+ return None
+
json = result.json()
data = json.get("data")
- print(data)
return data
except Exception as e:
LogManager.method_error(f"翻译失败,报错的原因:{e}", "翻译失败异常")
@@ -52,19 +56,25 @@ class Requester():
contact = aiConfig.get("contact", "")
inputs = {
- "agentName":agentName,
- "guildName":guildName,
- "contactTool":contactTool,
- "contact":contact
+ "name":agentName,
+ "Trade_union":guildName,
+ "contcat_method":contactTool,
+ "contcat_info":contact
}
param["inputs"] = inputs
+ print(param)
+
try:
url = "https://ai.yolozs.com/chat"
- result = requests.request(url=url, json=param, method="POST")
+ result = requests.post(url=url, json=param)
+
+
json = result.json()
- data = json.get("data", {})
- return data
+
+ data = json.get("answer", {})
+ session_id = json.get("conversation_id", {})
+ return data,session_id
except Exception as e:
LogManager.method_error(f"ai聊天失败,ai聊天出现异常,报错的原因:{e}", "ai聊天接口异常")
diff --git a/script/ScriptManager.py b/script/ScriptManager.py
index e2186c2..650b4db 100644
--- a/script/ScriptManager.py
+++ b/script/ScriptManager.py
@@ -145,10 +145,21 @@ class ScriptManager():
LogManager.method_error(f"刷视频过程出现错误,重试", "养号", udid)
raise e # 抛出给上层,触发重生机制
+ except wda.WDARequestError as e:
+ print(e)
+ LogManager.method_info("WDA 内部崩溃(nil 插入),准备重启 WDA", "养号", udid)
+ AiUtils.kill_wda(udid, ev.WdaAppBundleId)
+ time.sleep(1)
+ AiUtils.launch_wda(udid, ev.WdaAppBundleId)
except Exception as e:
- LogManager.method_error(f"[{udid}] 养号出现异常,将重启流程: {e}", "养号", udid)
retries += 1
- time.sleep(3) # 等待后重生
+ LogManager.method_error(f"greetNewFollowers 出现最终异常: {e},准备第 {retries} 次重试", "养号", udid)
+ time.sleep(3)
+ if retries:
+ LogManager.method_info("WDA 连接失败,准备重启 WDA", "养号", udid)
+ AiUtils.kill_wda(udid, ev.WdaAppBundleId)
+ time.sleep(1)
+ AiUtils.launch_wda(udid, ev.WdaAppBundleId)
# 观看直播
def watchLiveForGrowth(self, udid, event, max_retries=None):
@@ -285,11 +296,21 @@ class ScriptManager():
# break
self.greetNewFollowers(udid, needReply, event)
-
+ except wda.WDARequestError as e:
+ LogManager.method_info("WDA 内部崩溃(nil 插入),准备重启 WDA", "关注打招呼", udid)
+ AiUtils.kill_wda(udid, ev.WdaAppBundleId)
+ time.sleep(1)
+ AiUtils.launch_wda(udid, ev.WdaAppBundleId)
except Exception as e:
retries += 1
- LogManager.method_error(f"greetNewFollowers 出现异常: {e},准备第 {retries} 次重试", "关注打招呼", udid)
+ LogManager.method_error(f"greetNewFollowers 出现最终异常: {e},准备第 {retries} 次重试", "关注打招呼",
+ udid)
time.sleep(3)
+ if retries % 5 == 0:
+ LogManager.method_info("WDA 连接失败,准备重启 WDA", "关注打招呼", udid)
+ AiUtils.kill_wda(udid, ev.WdaAppBundleId)
+ time.sleep(1)
+ AiUtils.launch_wda(udid, ev.WdaAppBundleId)
LogManager.method_error("greetNewFollowers 重试次数耗尽,任务终止", "关注打招呼", udid)
# 关注打招呼以及回复主播消息
@@ -319,6 +340,7 @@ class ScriptManager():
# 返回上一步
def goBack(count):
for i in range(count):
+ session.appium_settings({"snapshotMaxDepth": 15})
ControlUtils.clickBack(session)
time.sleep(2)
@@ -567,19 +589,25 @@ class ScriptManager():
time.sleep(2)
ControlUtils.openTikTok(session, udid)
time.sleep(3)
-
+ retries = 0
while not event.is_set():
try:
# 调用检测消息的方法
self.monitorMessages(session, udid)
+ except wda.WDARequestError as e:
+ LogManager.method_info("WDA 内部崩溃(nil 插入),准备重启 WDA", "养号", udid)
+ AiUtils.kill_wda(udid, ev.WdaAppBundleId)
+ time.sleep(1)
+ AiUtils.launch_wda(udid, ev.WdaAppBundleId)
except Exception as e:
- LogManager.method_error(f"监控消息 出现异常: {e},重新启动监控直播", "检测消息", udid)
- # 出现异常时,稍等再重启 TikTok 并重试
- ControlUtils.closeTikTok(session, udid)
- time.sleep(2)
- ControlUtils.openTikTok(session, udid)
+ retries += 1
+ LogManager.method_error(f"greetNewFollowers 出现最终异常: {e},准备第 {retries} 次重试", "养号", udid)
time.sleep(3)
- continue # 重新进入 while 循环,调用 monitorMessages
+ if retries % 5 == 0:
+ LogManager.method_info("WDA 连接失败,准备重启 WDA", "养号", udid)
+ AiUtils.kill_wda(udid, ev.WdaAppBundleId)
+ time.sleep(1)
+ AiUtils.launch_wda(udid, ev.WdaAppBundleId)
# 检查未读消息并回复
def monitorMessages(self, session, udid):
@@ -725,6 +753,13 @@ class ScriptManager():
else:
last_msg_text = random.choice(text_list)
+ # 111111
+ if AiUtils.contains_chinese(last_msg_text):
+ LogManager.method_info(f"需要翻译:{last_msg_text}, 即将进行翻译", "检测消息", udid)
+
+ last_msg_text = Requester.translation(last_msg_text)
+ LogManager.method_info(f"翻译成功:{last_msg_text}, ", "检测消息", udid)
+
# 向ai发送信息
# 获取主播的名称
@@ -732,6 +767,10 @@ class ScriptManager():
LogManager.method_info(f"获取主播的名称:{anchor_name}", "检测消息", udid)
+ LogManager.method_info(f"获取主播最后发送的消息 进行翻译:{last_msg}", "检测消息", udid)
+ last_msg = Requester.translation(last_msg, "中国")
+ LogManager.method_info(f"翻译后的内容:{last_msg}", "检测消息", udid)
+
# 找到输入框
last_data = [{
"sender": anchor_name,
@@ -748,12 +787,14 @@ class ScriptManager():
if anchor_name not in anchorWithSession:
# 如果是第一次发消息(没有sessionId的情况)
- response = Requester.chatToAi({"query": last_msg_text})
- aiResult = response['result']
- sessionId = response['session_id']
+ aiResult, sessionId = Requester.chatToAi({"query": last_msg_text, "user": "1"})
+ # aiResult = response['result']
+ # sessionId = response['session_id']
anchorWithSession[anchor_name] = sessionId
# 找到输入框,输入ai返回出来的消息
+
+ # 123456
if sel.exists:
sel.click() # 聚焦
time.sleep(1)
@@ -766,8 +807,12 @@ class ScriptManager():
else:
# 如果不是第一次发消息(证明存储的有sessionId)
sessionId = anchorWithSession[anchor_name]
- response = Requester.chatToAi({"query": last_msg_text, "conversation_id": sessionId})
- aiResult = response['result']
+
+ # TODO: user后续添加,暂时写死
+
+ aiResult, sessionId = Requester.chatToAi(
+ {"query": last_msg_text, "conversation_id": sessionId, "user": "1"})
+ # aiResult = response['result']
if sel.exists:
sel.click() # 聚焦
time.sleep(1)