From 621e31941e6d14b53c7572e584c700043a03ca91 Mon Sep 17 00:00:00 2001 From: Dame-time-0034 <812793632@qq.com> Date: Mon, 8 Jun 2026 16:19:41 +0800 Subject: [PATCH 1/9] =?UTF-8?q?=E6=9B=B4=E6=96=B0=EF=BC=9A=E5=88=A0?= =?UTF-8?q?=E9=99=A4=20FastMCP=E8=AE=BE=E7=BD=AE=E6=8C=87=E5=8D=97=20-=20?= =?UTF-8?q?=E5=AE=8C=E6=95=B4=E9=85=8D=E7=BD=AE=E5=92=8C=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=95=99=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- llm/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/llm/README.md b/llm/README.md index d3cf436..71b0eb9 100644 --- a/llm/README.md +++ b/llm/README.md @@ -246,7 +246,6 @@ async def get_trending_repositories(language: Optional[str] = None, ## 📚 详细文档 -- 📖 **[FastMCP设置指南](FASTMCP_SETUP.md)** - 完整配置和使用教程 - 🤝 **[贡献指南](CONTRIBUTING.md)** - 参与项目开发 ## 🔑 API密钥获取 From 9cd33a4730a9d24cf61f77e208ede3364c3fa30b Mon Sep 17 00:00:00 2001 From: Dame-time-0034 <812793632@qq.com> Date: Wed, 17 Jun 2026 21:36:20 +0800 Subject: [PATCH 2/9] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=87=AA?= =?UTF-8?q?=E7=84=B6=E8=AF=AD=E8=A8=80=E7=94=9F=E6=88=90SUMO=E8=B7=AF?= =?UTF-8?q?=E7=BD=91=E5=92=8C=E8=BD=A6=E6=B5=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- llm/main_ai.py | 170 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 149 insertions(+), 21 deletions(-) diff --git a/llm/main_ai.py b/llm/main_ai.py index 051a559..6e021fd 100644 --- a/llm/main_ai.py +++ b/llm/main_ai.py @@ -17,13 +17,14 @@ from typing import Optional import carla import subprocess +import os # 添加src目录到Python路径 current_dir = Path(__file__).parent -sys.path.insert(0, str(current_dir)) +sys.path.insert(0, str(current_dir/ "src")) from fastmcp import FastMCP from src.github_client import GitHubClient -from src.config import config +from src.config import config from src.utils.logger import app_logger # 创建FastMCP实例 @@ -1792,7 +1793,25 @@ def __init__(self): } } }, - ] + + { # ← 新添加的工具 + "type": "function", + "function": { + "name": "generate_sumo_network", + "description": "生成 SUMO 路网和车流...", + "parameters": { + "type": "object", + "properties": { + "grid_x": {"type": "integer", "description": "X方向网格数,默认3"}, + "grid_y": {"type": "integer", "description": "Y方向网格数,默认3"}, + "duration": {"type": "integer", "description": "仿真时长(秒),默认200"}, + "rate": {"type": "number", "description": "发车间隔(秒/辆),默认2.0"} + }, + "required": [] + } + } + } + ] def process_markdown(self, text): """在Python端处理Markdown格式""" @@ -1949,6 +1968,17 @@ async def execute_fastmcp_tool_call(self, tool_call): "success": True, "data": result } + elif function_name == "generate_sumo_network": + result = await generate_sumo_network( + grid_x=arguments.get("grid_x", 3), + grid_y=arguments.get("grid_y", 3), + duration=arguments.get("duration", 200), + rate=arguments.get("rate", 2.0) + ) + return { + "success": True, + "data": result + } elif function_name == "search_github_repositories": result = await search_github_repositories_impl( query=arguments["query"], @@ -2144,15 +2174,24 @@ async def execute_fastmcp_tool_call(self, tool_call): "跑步者": "jogger", "跑步的人": "jogger" } - def _check_spawn_intent(self, message): - """检测用户是否有生成车辆或行人的意图,但缺少必要参数 - 只有当缺少类型时才询问,数量默认为1,不询问 - """ + """检测用户是否有生成车辆或行人的意图,但缺少必要参数""" message = message.lower() - # 首先排除视角控制相关的指令(这些不是生成请求) + # 首先排除 SUMO 路网生成相关的指令 + sumo_keywords = ['路网', '网格', 'sumo', '仿真', '交通'] + for kw in sumo_keywords: + if kw in message: + return { + 'needs_vehicle_type': False, + 'needs_vehicle_count': False, + 'needs_pedestrian_type': False, + 'needs_pedestrian_count': False, + 'is_ambiguous': False + } + + # 排除视角控制相关的指令 view_keywords = ['视角', '切换', '人称', '俯视', '鸟瞰', '自由视角', '录制', '录像', '视频'] if any(kw in message for kw in view_keywords): return { @@ -2165,31 +2204,22 @@ def _check_spawn_intent(self, message): # 车辆相关关键词 vehicle_keywords = ['车', '车辆', '汽车', '生成车', '创建车', '来车', '加车', '添加车辆'] - # 行人相关关键词(更精确,避免误判) pedestrian_keywords = ['行人', '生成行人', '创建行人', '添加行人', '路人'] - # 单独的"人"字需要结合生成类动词才认为是生成行人 person_spawn_verbs = ['生成', '创建', '来', '加', '添加', '放', 'spawn'] - # 数量相关模式 import re has_count = bool(re.search(r'\d+\s*[辆个]', message)) - # 检测车辆类型(支持英文和中文) has_vehicle_type = any(vtype in message for vtype in self.VEHICLE_TYPES.keys()) or \ any(vname in message for vname in self.VEHICLE_TYPE_MAP.keys()) - # 检测行人类型(支持英文和中文)- 但排除泛指的"行人" specific_pedestrian_keywords = set(self.PEDESTRIAN_TYPES.keys()) | set(self.PEDESTRIAN_TYPE_MAP.keys()) - {"行人", "人"} has_pedestrian_type = any(ptype in message for ptype in specific_pedestrian_keywords) - # 检查是否是模糊的车辆生成请求 is_vehicle_request = any(kw in message for kw in vehicle_keywords) - # 检查是否是模糊的行人生成请求 is_pedestrian_request = any(kw in message for kw in pedestrian_keywords) - # 单独的"人"需要配合生成动词才算 if not is_pedestrian_request and '人' in message: has_spawn_verb = any(verb in message for verb in person_spawn_verbs) - # 排除"人称"(第一人称、第三人称等) if has_spawn_verb and '人称' not in message: is_pedestrian_request = True @@ -2201,16 +2231,14 @@ def _check_spawn_intent(self, message): 'is_ambiguous': False } - # 如果是车辆请求但没有指定类型,需要询问 if is_vehicle_request and not has_vehicle_type: result['needs_vehicle_type'] = True - result['needs_vehicle_count'] = not has_count # 记录是否也缺少数量 + result['needs_vehicle_count'] = not has_count result['is_ambiguous'] = True - # 如果是行人请求但没有指定类型,需要询问 if is_pedestrian_request and not has_pedestrian_type: result['needs_pedestrian_type'] = True - result['needs_pedestrian_count'] = not has_count # 记录是否也缺少数量 + result['needs_pedestrian_count'] = not has_count result['is_ambiguous'] = True return result @@ -3237,5 +3265,105 @@ def main(): print(f"[INFO] 访问地址: http://{host_ip}:3000") uvicorn.run(app='main_ai:app', host=host_ip, port=3000, reload=True) +@mcp.tool() +async def generate_sumo_network( + grid_x: int = 3, + grid_y: int = 3, + duration: int = 200, + rate: float = 2.0 +) -> str: + """ + 生成 SUMO 路网和车流。 + 参数: + - grid_x: X方向网格数,默认3 + - grid_y: Y方向网格数,默认3 + - duration: 仿真时长(秒),默认200 + - rate: 发车间隔(秒/辆),默认2.0 + + 示例: + - "生成3x3网格路网,跑200秒,每2秒发一辆车" + - "生成4x4网格,跑300秒" + """ + sumo_home = os.environ.get("SUMO_HOME") + if not sumo_home: + return "❌ 错误:未设置 SUMO_HOME 环境变量。请在终端中设置:`$env:SUMO_HOME = 'D:\\mcp\\sumo\\sumo_install\\sumo-win64-1.27.0\\sumo-1.27.0'`" + + bin_dir = os.path.join(sumo_home, "bin") + tools_dir = os.path.join(sumo_home, "tools") + + prefix = "web_generated" + net_file = f"{prefix}.net.xml" + trips_file = f"{prefix}.trips.xml" + rou_file = f"{prefix}.rou.xml" + cfg_file = f"{prefix}.sumocfg" + + try: + # 1. 生成路网 + subprocess.run([ + os.path.join(bin_dir, "netgenerate"), + "--grid", + f"--grid-x-number={grid_x}", + f"--grid-y-number={grid_y}", + f"--grid-x-length=500", + f"--grid-y-length=500", + f"--output-file={net_file}" + ], check=True, capture_output=True, text=True) + + # 2. 生成出行 + subprocess.run([ + "python", + os.path.join(tools_dir, "randomTrips.py"), + f"-n={net_file}", + f"-e={duration}", + "-l", + f"-p={rate}", + f"-o={trips_file}" + ], check=True, capture_output=True, text=True) + + # 3. 生成路由 + subprocess.run([ + os.path.join(bin_dir, "duarouter"), + f"-n={net_file}", + f"-t={trips_file}", + f"-o={rou_file}", + "--ignore-errors" + ], check=True, capture_output=True, text=True) + + # 4. 创建配置文件 + with open(cfg_file, "w", encoding="utf-8") as f: + f.write(f''' + + + + + + + +''') + + return f"""✅ SUMO 路网和车流生成成功! + +📁 生成的文件: +- 路网: {net_file} +- 出行: {trips_file} +- 路由: {rou_file} +- 配置: {cfg_file} + +📊 参数: +- 网格: {grid_x}x{grid_y} +- 仿真时长: {duration} 秒 +- 发车间隔: {rate} 秒/辆 + +▶️ 在终端中运行以下命令查看: +cd D:\\mcp\\sumo +sumo-gui -c {cfg_file} +""" + + except subprocess.CalledProcessError as e: + return f"❌ 生成失败:{e.stderr}" + if __name__ == "__main__": main() From 445b51f04e27f0858db5ae02293ce413f37b4022 Mon Sep 17 00:00:00 2001 From: Dame-time-0034 <812793632@qq.com> Date: Sun, 28 Jun 2026 13:33:31 +0800 Subject: [PATCH 3/9] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E7=BD=91?= =?UTF-8?q?=E9=A1=B5=E7=95=8C=E9=9D=A2=EF=BC=8C=E6=B7=BB=E5=8A=A0SUMO?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- llm/main_ai.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/llm/main_ai.py b/llm/main_ai.py index 6e021fd..3d87822 100644 --- a/llm/main_ai.py +++ b/llm/main_ai.py @@ -3038,7 +3038,7 @@ def get_web_interface():
-
+
👋 欢迎使用基于FastMCP框架的 HUTB 模拟器智能助手!集成 HUTB 仿真控制。

🔧 技术特色:本助手使用FastMCP装饰器实现工具定义,提供类型安全、自动化的MCP体验! @@ -3058,8 +3058,22 @@ def get_web_interface(): 🚗 生成车辆
-
-
+ + +
+

🚦 SUMO 交通仿真(新增功能)

+
+
+ 🚦 生成3x3网格路网 +
+
+ 🚦 生成4x4网格路网 +
+
+ 🚦 生成5x5网格路网 +
+
+
From 390a0cd98a261a7b9f6cee6cd11efc8705b267fb Mon Sep 17 00:00:00 2001 From: Dame-time-0034 <812793632@qq.com> Date: Thu, 2 Jul 2026 15:18:34 +0800 Subject: [PATCH 4/9] =?UTF-8?q?=E8=AE=BE=E7=BD=AE=20SUMO=5FHOME=20?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mcp.bat | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mcp.bat b/mcp.bat index 67c166b..9a40246 100644 --- a/mcp.bat +++ b/mcp.bat @@ -121,6 +121,12 @@ REM Set environment variables set "PATH=%VENV_PATH%\Scripts;%VENV_PATH%;%PATH%" set "VIRTUAL_ENV=%VENV_PATH%" +REM ===== 设置 SUMO_HOME(相对路径) ===== +set "SUMO_HOME=%PROJECT_ROOT%\sumo\sumo_install\sumo-win64-1.27.0\sumo-1.27.0" +echo SUMO_HOME is set to: %SUMO_HOME% +set "PATH=%SUMO_HOME%\bin;%PATH%" +REM ====================================== + REM Check if OpenCV (cv2) is installed echo Checking OpenCV (cv2)... "%PYTHON_EXE%" "%PROJECT_ROOT%\llm\check_opencv.py" From 98c1a7d8e6d6b7ddffa18bbd62f0ca571322f6f4 Mon Sep 17 00:00:00 2001 From: Dame-time-0034 <812793632@qq.com> Date: Thu, 2 Jul 2026 23:16:42 +0800 Subject: [PATCH 5/9] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0README=E5=B8=B8?= =?UTF-8?q?=E7=94=A8=E5=AF=B9=E8=AF=9D=EF=BC=8C=E4=B8=8E=E7=BD=91=E9=A1=B5?= =?UTF-8?q?=E7=95=8C=E9=9D=A2=E4=BF=9D=E6=8C=81=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- llm/main_ai.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/llm/main_ai.py b/llm/main_ai.py index 3d87822..ce567b8 100644 --- a/llm/main_ai.py +++ b/llm/main_ai.py @@ -3060,21 +3060,17 @@ def get_web_interface():
-
-

🚦 SUMO 交通仿真(新增功能)

-
+
+

🚦 SUMO 交通仿真(新增功能)

+
- 🚦 生成3x3网格路网 -
-
- 🚦 生成4x4网格路网 -
-
- 🚦 生成5x5网格路网 -
-
-
- + 🚦 生成默认网格路网 +
+
+
+ 💡 也支持自然语言自定义参数:"生成4x4网格路网,跑300秒""生成5x5网格路网,跑500秒,每3秒发一辆车" +
+
From 2e5e8b0f088168e4191dd87f7b339c0b6894ce62 Mon Sep 17 00:00:00 2001 From: Dame-time-0034 <812793632@qq.com> Date: Thu, 2 Jul 2026 23:24:26 +0800 Subject: [PATCH 6/9] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0README=E5=B8=B8?= =?UTF-8?q?=E7=94=A8=E5=AF=B9=E8=AF=9D=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 638796a..18621bc 100644 --- a/README.md +++ b/README.md @@ -33,16 +33,10 @@ graph LR ### 1.1 常用对话 ``` 连接服务器 -设置雨天天气条件 +天气设置(默认雨天) +生成行人 生成车辆 -开启自动驾驶 -生成行人(默认开启自由移动) -切换视角 -切换第三人称视角ID -切换第一人称视角ID -切换旁观者视角 -开启录制 -结束录制 +生成默认网格路网 ``` From 26e40d811b3e3bb0e6d84247a694c21046b34a22 Mon Sep 17 00:00:00 2001 From: Dame-time-0034 <812793632@qq.com> Date: Sat, 4 Jul 2026 11:10:18 +0800 Subject: [PATCH 7/9] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20README?= =?UTF-8?q?=EF=BC=8C=E8=AF=B4=E6=98=8E=20SUMO=20=E8=B7=AF=E7=BD=91?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 18621bc..152cf21 100644 --- a/README.md +++ b/README.md @@ -33,9 +33,16 @@ graph LR ### 1.1 常用对话 ``` 连接服务器 -天气设置(默认雨天) -生成行人 +设置雨天天气条件 生成车辆 +开启自动驾驶 +生成行人(默认开启自由移动) +切换视角 +切换第三人称视角ID +切换第一人称视角ID +切换旁观者视角 +开启录制 +结束录制 生成默认网格路网 ``` From a446bb59e355feb37e286bfd75b3005918816a9a Mon Sep 17 00:00:00 2001 From: Dame-time-0034 <812793632@qq.com> Date: Sat, 4 Jul 2026 12:26:54 +0800 Subject: [PATCH 8/9] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DSUMO=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E8=B0=83=E7=94=A8=E9=94=99=E8=AF=AF=EF=BC=8C=E5=88=86?= =?UTF-8?q?=E7=A6=BB=E5=AE=9E=E7=8E=B0=E5=87=BD=E6=95=B0=E4=B8=8E=E8=A3=85?= =?UTF-8?q?=E9=A5=B0=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- llm/main_ai.py | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/llm/main_ai.py b/llm/main_ai.py index ce567b8..82507a2 100644 --- a/llm/main_ai.py +++ b/llm/main_ai.py @@ -1969,7 +1969,7 @@ async def execute_fastmcp_tool_call(self, tool_call): "data": result } elif function_name == "generate_sumo_network": - result = await generate_sumo_network( + result = await generate_sumo_network_impl( grid_x=arguments.get("grid_x", 3), grid_y=arguments.get("grid_y", 3), duration=arguments.get("duration", 200), @@ -3282,21 +3282,19 @@ async def generate_sumo_network( duration: int = 200, rate: float = 2.0 ) -> str: - """ - 生成 SUMO 路网和车流。 - 参数: - - grid_x: X方向网格数,默认3 - - grid_y: Y方向网格数,默认3 - - duration: 仿真时长(秒),默认200 - - rate: 发车间隔(秒/辆),默认2.0 - - 示例: - - "生成3x3网格路网,跑200秒,每2秒发一辆车" - - "生成4x4网格,跑300秒" - """ + """生成 SUMO 路网和车流。""" + return await generate_sumo_network_impl(grid_x, grid_y, duration, rate) + +async def generate_sumo_network_impl( + grid_x: int = 3, + grid_y: int = 3, + duration: int = 200, + rate: float = 2.0 +) -> str: + """SUMO 路网生成实现函数""" sumo_home = os.environ.get("SUMO_HOME") if not sumo_home: - return "❌ 错误:未设置 SUMO_HOME 环境变量。请在终端中设置:`$env:SUMO_HOME = 'D:\\mcp\\sumo\\sumo_install\\sumo-win64-1.27.0\\sumo-1.27.0'`" + return "❌ 错误:未设置 SUMO_HOME 环境变量。请在终端中设置:`set SUMO_HOME=D:\\mcp\\sumo\\sumo_install\\sumo-win64-1.27.0\\sumo-1.27.0`" bin_dir = os.path.join(sumo_home, "bin") tools_dir = os.path.join(sumo_home, "tools") From 269a44c27b6699a152d819c50aebf2ebc08ce1ab Mon Sep 17 00:00:00 2001 From: Dame-time-0034 <812793632@qq.com> Date: Sat, 4 Jul 2026 13:10:07 +0800 Subject: [PATCH 9/9] =?UTF-8?q?fix:=20=E6=9B=B4=E6=96=B0mcp.bat=E4=B8=AD?= =?UTF-8?q?=E7=9A=84SUMO=5FHOME=E8=B7=AF=E5=BE=84=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81hutb\sumo=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mcp.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mcp.bat b/mcp.bat index 9a40246..1ea55ec 100644 --- a/mcp.bat +++ b/mcp.bat @@ -122,7 +122,7 @@ set "PATH=%VENV_PATH%\Scripts;%VENV_PATH%;%PATH%" set "VIRTUAL_ENV=%VENV_PATH%" REM ===== 设置 SUMO_HOME(相对路径) ===== -set "SUMO_HOME=%PROJECT_ROOT%\sumo\sumo_install\sumo-win64-1.27.0\sumo-1.27.0" +set "SUMO_HOME=%PROJECT_ROOT%\hutb\sumo" echo SUMO_HOME is set to: %SUMO_HOME% set "PATH=%SUMO_HOME%\bin;%PATH%" REM ======================================