临时提交
This commit is contained in:
@@ -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
66
Utils/IOSAIStorage.py
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ class JsonUtils:
|
||||
|
||||
data.extend(items)
|
||||
|
||||
LogManager.method_info(filename,"路径")
|
||||
# LogManager.method_info(filename,"路径")
|
||||
cls._write_json_list(file_path, data)
|
||||
|
||||
|
||||
|
||||
@@ -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", "")
|
||||
|
||||
@@ -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:
|
||||
"""
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user