From 9ae045c93c60c734f2a34cc5f91395b3eb4e2ce4 Mon Sep 17 00:00:00 2001 From: Jiaqing Liang Date: Wed, 25 Feb 2026 12:56:40 +0800 Subject: [PATCH] launch: auto port discovery; simphtml: init newTabs; SOP docs update --- launch.pyw | 14 +++++++++++--- memory/ljqCtrl_sop.md | 2 +- memory/web_setup_sop.md | 6 +++++- simphtml.py | 2 +- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/launch.pyw b/launch.pyw index c3335b8..1b76487 100644 --- a/launch.pyw +++ b/launch.pyw @@ -1,7 +1,14 @@ -import webview, threading, subprocess, sys, time, os, ctypes, atexit, socket +import webview, threading, subprocess, sys, time, os, ctypes, atexit, socket, random WINDOW_WIDTH, WINDOW_HEIGHT, RIGHT_PADDING, TOP_PADDING = 600, 900, 0, 300 +def find_free_port(lo=8501, hi=8599): + ports = list(range(lo, hi+1)); random.shuffle(ports) + for p in ports: + try: s = socket.socket(); s.bind(('127.0.0.1', p)); s.close(); return p + except OSError: continue + raise RuntimeError(f'No free port in {lo}-{hi}') + def get_screen_width(): try: return ctypes.windll.user32.GetSystemMetrics(0) except: return 1920 @@ -55,12 +62,13 @@ def idle_monitor(): if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() - parser.add_argument('port', nargs='?', default='8501'); + parser.add_argument('port', nargs='?', default='0'); parser.add_argument('--no-tg', action='store_true', help='不启动 Telegram Bot'); parser.add_argument('--no-sched', action='store_true', help='不启动计划任务调度器') parser.add_argument('--llm_no', type=int, default=0, help='LLM编号') args = parser.parse_args() - port = args.port + port = str(find_free_port()) if args.port == '0' else args.port + print(f'[Launch] Using port {port}') threading.Thread(target=start_streamlit, args=(port,), daemon=True).start() if not args.no_tg: diff --git a/memory/ljqCtrl_sop.md b/memory/ljqCtrl_sop.md index 8cea674..9070d72 100644 --- a/memory/ljqCtrl_sop.md +++ b/memory/ljqCtrl_sop.md @@ -1,6 +1,6 @@ # ljqCtrl 使用与坐标转换 SOP -> **must call update_working_memory**:`ljqCtrl一律使用物理坐标|禁pyautogui|操作前先gw激活窗口` +> **must call update working ckp**:`ljqCtrl一律使用物理坐标|禁pyautogui|操作前先gw激活窗口` ## 0. API 快速参考 (Signatures) - `ljqCtrl.dpi_scale`: float (缩放系数 = 逻辑宽度 / 物理宽度) diff --git a/memory/web_setup_sop.md b/memory/web_setup_sop.md index 6f8bf70..a0049e7 100644 --- a/memory/web_setup_sop.md +++ b/memory/web_setup_sop.md @@ -56,8 +56,12 @@ browser = "chrome" if shutil.which("chrome") else "msedge" # Edge内置必存 ### 方案A(自动化,优先) 本地 HTTP 服务器 + TM 中间页,用 `start` 命令打开: 1. Python 启动 `http.server` 托管脚本(Content-Type: text/javascript) + - ⚠️ 必须用 `Popen(..., stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)` 丢弃输出 + - ❌ 禁用 `stdout=PIPE` 或 `stderr=PIPE`,会导致缓冲区满后服务器阻塞返回空响应 + - Windows 可加 `creationflags=subprocess.CREATE_NO_WINDOW` 避免弹窗 2. `start "" "https://www.tampermonkey.net/script_installation.php#url=http://127.0.0.1:{port}/ljq_web_driver.user.js"` - - ⚠️ 以上步骤均须用 `Popen` 非阻塞执行,禁止 `subprocess.run`,否则阻塞 agent + - ⚠️ 以上步骤均须用 `Popen` 非阻塞执行,禁止 `subprocess.run`(会等待进程结束) + - 服务器需持续运行直到用户完成安装,用 `Popen` 启动后立即返回继续执行 3. TM 秒弹安装确认,用户点"安装"即可 ### 方案B(手动 fallback) diff --git a/simphtml.py b/simphtml.py index 24cee2d..2a7067a 100644 --- a/simphtml.py +++ b/simphtml.py @@ -862,7 +862,7 @@ def get_html(driver, cutlist=False, maxchars=28000, instruction="", extra_js="") def execute_js_rich(script, driver): try: last_html = get_html(driver, cutlist=False, extra_js=temp_monitor_js) except: last_html = None - result = None; error_msg = None; reloaded = False + result = None; error_msg = None; reloaded = False; newTabs = [] before_sids = set(driver.get_session_dict().keys()) try: print(f"Executing: {script[:250]} ...")