feat(ui): 新增一键上传日志报告功能

This commit is contained in:
XcantloadX 2025-02-26 16:14:07 +08:00
parent b11126e426
commit 62d5805b96
4 changed files with 192 additions and 4 deletions

View File

@ -276,7 +276,7 @@ def clear_saved():
logger.info("Clearing debug saved files...")
if debug.auto_save_to_folder:
try:
shutil.rmtree(debug.auto_save_to_folder)
shutil.rmtree(debug.auto_save_to_folder, ignore_errors=True)
logger.info(f"Cleared debug saved files: {debug.auto_save_to_folder}")
except PermissionError:
logger.error(f"Failed to clear debug saved files: {debug.auto_save_to_folder}")

View File

@ -0,0 +1,36 @@
import requests
import os
def upload(file_path: str) -> str:
"""
上传文件到 paste.sensio.no
Args:
file_path: 要上传的文件路径
Returns:
str: 上传后的 URL
"""
url = 'https://paste.sensio.no/'
headers = {
'accept': 'text/plain',
'User-Agent': 'KAA',
'x-uuid': ''
}
files = {
'file': (os.path.basename(file_path), open(file_path, 'rb'))
}
response = requests.post(url, files=files, headers=headers, allow_redirects=False)
if response.status_code != 200:
raise Exception(f"Upload failed with status code {response.status_code}")
return response.text.strip()
if __name__ == "__main__":
test_file = "version"
if os.path.exists(test_file):
result = upload(test_file)
print(f"Upload result: {result}")

View File

@ -0,0 +1,54 @@
import requests
import os
def upload(file_path: str) -> str:
url = 'https://tmpsend.com/upload'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36',
'Referer': 'https://tmpsend.com/',
}
file_name = os.path.basename(file_path)
file_size = os.path.getsize(file_path)
# 第一次请求:添加文件信息
files = {
'action': (None, 'add'),
'name': (None, file_name),
'size': (None, str(file_size)),
'file': (file_name, open(file_path, 'rb'))
}
response = requests.post(url, headers=headers, files=files)
if response.status_code != 200:
raise Exception(f"Upload failed with status code {response.status_code}")
result = response.json()
if result.get('hasError'):
raise Exception(result.get('error'))
file_id = result.get('id')
if not file_id:
raise Exception("Failed to get file ID")
# 第二次请求:上传实际文件
upload_files = {
'action': (None, 'upload'),
'id': (None, file_id),
'name': (None, file_name),
'size': (None, str(file_size)),
'start': (None, '0'),
'end': (None, str(file_size)),
'data': (file_name, open(file_path, 'rb'), 'application/octet-stream')
}
upload_response = requests.post(url, headers=headers, files=upload_files)
if upload_response.status_code != 200:
raise Exception(f"File upload failed with status code {upload_response.status_code}")
return 'https://tmpsend.com/' + file_id
if __name__ == "__main__":
file_path = r"主题1.thmx"
print(upload(file_path))

View File

@ -1,10 +1,12 @@
import os
import zipfile
import logging
from datetime import datetime
from typing import List, Dict, Tuple, Literal
from functools import partial
from datetime import datetime, timedelta
from typing import List, Dict, Tuple, Literal, Generator
import importlib.metadata
import cv2
import gradio as gr
from kotonebot.backend.context import task_registry
@ -34,6 +36,95 @@ root_logger.addHandler(file_handler)
logging.getLogger("kotonebot").setLevel(logging.DEBUG)
def _save_bug_report(
path: str
) -> Generator[str, None, str]:
"""
保存错误报告
:param path: 保存的路径若为 `None`则保存到 `./reports/{YY-MM-DD HH-MM-SS}.zip`
:return: 保存的路径
"""
from kotonebot import device
from kotonebot.backend.context import ContextStackVars
# 确保目录存在
os.makedirs('logs', exist_ok=True)
os.makedirs('reports', exist_ok=True)
error = ""
with zipfile.ZipFile(path, 'w', zipfile.ZIP_DEFLATED, compresslevel=9) as zipf:
# 打包截图
yield "### 打包上次截图..."
try:
stack = ContextStackVars.current()
screenshot = None
if stack is not None:
screenshot = stack._screenshot
if screenshot is not None:
img = cv2.imencode('.png', screenshot)[1].tobytes()
zipf.writestr('last_screenshot.png', img)
if screenshot is None:
error += "无上次截图数据\n"
except Exception as e:
error += f"保存上次截图失败:{str(e)}\n"
# 打包当前截图
yield "### 打包当前截图..."
try:
screenshot = device.screenshot()
img = cv2.imencode('.png', screenshot)[1].tobytes()
zipf.writestr('current_screenshot.png', img)
except Exception as e:
error += f"保存当前截图失败:{str(e)}\n"
# 打包配置文件
yield "### 打包配置文件..."
try:
with open('config.json', 'r', encoding='utf-8') as f:
zipf.writestr('config.json', f.read())
except Exception as e:
error += f"保存配置文件失败:{str(e)}\n"
# 打包 logs 文件夹
if os.path.exists('logs'):
for root, dirs, files in os.walk('logs'):
for file in files:
file_path = os.path.join(root, file)
arcname = os.path.join('logs', os.path.relpath(file_path, 'logs'))
zipf.write(file_path, arcname)
yield f"### 打包 log 文件:{arcname}"
# 打包 reports 文件夹
if os.path.exists('reports'):
for root, dirs, files in os.walk('reports'):
for file in files:
file_path = os.path.join(root, file)
arcname = os.path.join('reports', os.path.relpath(file_path, 'reports'))
zipf.write(file_path, arcname)
yield f"### 打包 report 文件:{arcname}"
# 上传报告
from .file_host.sensio import upload
yield "### 上传报告..."
url = ''
try:
url = upload(path)
except Exception as e:
yield f"### 上传报告失败:{str(e)}\n\n"
return ''
final_msg = f"### 报告导出成功:{url}\n\n"
expire_time = datetime.now() + timedelta(days=7)
if error:
final_msg += f"### 但发生了以下错误\n\n"
final_msg += '\n* '.join(error.strip().split('\n'))
final_msg += '\n'
final_msg += f"### 此链接将于 {expire_time.strftime('%Y-%m-%d %H:%M:%S')}7 天后)过期\n\n"
final_msg += '### 复制以上文本并反馈给开发者'
yield final_msg
return path
class KotoneBotUI:
def __init__(self) -> None:
self.is_running: bool = False
@ -232,6 +323,7 @@ class KotoneBotUI:
with gr.Row():
run_btn = gr.Button("启动", scale=1)
debug_btn = gr.Button("调试", scale=1)
gr.Markdown("脚本报错或者卡住?点击“日志”选项卡中的“一键导出报告”可以快速反馈!")
task_status = gr.Dataframe(
headers=["任务", "状态"],
@ -577,6 +669,8 @@ class KotoneBotUI:
with gr.Row():
export_dumps_btn = gr.Button("导出 dump")
export_logs_btn = gr.Button("导出日志")
with gr.Row():
save_report_btn = gr.Button("一键导出报告")
result_text = gr.Markdown("等待操作\n\n\n")
export_dumps_btn.click(
@ -587,6 +681,10 @@ class KotoneBotUI:
fn=self.export_logs,
outputs=[result_text]
)
save_report_btn.click(
fn=partial(_save_bug_report, path='report.zip'),
outputs=[result_text]
)
def _load_config(self) -> None:
# 加载配置文件
@ -624,4 +722,4 @@ def main() -> None:
app.launch(inbrowser=True)
if __name__ == "__main__":
main()
main()