From 8cfafe119d2c342f67bdc68391a5ca21701eb3d1 Mon Sep 17 00:00:00 2001 From: Liang Jiaqing Date: Mon, 9 Feb 2026 09:24:53 +0800 Subject: [PATCH] Refactor: decouple task queues, add JS injection support, and simplify stapp rendering --- agentmain.py | 15 +++++++-------- launch.pyw | 19 ++++++++++++++----- stapp.py | 38 +++++++++++--------------------------- 3 files changed, 32 insertions(+), 40 deletions(-) diff --git a/agentmain.py b/agentmain.py index dec1bbc..9a45e09 100644 --- a/agentmain.py +++ b/agentmain.py @@ -61,16 +61,15 @@ class GeneraticAgent: self.handler.code_stop_signal.append(1) def put_task(self, query, source="user"): - while self.display_queue.qsize() > 0: - try: self.display_queue.get_nowait() - except queue.Empty: break - self.task_queue.put({"query": query, "source": source}) + display_queue = queue.Queue() + self.task_queue.put({"query": query, "source": source, "output": display_queue}) + return display_queue def run(self): while True: task = self.task_queue.get() self.is_running = True - raw_query, source = task["query"], task["source"] + raw_query, source, display_queue = task["query"], task["source"], task["output"] self.current_source = source self.last_active_time = time.time() @@ -90,15 +89,15 @@ class GeneraticAgent: if self.stop_sig: break full_response += chunk if len(full_response) - last_pos > 50: - self.display_queue.put({'next': f'{full_response}', 'source': source}) + display_queue.put({'next': f'{full_response}', 'source': source}) last_pos = len(full_response) if '' in full_response: full_response = full_response.replace('', '\n\n') if '' in full_response: full_response = re.sub(r'\s*(.*?)\s*', r'\n````\n\n\1\n\n````', full_response, flags=re.DOTALL) - self.display_queue.put({'done': full_response, 'source': source}) + display_queue.put({'done': full_response, 'source': source}) self.history = handler.history_info except Exception as e: print(f"Backend Error: {format_error(e)}") - self.display_queue.put({'done': full_response + f'\n```\n{format_error(e)}\n```', 'source': source}) + display_queue.put({'done': full_response + f'\n```\n{format_error(e)}\n```', 'source': source}) finally: self.is_running = False self.stop_sig = False diff --git a/launch.pyw b/launch.pyw index 90f1931..06f732f 100644 --- a/launch.pyw +++ b/launch.pyw @@ -12,12 +12,9 @@ TOP_PADDING = 300 # 离屏幕上边缘的距离 def get_screen_width(): try: - # GetSystemMetrics(0) 获取主屏幕宽度 user32 = ctypes.windll.user32 return user32.GetSystemMetrics(0) - except: - # 如果不是 Windows 或者出错了,返回一个兜底值 (比如 1920) - return 1920 + except: return 1920 def start_streamlit(port): global proc @@ -30,6 +27,18 @@ def start_streamlit(port): proc = subprocess.Popen(cmd) atexit.register(proc.kill) +def inject(text): + """注入输入到 Streamlit""" + window.evaluate_js(f""" + const input = document.querySelector('input[data-testid="stChatInputTextInput"]'); + if (input) {{ + input.value = {repr(text)}; + input.dispatchEvent(new Event('input', {{bubbles: true}})); + input.dispatchEvent(new KeyboardEvent('keydown', {{key: 'Enter', keyCode: 13, bubbles: true}})); + }} + """) + + if __name__ == '__main__': port = sys.argv[1] if len(sys.argv) > 1 else "8501" t = threading.Thread(target=start_streamlit, args=(port,), daemon=True) @@ -39,7 +48,7 @@ if __name__ == '__main__': x_pos = screen_width - WINDOW_WIDTH - RIGHT_PADDING else: x_pos = 100 time.sleep(2) - webview.create_window( + window = webview.create_window( title='GenericAgent', url=f'http://localhost:{port}', width=WINDOW_WIDTH, diff --git a/stapp.py b/stapp.py index 40ce496..116e314 100644 --- a/stapp.py +++ b/stapp.py @@ -23,12 +23,6 @@ agent = init() st.title("🖥️ Cowork") -if "idle_buf" not in st.session_state: st.session_state.idle_buf = "" -if "messages" not in st.session_state: st.session_state.messages = [] - -for msg in st.session_state.messages: - with st.chat_message(msg["role"]): st.markdown(msg["content"]) - @st.fragment def render_llm_switcher(): current_idx = agent.llm_no @@ -44,36 +38,22 @@ def render_llm_switcher(): st.toast("下次将重新注入System Prompt") with st.sidebar: render_llm_switcher() -@st.fragment(run_every="1s") -def global_queue_listener(): - if agent.current_source == 'auto': - while not agent.display_queue.empty(): - item = agent.display_queue.get() - if item.get('source') == 'auto': - if 'next' in item: st.session_state.idle_buf = item['next'] - if 'done' in item: - st.session_state.messages.append({"role": "assistant", "content": f"🤖 {item['done']}"}) - st.session_state.idle_buf = ""; st.rerun() - if st.session_state.get("idle_buf"): - with st.chat_message("assistant"): - st.write(st.session_state.idle_buf + "▌") - else: - st.caption("🟢 Agent Listener Active", help=f"Last sync: {int(time.time())}") - st.session_state.idle_buf = "" - -global_queue_listener() def agent_backend_stream(prompt): - agent.put_task(prompt, source="user") + display_queue = agent.put_task(prompt, source="user") try: while True: - item = agent.display_queue.get() + item = display_queue.get() if 'next' in item: yield item['next'] if 'done' in item: yield item['done']; break finally: agent.abort() +if "messages" not in st.session_state: st.session_state.messages = [] +for msg in st.session_state.messages: + with st.chat_message(msg["role"]): st.markdown(msg["content"]) + if prompt := st.chat_input("请输入指令"): st.session_state.messages.append({"role": "user", "content": prompt}) with st.chat_message("user"): st.markdown(prompt) @@ -84,4 +64,8 @@ if prompt := st.chat_input("请输入指令"): for response in agent_backend_stream(prompt): message_placeholder.markdown(response + "▌") message_placeholder.markdown(response) - st.session_state.messages.append({"role": "assistant", "content": response}) \ No newline at end of file + st.session_state.messages.append({"role": "assistant", "content": response}) + st.session_state.last_reply_time = int(time.time()) + +st.markdown(f"""""", unsafe_allow_html=True) +