from flask import Flask, redirect, session, request, jsonify, render_template, send_from_directory, url_for from flask_cors import CORS from flask_socketio import SocketIO, join_room, emit, Namespace import markdown import os import uuid import shutil import sys import json parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) sys.path.insert(0, parent_dir) current_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '.')) sys.path.insert(0, current_dir) from AlgoriAgent.projects.algoriAgent.agent_manager import AgentManager app = Flask(__name__) socketio = SocketIO(app, cors_allowed_origins="*",ping_timeout=60, ping_interval=5) # socketio = SocketIO(app, cors_allowed_origins="http://localhost:9888") # 设置跨域支持 import logging app.secret_key = 'cakebaker' app.logger.setLevel(logging.DEBUG) # 配置 CORS CORS(app, resources={r"/*": {"origins": "http://127.0.0.1:9090"},}, supports_credentials=True) userid_recorder = {} # user_id&path -> session['user_id'] ''' Backboard ''' from backboardManager import BackBoardManager, Backboard backboard_manager = BackBoardManager() uuid2user_id = {} user_id2uuid = {} # 定义命名空间:用于和 VSCode 插件交流 class VSCodeNamespace(Namespace): def on_login(self,data): print("VSCode client connected") print(data) dataconfig = data['config'] user_id = dataconfig.get('user_id') path = dataconfig.get('path') print(f"User {user_id} connected with path: {path}") useruuid = user_id2uuid[user_id] join_room(useruuid, namespace='/vscode') if backboard_manager.get_backboard(useruuid) == None: backboard_manager.add_backboard(useruuid, path) def on_message(self, data): print(f"Received from VSCode client: {data}") dataconfig = data['config'] realtime_response(dataconfig, data) # emit('response', {'message': 'Config data received and connection established'}) def on_disconnect(self): print("VSCode client disconnected") def realtime_response(config, realtime_action): user_id = config['user_id'] folder_path = config['path'] useruuid = user_id2uuid[user_id] bb = backboard_manager.get_backboard(useruuid) assert type(bb) == Backboard bb.add_history(realtime_action) if realtime_action['type'] == 'workspaceFolders': bb.file_tree = realtime_action['fileTree'] if realtime_action['type'] == 'activeFile': file_path = realtime_action['filePath'] assert type(file_path) == str file_path = "".join(file_path.split(f'/{user_id}/{folder_path}/')[1:]) bb.active_file_path = file_path with open(f"../{user_id}/{folder_path}/{file_path}") as f: bb.active_file_content = f.read() if realtime_action['type'] == 'paste': file_path = realtime_action['filePath'] file_path = "".join(file_path.split(f'/{user_id}/{folder_path}/')[1:]) bb.pasted_file_path = file_path bb.pasted_content = realtime_action['content'] print("config"+str(config)) print("realtime_action"+str(realtime_action)) pass ''' Agent and Chat ''' agent_manager = AgentManager(app = app, socketio = socketio) user_threads = {} import threading from concurrent.futures import ThreadPoolExecutor, as_completed # 初始化线程池 executor = ThreadPoolExecutor(max_workers=10) class AgentNamespace(Namespace): def on_login(self, data): data = json.loads(data) user = data['username'] folder_name = data['folder'] user_uuid = user_id2uuid[user] session['user_id'] = user_uuid print(f'User connected with session user_id: {user_uuid}') # 从markdown、markdown_prompts、score_prompts中各读取数据folder.md并进行new_agent with open(f'books/markdown/{folder_name}.md','r',encoding='UTF-8') as fmd,\ open(f'books/markdown_prompts/{folder_name}.md','r',encoding='UTF-8')as fmdp,\ open(f'books/score_prompts/{folder_name}.md','r',encoding='UTF-8') as fsp: markdown = fmd.read() markdown_prompts = fmdp.read() score_prompts = fsp.read() user_uuid, agent = agent_manager.new_agent(markdown, markdown_prompts, score_prompts, id=user_uuid, root_path=f'{user}/{folder_name}') print(user_uuid) join_room(user_uuid, namespace='/agent') # 将该用户加入以user_id为名的room backboard_manager.add_backboard(user_uuid, folder_name) def on_language(self, language): id = session.get('user_id') agent_manager.change_language(id, language) def on_message(self, data): print(f"Message from client: {data}") id = session.get('user_id') if (type(data)==str): data = json.loads(data) print(id) if data['type'] == 'text': res = agent_manager.invoke(id, data['data'], backboard_manager.get_backboard(id).get_info_prompt()) print('=*='*20) print(res.content) reply = f"AI: {res.content['speak']}" with app.app_context(): emit('message',reply, room=id, namespace='/agent') emit('request_function',res.content['function'], room=id, namespace='/agent') # for res in agent_manager.invoke(id, data, backboard_manager.get_backboard(id).get_info_prompt(), reset=True): # print('=*='*20) # print(res.content) # if ('speak' in res.content): # reply = f"AI: {res.content['speak']}" # with app.app_context(): emit('message',reply, room=id, namespace='/agent') # if ('function' in res.content): # functions = res.content['function'] # if functions is None: break # if len(functions)==0:break if data['type'] == 'function': agent_manager.function_call(id, data['data']) def on_disconnect(self): print("VSCode client disconnected") ''' Markdown to HTML ''' # 配置文件路径 MARKDOWN_DIR = 'books/markdown' # 存放 markdown 文件的文件夹 STATIC_DIR = 'static' # 存放生成的 HTML 和图片资源的文件夹 IMAGE_DIR = 'image' # 图片资源相对于 markdown 的位置 @app.route('/-markdown', methods=['GET']) def convert_md(filename): md_file_path = os.path.join(MARKDOWN_DIR, f'{filename}.md') if not os.path.exists(md_file_path): return jsonify({'error': 'Markdown file not found'}), 404 # 读取 markdown 文件内容 with open(md_file_path, 'r', encoding='utf-8') as file: md_content = file.read() # 将 markdown 转换为 HTML html_content = markdown.markdown(md_content) # 插入 CSS 样式,限制图片最大宽度为 100%,高度自动调整 html_with_styles = f""" {html_content} """ # 保存 HTML 文件到 static 文件夹 html_output_path = os.path.join(STATIC_DIR, f'{filename}.html') with open(html_output_path, 'w', encoding='utf-8') as html_file: html_file.write(html_with_styles) # 处理图片资源,将 image/xxx 文件夹拷贝到 static/image/xxx image_source_dir = os.path.join(MARKDOWN_DIR, IMAGE_DIR, filename) image_target_dir = os.path.join(STATIC_DIR, IMAGE_DIR, filename) print(f"Copying image resources from {image_source_dir} to {image_target_dir}") if os.path.exists(image_source_dir): # 确保 static/image/xxx 目录存在 if not os.path.exists(image_target_dir): os.makedirs(image_target_dir) # 拷贝图片资源 for image_file in os.listdir(image_source_dir): full_image_file_path = os.path.join(image_source_dir, image_file) if os.path.isfile(full_image_file_path): shutil.copy(full_image_file_path, image_target_dir) return jsonify({'html_url': f'/static/{filename}.html'}) # 静态文件(HTML 和图片资源)的访问 @app.route('/static/') def serve_static(filename): return send_from_directory(STATIC_DIR, filename) ''' Vscode ''' @app.route('/desktop//') def hello_world(user_id, path): if 'user_id' not in session: # return redirect(url_for('login')) session['user_id'] = 'user_' + str(uuid.uuid4()) print("user "+ user_id + "uuid is"+ session['user_id']) user_id2uuid[user_id] = session['user_id'] uuid2user_id[session['user_id']] = user_id userid_recorder[user_id+'&'+path] = session['user_id'] # 在上层 目录下创建一个名为 user_id_path 的文件夹 path_dir = os.path.join(parent_dir, user_id, path) os.makedirs(path_dir, exist_ok=True) # 在此文件夹内部创建一个.config文件,并写入 user_id=user_id\n path=path config_path = os.path.join(path_dir, '.config') with open(config_path, 'w') as f: f.write(f"user_id={user_id}\npath={path}") return render_template('desktop.html', user_id=user_id, path=path) @app.route('/vscode_data', methods=['POST']) def vscode_data(): data = request.json config = data['config'] realtime_response(config,data) print(f"Received data from VSCode: {data}") return jsonify({"status": "success", "received": data}) @app.route('/get_session') def get_session(): user_session = session.get('user_id', 'default_session') return jsonify({"session": user_session}) ''' Login ''' @app.route('/login') def login(): if 'user_id' not in session: return render_template('login.html') else: return redirect(url_for('/')) from db.user_list import UserList users_list = UserList() @app.route('/login_post', methods=['POST']) def login_post(): # 获取请求的 JSON 数据 data = request.get_json() username = data.get('username') password = data.get('password') user = users_list.get_user(username) if user is None: return jsonify({'success': False, 'message': '用户名或密码错误'}) if user['password'] != password: return jsonify({'success': False, 'message': '用户名或密码错误'}) session['user_id'] = 'user_' + str(uuid.uuid4()) print("user "+ username + "uuid is"+ session['user_id']) user_id2uuid[username] = session['user_id'] uuid2user_id[session['user_id']] = username return jsonify({'success': True, 'message': '登录成功'}) ''' DashBoard ''' @app.route('/dashboard') def dashboard(): if 'user_id' not in session: return redirect(url_for('login')) return render_template('dashboard.html') ''' Book ''' @app.route('/book/') def book(book_name): return render_template('book.html', book_name=book_name) @app.route('/') def home_index(): return render_template('index.html') if __name__ == '__main__': socketio.on_namespace(VSCodeNamespace('/vscode')) socketio.on_namespace(AgentNamespace('/agent')) socketio.run(app, host='0.0.0.0', port=5000, debug=True)