feat:加入MaiSaKa(MaiBaKa?(MaiZako?))
This commit is contained in:
95
src/MaiDiary/debug_client.py
Normal file
95
src/MaiDiary/debug_client.py
Normal file
@@ -0,0 +1,95 @@
|
||||
"""
|
||||
MaiSaka - Debug Viewer 客户端
|
||||
在独立命令行窗口中显示每次 LLM 调用的完整 Prompt。
|
||||
通过 TCP socket 将数据发送给 debug_viewer.py 子进程。
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
from config import console
|
||||
|
||||
|
||||
class DebugViewer:
|
||||
"""
|
||||
在独立命令行窗口中显示每次 LLM 调用的完整 Prompt。
|
||||
|
||||
通过 TCP socket 将数据发送给 debug_viewer.py 子进程。
|
||||
"""
|
||||
|
||||
def __init__(self, port: int = 19876):
|
||||
self._port = port
|
||||
self._conn: Optional[socket.socket] = None
|
||||
self._process: Optional[subprocess.Popen] = None
|
||||
|
||||
def start(self):
|
||||
"""启动调试窗口子进程并建立 TCP 连接。"""
|
||||
script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "debug_viewer.py")
|
||||
|
||||
try:
|
||||
self._process = subprocess.Popen(
|
||||
[sys.executable, script_path, str(self._port)],
|
||||
creationflags=getattr(subprocess, "CREATE_NEW_CONSOLE", 0),
|
||||
)
|
||||
except Exception as e:
|
||||
console.print(f"[warning]⚠️ 无法启动调试窗口: {e}[/warning]")
|
||||
return
|
||||
|
||||
# 重试连接(等待子进程启动监听)
|
||||
for attempt in range(20):
|
||||
try:
|
||||
time.sleep(0.3)
|
||||
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
conn.connect(("127.0.0.1", self._port))
|
||||
self._conn = conn
|
||||
console.print(
|
||||
f"[success]✓ 调试窗口已启动[/success] [muted](port {self._port})[/muted]"
|
||||
)
|
||||
return
|
||||
except ConnectionRefusedError:
|
||||
conn.close()
|
||||
|
||||
console.print("[warning]⚠️ 无法连接到调试窗口(超时)[/warning]")
|
||||
|
||||
def send(self, label: str, messages: list, tools: Optional[list] = None, response: Optional[dict] = None):
|
||||
"""发送一次 LLM 调用的完整 prompt 和响应到调试窗口。"""
|
||||
if not self._conn:
|
||||
return
|
||||
|
||||
# 只在有响应时才发送(避免显示两次:请求中 + 完成响应)
|
||||
if response is None:
|
||||
return
|
||||
|
||||
payload = {"label": label, "messages": messages}
|
||||
if tools:
|
||||
payload["tools"] = tools
|
||||
payload["response"] = response
|
||||
|
||||
try:
|
||||
data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
|
||||
header = struct.pack(">I", len(data))
|
||||
self._conn.sendall(header + data)
|
||||
except Exception:
|
||||
# 连接断开时静默忽略
|
||||
self._conn = None
|
||||
|
||||
def close(self):
|
||||
"""关闭连接和子进程。"""
|
||||
if self._conn:
|
||||
try:
|
||||
self._conn.close()
|
||||
except Exception:
|
||||
pass
|
||||
self._conn = None
|
||||
if self._process:
|
||||
try:
|
||||
self._process.terminate()
|
||||
except Exception:
|
||||
pass
|
||||
self._process = None
|
||||
Reference in New Issue
Block a user