diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md index 84052f6c..0b95e1d3 100644 --- a/GETTING_STARTED.md +++ b/GETTING_STARTED.md @@ -171,8 +171,6 @@ Agent 会自己读代码、找出需要的包、全部装好。 python3 launch.pyw ``` -Windows 原生桌面窗口启动失败时,可运行 `python3 launch.pyw --browser` 使用浏览器版 Streamlit UI。 - 启动后会出现一个桌面悬浮窗,直接在里面输入任务指令。 ### 可选:让 Agent 帮你做的事 @@ -268,4 +266,4 @@ GenericAgent 不预设技能,而是**靠使用进化**。每完成一个新任 > Agent 会自动 pull 最新代码并解读 commit log,告诉你新增了什么能力。 -> 更多细节请参阅 [README.md](README.md) 或 [详细版图文教程](https://my.feishu.cn/wiki/CGrDw0T76iNFuskmwxdcWrpinPb)。 +> 更多细节请参阅 [README.md](README.md) 或 [详细版图文教程](https://my.feishu.cn/wiki/CGrDw0T76iNFuskmwxdcWrpinPb)。 \ No newline at end of file diff --git a/README.md b/README.md index 98748287..5d860a78 100644 --- a/README.md +++ b/README.md @@ -103,8 +103,6 @@ cp mykey_template.py mykey.py python launch.pyw ``` -Windows native shell fallback: if the desktop window fails during pywebview startup, run `python launch.pyw --browser` to use the Streamlit browser UI. - > GenericAgent is meant to grow its environment through the Agent itself, not by pre-installing every possible package. Full guide: [GETTING_STARTED.md](GETTING_STARTED.md) @@ -320,8 +318,6 @@ cp mykey_template.py mykey.py python launch.pyw ``` -Windows 原生桌面窗口启动失败时,可运行 `python launch.pyw --browser` 使用浏览器版 Streamlit UI。 - > GenericAgent 更推荐由 Agent 在使用中自举环境,而不是预先手动装完整依赖。 完整引导流程见 [GETTING_STARTED.md](GETTING_STARTED.md)。 diff --git a/launch.pyw b/launch.pyw index fc824b04..e5b148f2 100644 --- a/launch.pyw +++ b/launch.pyw @@ -1,10 +1,9 @@ -import threading, subprocess, sys, time, os, ctypes, atexit, socket, random, webbrowser, urllib.request +import webview, threading, subprocess, sys, time, os, ctypes, atexit, socket, random WINDOW_WIDTH, WINDOW_HEIGHT, RIGHT_PADDING, TOP_PADDING = 600, 900, 0, 100 script_dir = os.path.dirname(os.path.abspath(__file__)) frontends_dir = os.path.join(script_dir, "frontends") -window = proc = None def find_free_port(lo=18501, hi=18599): ports = list(range(lo, hi+1)); random.shuffle(ports) @@ -23,28 +22,6 @@ def start_streamlit(port): proc = subprocess.Popen(cmd) atexit.register(proc.kill) -def wait_for_streamlit(url, timeout=20): - deadline = time.time() + timeout - while time.time() < deadline: - try: - with urllib.request.urlopen(url, timeout=0.5): return True - except Exception: time.sleep(0.5) - return False - -def keep_streamlit_alive(): - try: - while proc and proc.poll() is None: time.sleep(1) - except KeyboardInterrupt: - if proc and proc.poll() is None: proc.kill() - -def open_browser_mode(port, reason=None): - url = f'http://localhost:{port}' - if reason: print(f'[Launch] Native window unavailable: {reason}') - wait_for_streamlit(url) - print(f'[Launch] Opening browser: {url}') - webbrowser.open(url) - keep_streamlit_alive() - def inject(text): window.evaluate_js(f""" const textarea = document.querySelector('textarea[data-testid="stChatInputTextArea"]'); @@ -85,10 +62,9 @@ PASTE_HOOK_JS = """if (!window._pasteHooked) { window._pasteHooked = true; }, true); }""" -def idle_monitor(stop_event=None): +def idle_monitor(): last_trigger_time = 0 while True: - if stop_event and stop_event.is_set(): return time.sleep(5) try: window.evaluate_js(PASTE_HOOK_JS) @@ -102,32 +78,10 @@ def idle_monitor(stop_event=None): except Exception as e: print(f'[Idle Monitor] Error: {e}') -def start_native_window(port): - global window - if os.name == 'nt': os.environ.setdefault('PYTHONNET_RUNTIME', 'coreclr') - import webview - if os.name == 'nt': - screen_width = get_screen_width() - x_pos = screen_width - WINDOW_WIDTH - RIGHT_PADDING - else: x_pos = 100 - time.sleep(2) - window = webview.create_window( - title='GenericAgent', url=f'http://localhost:{port}', - width=WINDOW_WIDTH, height=WINDOW_HEIGHT, x=x_pos, y=TOP_PADDING, - resizable=True, text_select=True) - monitor_stop = threading.Event() - monitor_thread = threading.Thread(target=idle_monitor, args=(monitor_stop,), daemon=True) - monitor_thread.start() - try: webview.start() - except Exception: - monitor_stop.set() - raise - if __name__ == '__main__': import argparse parser = argparse.ArgumentParser() parser.add_argument('port', nargs='?', default='0'); - parser.add_argument('--browser', action='store_true', help='Open Streamlit in the default browser') parser.add_argument('--tg', action='store_true', help='启动 Telegram Bot'); parser.add_argument('--qq', action='store_true', help='启动 QQ Bot'); parser.add_argument('--feishu', '--fs', dest='feishu', action='store_true', help='启动 Feishu Bot'); @@ -176,7 +130,15 @@ if __name__ == '__main__': print('[Launch] Task Scheduler started (duplicate prevented by scheduler port lock)') else: print('[Launch] Task Scheduler not enabled (--sched)') - if args.browser: open_browser_mode(port) - else: - try: start_native_window(port) - except Exception as e: open_browser_mode(port, e) + monitor_thread = threading.Thread(target=idle_monitor, daemon=True) + monitor_thread.start() + if os.name == 'nt': + screen_width = get_screen_width() + x_pos = screen_width - WINDOW_WIDTH - RIGHT_PADDING + else: x_pos = 100 + time.sleep(2) + window = webview.create_window( + title='GenericAgent', url=f'http://localhost:{port}', + width=WINDOW_WIDTH, height=WINDOW_HEIGHT, x=x_pos, y=TOP_PADDING, + resizable=True, text_select=True) + webview.start()