""" Web 版 Agent 界面 - 完整显示所有信息 Flask + SocketIO 实现实时双向通信 """ import asyncio import json import sys import threading import queue from pathlib import Path from datetime import datetime from flask import Flask, render_template_string from flask_socketio import SocketIO, emit # 导入 DeepSeek Agent 的核心类 from yuanbao_agent_chat import SoloAgent, ExecutionEngine app = Flask(__name__) app.config['SECRET_KEY'] = 'deepseek-agent-secret' socketio = SocketIO(app, cors_allowed_origins="*", async_mode='threading') # 全局状态 agent_instance = None browser_running = False message_queue = queue.Queue() # HTML 模板 HTML_TEMPLATE = ''' DeepSeek Agent - Web 控制台

🤖 DeepSeek Agent Web 控制台

浏览器未启动
DeepSeek 正在思考...
运行日志
命令终端
''' class WebInterface: """Web 界面适配器""" def __init__(self): self.socket = None def set_socket(self, socket): self.socket = socket def emit(self, event, data): socketio.emit(event, data) def print_user(self, message: str): """显示用户消息""" self.emit('user_message', { 'content': message, 'timestamp': datetime.now().strftime('%H:%M:%S') }) def print_ai(self, message: str, raw: str = ""): """显示 AI 消息""" self.emit('dp_message', { 'content': message, 'raw': raw, 'timestamp': datetime.now().strftime('%H:%M:%S') }) def print_system(self, message: str): """显示系统消息""" self.emit('system_message', { 'content': message, 'timestamp': datetime.now().strftime('%H:%M:%S') }) def print_error(self, message: str): """显示错误消息""" self.emit('error_message', { 'content': message, 'timestamp': datetime.now().strftime('%H:%M:%S') }) def log(self, category: str, message: str, level: str = "info"): """添加日志条目""" self.emit('log_entry', { 'time': datetime.now().strftime('%H:%M:%S'), 'category': category, 'message': message, 'level': level }) def update_browser_status(self, running: bool, message: str): """更新浏览器状态""" self.emit('browser_status', { 'running': running, 'message': message }) # 创建 Web 界面实例 web_interface = WebInterface() @app.route('/') def index(): return render_template_string(HTML_TEMPLATE) @socketio.on('connect') def handle_connect(): web_interface.set_socket(request.sid if hasattr(request, 'sid') else None) web_interface.update_browser_status(browser_running, '浏览器未启动') @socketio.on('disconnect') def handle_disconnect(): pass @socketio.on('start_browser') def handle_start_browser(): """启动浏览器""" global agent_instance, browser_running def start(): global agent_instance, browser_running try: web_interface.update_browser_status(False, '正在启动浏览器...') web_interface.log('BROWSER', '正在初始化 Playwright...') if agent_instance is None: agent_instance = SoloAgent() # 创建新的事件循环 loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) # 启动浏览器 loop.run_until_complete(agent_instance.start()) browser_running = True web_interface.update_browser_status(True, '浏览器已连接') web_interface.log('BROWSER', '浏览器启动成功', level='success') web_interface.print_system('🚀 浏览器已启动,可以开始对话了') loop.close() except Exception as e: browser_running = False web_interface.update_browser_status(False, '启动失败') web_interface.print_error(f'浏览器启动失败: {str(e)}') web_interface.log('ERROR', str(e), level='error') import traceback web_interface.log('ERROR', traceback.format_exc(), level='error') threading.Thread(target=start, daemon=True).start() @socketio.on('stop_browser') def handle_stop_browser(): """停止浏览器""" global agent_instance, browser_running def stop(): global agent_instance, browser_running try: if agent_instance: web_interface.log('BROWSER', '正在关闭浏览器...') loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(agent_instance.stop()) loop.close() agent_instance = None browser_running = False web_interface.update_browser_status(False, '浏览器已停止') web_interface.log('BROWSER', '浏览器已关闭', level='success') web_interface.print_system('浏览器已停止') except Exception as e: web_interface.print_error(f'关闭浏览器出错: {str(e)}') web_interface.log('ERROR', str(e), level='error') threading.Thread(target=stop, daemon=True).start() @socketio.on('user_input') def handle_user_input(data): """处理用户输入""" global browser_running if not browser_running or agent_instance is None: web_interface.print_error('浏览器未启动,请先启动浏览器') return content = data.get('content', '').strip() if not content: return # 显示用户消息 web_interface.print_user(content) web_interface.emit('typing', {}) # 在后台线程中处理 def process(): asyncio.run(process_user_input(content)) threading.Thread(target=process, daemon=True).start() async def process_user_input(user_input: str): """处理用户输入(异步)""" try: # 发送用户输入给 DeepSeek await agent_instance.send_message(user_input) # 等待并获取响应 response = await agent_instance.wait_for_response() if response: # 解析 ACTION action = agent_instance._parse_action(response) # 显示完整的原始响应 web_interface.print_ai(response, raw=response) # 记录日志 web_interface.log('AGENT', f'收到响应: {len(response)} 字符') if action: web_interface.log('ACTION', f'检测到 ACTION: {action.get("type")}') # 执行命令 result = await agent_instance.engine.execute( action.get('type', ''), action.get('cmd', ''), action.get('cwd', ''), action.get('content', ''), agent=agent_instance ) # 显示执行结果 output = result.get('output', '') web_interface.log('RESULT', f'执行结果: {output[:200]}...' if len(output) > 200 else f'执行结果: {output}') # 发送结果回 DeepSeek await agent_instance.send_result(output) else: web_interface.print_error('未收到 DeepSeek 的响应') except Exception as e: web_interface.print_error(f'处理出错: {str(e)}') import traceback web_interface.log('ERROR', traceback.format_exc(), level='error') @socketio.on('get_terminal_output') def handle_get_terminal(): """获取终端输出""" if agent_instance and agent_instance.engine: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) result = loop.run_until_complete( agent_instance.engine.execute('get_terminal_output', '', '', '', agent=agent_instance) ) loop.close() web_interface.emit('terminal_output', {'content': result.get('output', '')}) @socketio.on('clear_terminal') def handle_clear_terminal(): """清空终端""" if agent_instance and agent_instance.engine: loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) result = loop.run_until_complete( agent_instance.engine.execute('clear_terminal', '', '', '', agent=agent_instance) ) loop.close() web_interface.print_system('终端输出已清空') def main(): print("=" * 60) print("DeepSeek Agent Web 控制台") print("=" * 60) print(f"请打开浏览器访问: http://localhost:5000") print("=" * 60) # 启动 Flask-SocketIO 服务器 socketio.run(app, host='0.0.0.0', port=5000, debug=False, allow_unsafe_werkzeug=True) if __name__ == '__main__': main()