临时提交

This commit is contained in:
zw
2025-08-14 14:30:36 +08:00
parent 4c2bf5d8f2
commit f3fe7a661f
4 changed files with 67 additions and 36 deletions

View File

@@ -5,6 +5,8 @@ import threading
import warnings import warnings
from queue import Queue from queue import Queue
from typing import Any, Dict from typing import Any, Dict
from Utils.AiUtils import AiUtils
from Utils.Requester import Requester
import tidevice import tidevice
import wda import wda
@@ -72,6 +74,11 @@ listener_thread.start()
def passToken(): def passToken():
data = request.get_json() data = request.get_json()
accountToken = data['token'] accountToken = data['token']
print(accountToken)
Requester.requestComments()
return ResultData(data="").toJson() return ResultData(data="").toJson()
# 获取设备列表 # 获取设备列表
@@ -230,5 +237,16 @@ def addTempAnchorData():
addModelToAnchorList(data) addModelToAnchorList(data)
return ResultData(data="").toJson() return ResultData(data="").toJson()
# 获取当前屏幕上的聊天信息
@app.route("/getChatTextInfo", methods=['POST'])
def getChatTextInfo():
data = request.get_json()
udid = data.get("udid")
client = wda.USBClient(udid)
session = client.session()
xml = session.source()
result = AiUtils.extract_messages_from_xml(xml)
return ResultData(data=result).toJson()
if __name__ == '__main__': if __name__ == '__main__':
app.run("0.0.0.0", port=5000, debug=True, use_reloader=False) app.run("0.0.0.0", port=5000, debug=True, use_reloader=False)

View File

@@ -286,39 +286,59 @@ class AiUtils(object):
@classmethod @classmethod
def extract_messages_from_xml(cls, xml: str): def extract_messages_from_xml(cls, xml: str):
""" """
输入 WDA 的页面 XML输出按时间顺序的消息列表 仅返回当前屏幕中“可见的”聊天内容(含时间分隔)
每项形如:
{'type': 'time', 'text': '昨天 下午8:48'}
{'type': 'msg', 'dir': 'in'|'out', 'text': 'hello'}
""" """
from lxml import etree
root = etree.fromstring(xml.encode("utf-8")) root = etree.fromstring(xml.encode("utf-8"))
items = [] items = []
# 屏幕宽度(用于右对齐判断) # 屏幕宽度
app = root.xpath('/XCUIElementTypeApplication') app = root.xpath('/XCUIElementTypeApplication')
screen_w = cls.parse_float(app[0], 'width', 414.0) if app else 414.0 screen_w = cls.parse_float(app[0], 'width', 414.0) if app else 414.0
# 1) 时间分隔 # 找 Table 的可见范围
table = root.xpath('//XCUIElementTypeTable')
if table:
table = table[0]
table_top = cls.parse_float(table, 'y', 0.0)
table_h = cls.parse_float(table, 'height', 0.0)
table_bottom = table_top + table_h
else:
table_top, table_bottom = 0.0, cls.parse_float(app[0], 'height', 736.0) if app else 736.0
def in_view(el) -> bool:
"""元素在聊天区内并且可见"""
if el.get('visible') != 'true':
return False
y = cls.parse_float(el, 'y', -1e9)
h = cls.parse_float(el, 'height', 0.0)
by = y + h
return not (by <= table_top or y >= table_bottom)
# 时间分隔
for t in root.xpath('//XCUIElementTypeStaticText[contains(@traits, "Header")]'): for t in root.xpath('//XCUIElementTypeStaticText[contains(@traits, "Header")]'):
txt = t.get('label') or t.get('name') or t.get('value') or '' if not in_view(t):
y = cls.parse_float(t, 'y') continue
if txt.strip(): txt = (t.get('label') or t.get('name') or t.get('value') or '').strip()
items.append({'type': 'time', 'text': txt.strip(), 'y': y}) if txt:
items.append({'type': 'time', 'text': txt, 'y': cls.parse_float(t, 'y')})
# 2) 消息气泡
msg_nodes = root.xpath(
'//XCUIElementTypeTable//XCUIElementTypeCell'
'//XCUIElementTypeOther[@name or @label]'
)
# 消息气泡
EXCLUDES = {'Heart', 'Lol', 'ThumbsUp', '分享发布内容', '视频贴纸标签页', '双击发送表情'} EXCLUDES = {'Heart', 'Lol', 'ThumbsUp', '分享发布内容', '视频贴纸标签页', '双击发送表情'}
msg_nodes = table.xpath(
'.//XCUIElementTypeCell[@visible="true"]'
'//XCUIElementTypeOther[@visible="true" and (@name or @label) and not(ancestor::XCUIElementTypeCollectionView)]'
) if table is not None else []
for o in msg_nodes: for o in msg_nodes:
text = (o.get('label') or o.get('name') or '').strip() text = (o.get('label') or o.get('name') or '').strip()
if not text or text in EXCLUDES: if not text or text in EXCLUDES:
continue continue
if not in_view(o):
continue
# 拿到所在 Cell(用来找头像按钮) # 所在 Cell
cell = o.getparent() cell = o.getparent()
while cell is not None and cell.get('type') != 'XCUIElementTypeCell': while cell is not None and cell.get('type') != 'XCUIElementTypeCell':
cell = cell.getparent() cell = cell.getparent()
@@ -329,29 +349,20 @@ class AiUtils(object):
right_edge = x + w right_edge = x + w
direction = None direction = None
# 头像位置判定
# 2.1 依据同 Cell 内“图片头像”的位置判定(优先,最稳)
if cell is not None: if cell is not None:
avatar_btns = cell.xpath('.//XCUIElementTypeButton[@name="图片头像" or @label="图片头像"]') avatar_btns = cell.xpath(
'.//XCUIElementTypeButton[@visible="true" and (@name="图片头像" or @label="图片头像")]')
if avatar_btns: if avatar_btns:
ax = cls.parse_float(avatar_btns[0], 'x') ax = cls.parse_float(avatar_btns[0], 'x')
# 头像在左侧 → 对方;头像在右侧 → 自己 direction = 'in' if ax < (screen_w / 2) else 'out'
if ax < screen_w / 2: # 右对齐兜底
direction = 'in'
else:
direction = 'out'
# 2.2 退化规则:看是否右对齐
if direction is None: if direction is None:
# 离右边 <= 20px 视为右对齐(自己发的) direction = 'out' if right_edge > (screen_w - 20) else 'in'
if right_edge > screen_w - 20:
direction = 'out'
else:
direction = 'in'
items.append({'type': 'msg', 'dir': direction, 'text': text, 'y': y}) items.append({'type': 'msg', 'dir': direction, 'text': text, 'y': y})
# 3) 按 y 排序并清理 # 排序 & 清理
items.sort(key=lambda i: i['y']) items.sort(key=lambda i: i['y'])
for it in items: for it in items:
it.pop('y', None) it.pop('y', None)

View File

@@ -8,6 +8,7 @@ BaseUrl = "http://192.168.1.174:8101/api/common/"
class Requester(): class Requester():
comment = "comment" comment = "comment"
prologue = "prologue" prologue = "prologue"
@classmethod @classmethod
def requestComments(cls): def requestComments(cls):
headers = { headers = {

View File

@@ -317,10 +317,9 @@ class ScriptManager():
if chatInput.exists: if chatInput.exists:
print("找到输入框了, 准备发送一条打招呼消息") print("找到输入框了, 准备发送一条打招呼消息")
# 准备打招呼的文案 # 准备打招呼的文案
# text = random.choice(prologueList) text = random.choice(prologueList)
text = "你好"
# 翻译成主播国家的语言 # 翻译成主播国家的语言
msg = Requester.translation(text, "法国") msg = Requester.translation(text, anchorCountry)
# 准备发送一条信息 # 准备发送一条信息
chatInput.click() chatInput.click()
time.sleep(2) time.sleep(2)
@@ -329,6 +328,8 @@ class ScriptManager():
time.sleep(1) time.sleep(1)
else: else:
print("无法发送信息") print("无法发送信息")
LogManager.error(f"给主播{anchor.anchorId} 发送消息失败", udid)
# 接着下一个主播 # 接着下一个主播
removeModelFromAnchorList(anchor) removeModelFromAnchorList(anchor)
goBack(4) goBack(4)