Files
GenericAgent/launch.pyw

101 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
def start_streamlit(port):
global proc
cmd = [sys.executable, "-m", "streamlit", "run", "stapp.py", "--server.port", str(port), "--server.headless", "true", "--theme.base", "dark"] # 暗黑模式
proc = subprocess.Popen(cmd)
atexit.register(proc.kill)
def inject(text):
window.evaluate_js(f"""
const textarea = document.querySelector('textarea[data-testid="stChatInputTextArea"]');
if (textarea) {{
// 1. 用原生 setter 设置值(绕过 React
const nativeTextAreaValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, 'value').set;
nativeTextAreaValueSetter.call(textarea, {repr(text)});
// 2. 触发 React 的 input 事件
textarea.dispatchEvent(new Event('input', {{ bubbles: true }}));
// 3. 触发 change 事件(有些组件需要)
textarea.dispatchEvent(new Event('change', {{ bubbles: true }}));
// 4. 延迟提交
setTimeout(() => {{
const btn = document.querySelector('[data-testid="stChatInputSubmitButton"]');
if (btn) {{btn.click();console.log('Submitted:', {repr(text)});}}
}}, 200);
}}""")
def get_last_reply_time():
last = window.evaluate_js("""
const el = document.getElementById('last-reply-time');
el ? parseInt(el.textContent) : 0;
""") or 0
return last or int(time.time())
def idle_monitor():
last_trigger_time = 0
while True:
time.sleep(5)
try:
now = time.time()
if now - last_trigger_time < 120: continue
last_reply = get_last_reply_time()
if now - last_reply > 1800:
print('[Idle Monitor] Detected idle state, injecting task...')
inject("[AUTO]🤖 用户已经离开超过30分钟作为自主智能体请阅读自动化sop执行自动任务。")
last_trigger_time = now
except Exception as e:
print(f'[Idle Monitor] Error: {e}')
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('port', nargs='?', default='0');
parser.add_argument('--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 = 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 args.tg:
tgproc = subprocess.Popen([sys.executable, "tgapp.py"], creationflags=subprocess.CREATE_NO_WINDOW if os.name=='nt' else 0)
atexit.register(tgproc.kill)
print('[Launch] Telegram Bot started')
else: print('[Launch] Telegram Bot not enabled (use --tg to start)')
if not args.no_sched:
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM); sock.bind(('127.0.0.1', 45762)); sock.listen(1)
scheduler_proc = subprocess.Popen([sys.executable, "agentmain.py", "--scheduled", "--llm_no", str(args.llm_no)], creationflags=subprocess.CREATE_NO_WINDOW if os.name=='nt' else 0);
atexit.register(lambda: (scheduler_proc.kill(), sock.close()))
print('[Launch] Task Scheduler started')
except OSError:
print('[Launch] Task Scheduler already running (port occupied)')
else: print('[Launch] Task Scheduler disabled (--no-sched)')
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()