临时提交

This commit is contained in:
2025-09-20 21:57:37 +08:00
parent bfdf684952
commit 8f290cf610
25 changed files with 343 additions and 87 deletions

View File

@@ -336,6 +336,7 @@ class AiUtils(object):
screen_h = cls.parse_float(app[0], 'height', 736.0) if app else 736.0
# ---------- 主容器探测(评分选择最像聊天区的容器) ----------
def pick_container():
cands = []
for xp, ctype in (
@@ -706,7 +707,7 @@ class AiUtils(object):
data.extend(to_add)
cls._write_json_list(file_path, data)
LogManager.method_info(f"写入的路径是:{file_path}", "写入数据")
# LogManager.method_info(f"写入的路径是:{file_path}", "写入数据")
LogManager.info(f"[acList] 已追加 {len(to_add)} 条,当前总数={len(data)} -> {file_path}")
@@ -842,24 +843,25 @@ class AiUtils(object):
ids.append(str(it["anchorId"]))
return ids
@classmethod
def delete_anchors_by_ids(cls, ids: list[str], filename="log/acList.json") -> int:
def delete_anchors_by_ids(cls, ids: list[str], filename: str = "acList.json") -> int:
"""
根据 anchorId 列表根目录/log/acList.json 中删除匹配的 anchor。
返回删除数量。
根据 anchorId 列表,从项目根目录/log/acList.json 中删除匹配的 anchor。
- ids: 要删除的 anchorId 列表
- filename: 默认为 acList.json可以传文件名或绝对路径
返回:删除数量
"""
# 确保路径固定在根目录下的 log 文件夹
# 计算文件路径
root_dir = Path(__file__).resolve().parent.parent
file_path = root_dir / "log" / filename
if Path(filename).is_absolute():
file_path = Path(filename)
else:
file_path = root_dir / "log" / filename
if not file_path.exists():
return 0
# 读取 JSON 文件
try:
with open(file_path, "r", encoding="utf-8") as f:
data = json.load(f)
@@ -870,10 +872,12 @@ class AiUtils(object):
return 0
before = len(data)
# 保留不在 ids 里的对象
data = [d for d in data if isinstance(d, dict) and d.get("anchorId") not in ids]
deleted = before - len(data)
# 写回 JSON 文件
try:
file_path.parent.mkdir(parents=True, exist_ok=True)
with open(file_path, "w", encoding="utf-8") as f:

66
Utils/IOSAIStorage.py Normal file
View File

@@ -0,0 +1,66 @@
import json
from pathlib import Path
class IOSAIStorage:
@staticmethod
def _get_iosai_dir() -> Path:
"""获取 C:/Users/<用户名>/IOSAI/ 目录"""
user_dir = Path.home()
iosai_dir = user_dir / "IOSAI"
iosai_dir.mkdir(parents=True, exist_ok=True)
return iosai_dir
@classmethod
def save(cls, data: dict | list, filename: str = "data.json") -> Path:
"""
存储数据到 C:/Users/<用户名>/IOSAI/filename
"""
file_path = cls._get_iosai_dir() / filename
try:
with open(file_path, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"[IOSAIStorage] 已保存到: {file_path}")
except Exception as e:
print(f"[IOSAIStorage] 写入失败: {e}")
return file_path
@classmethod
def load(cls, filename: str = "data.json") -> dict | list | None:
"""
从 C:/Users/<用户名>/IOSAI/filename 读取数据
"""
file_path = cls._get_iosai_dir() / filename
if not file_path.exists():
print(f"[IOSAIStorage] 文件不存在: {file_path}")
return {}
try:
with open(file_path, "r", encoding="utf-8") as f:
return json.load(f)
except Exception as e:
print(f"[IOSAIStorage] 读取失败: {e}")
return {}
@classmethod
def overwrite(cls, data: dict | list, filename: str = "data.json") -> Path:
"""
强制覆盖写入数据到 C:/Users/<用户名>/IOSAI/filename
(无论是否存在,都会写入)
"""
file_path = cls._get_iosai_dir() / filename
try:
# "w" 模式本身就是覆盖,但这里单独做一个方法
with open(file_path, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"[IOSAIStorage] 已覆盖写入: {file_path}")
except Exception as e:
print(f"[IOSAIStorage] 覆盖失败: {e}")
return file_path

View File

@@ -142,7 +142,7 @@ class JsonUtils:
data.extend(items)
LogManager.method_info(filename,"路径")
# LogManager.method_info(filename,"路径")
cls._write_json_list(file_path, data)

View File

@@ -1,5 +1,6 @@
import requests
from Entity.Variables import prologueList
from Utils.IOSAIStorage import IOSAIStorage
from Utils.JsonUtils import JsonUtils
from Utils.LogManager import LogManager
@@ -56,6 +57,7 @@ class Requester():
@classmethod
def chatToAi(cls, param):
aiConfig = JsonUtils.read_json("aiConfig")
aiConfig = IOSAIStorage.load("aiConfig.json")
agentName = aiConfig.get("agentName")
guildName = aiConfig.get("guildName")
contactTool = aiConfig.get("contactTool", "")

View File

@@ -67,13 +67,6 @@ class ThreadManager:
@classmethod
def batch_stop(cls, udids: List[str]) -> Tuple[int, List[str], str]:
"""
批量停止任务——瞬间下发停止信号,仍统计失败结果。
返回格式与原接口 100% 兼容:
(code, fail_list, msg)
code=200 全部成功
code=1001 部分/全部失败
"""
if not udids:
return 200, [], "无设备需要停止"
@@ -83,48 +76,53 @@ class ThreadManager:
with cls._lock:
for udid in udids:
task = cls._tasks.get(udid)
if not task or not task.get("running"):
# fail_list.append(f"设备{udid}停止失败:当前设备没有执行相关任务")
continue
task["event"].set() # 下发停止信号
if task and task.get("running"):
task["event"].set()
# ---------- 2. 并发等 0.2 s 收尾 ----------
def _wait_and_clean(udid: str) -> Tuple[int, str]:
with cls._lock:
task = cls._tasks.get(udid)
if not task:
return 400, "任务记录已丢失"
thread = task["thread"]
# 第一次等 3 秒,让“分片睡眠”有机会退出
thread.join(timeout=3)
# 如果还活,再补 2 秒
if thread.is_alive():
thread.join(timeout=2)
# 最终仍活,记录日志但不硬杀,避免僵尸
with cls._lock:
cls._tasks.pop(udid, None)
if thread.is_alive():
LogManager.warning(f"[batch_stop] 线程 5s 未退出,已清理记录但线程仍跑 {udid}")
return 201, "已下发停止,线程超长任务未立即结束"
return 200, "已停止"
# ---------- 2. 单设备重试 5 次 ----------
def _wait_and_clean_with_retry(udid: str) -> Tuple[int, List[str], str]:
"""
内部重试 5 次,最终返回格式与 batch_stop 完全一致:
(code, fail_list, msg) fail_list 空表示成功
"""
for attempt in range(1, 6):
with cls._lock:
task = cls._tasks.get(udid)
if not task:
return 200, [], "任务已不存在" # 成功
thread = task["thread"]
thread.join(timeout=5)
still_alive = thread.is_alive()
# 最后一次重试才清理记录
if attempt == 5:
with cls._lock:
cls._tasks.pop(udid, None)
if not still_alive:
return 200, [], "已停止"
LogManager.warning(f"[batch_stop] {udid}{attempt}/5 次停止未立即结束,重试", udid)
# 5 次都失败
LogManager.error(f"[batch_stop] {udid} 停止失败5 次重试后线程仍活)", udid)
return 1001, [udid], "部分设备停止失败"
# ---------- 3. 并发执行 ----------
with ThreadPoolExecutor(max_workers=min(32, len(udids))) as executor:
future_map = {executor.submit(_wait_and_clean, udid): udid for udid in udids}
future_map = {executor.submit(_wait_and_clean_with_retry, udid): udid for udid in udids}
for future in as_completed(future_map):
udid = future_map[future]
try:
code, reason = future.result()
if code != 200:
fail_list.append(f"设备{udid}停止失败:{reason}")
except Exception as exc:
fail_list.append(f"设备{udid}停止异常:{exc}")
code, sub_fail_list, sub_msg = future.result() # ← 现在解包正确
if code != 200:
fail_list.extend(sub_fail_list) # 收集失败 udid
# ---------- 3. 返回兼容格式 ----------
# ---------- 4. 返回兼容格式 ----------
if fail_list:
return 1001, fail_list, "部分设备停止失败"
return 200, [], "全部设备停止成功"
@classmethod
def is_task_running(cls, udid: str) -> bool:
"""