Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 170 additions & 12 deletions llm/main_ai.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,38 @@ async def spawn_pedestrians(self, pedestrian_type='pedestrian', count=1):
await self.start_tick_loop()
app_logger.info("🔄 已启动后台tick循环,行人将开始移动")

# 再次确保所有行人控制器都有目标位置
if spawned_pedestrians:
import asyncio
await asyncio.sleep(0.5) # 等待一小段时间让控制器初始化
for pedestrian in spawned_pedestrians:
try:
# 获取行人的控制器
controller = pedestrian.get_control()
if controller:
# 重新设置随机目标位置
target_location = self.world.get_random_location_from_navigation()
if target_location:
# 通过walker的controller来设置目标
walker_controller = None
for actor in self.world.get_actors():
if 'controller.ai.walker' in actor.type_id:
# 检查这个控制器是否附着到当前行人
try:
if hasattr(actor, 'parent') and actor.parent == pedestrian:
walker_controller = actor
break
except:
pass

if walker_controller:
walker_controller.go_to_location(target_location)
walker_controller.set_max_speed(1.4 + (0.5 - 1.0)) # 随机速度 0.9-1.9 m/s
app_logger.info(f"🚶 为行人 {pedestrian.id} 重新设置目标位置和速度")
except Exception as e:
app_logger.warning(f"⚠️ 为行人设置目标时出错: {e}")
continue

return spawned_pedestrians

except Exception as e:
Expand Down Expand Up @@ -697,10 +729,10 @@ async def spawn_pedestrian_impl(query: str, count: int = 1, **kwargs) -> str:
pedestrians = await carla_client.spawn_pedestrians(query, count=count)
if pedestrians:
if len(pedestrians) == 1:
return f"✅ 已生成1个{query}行人 (ID: {pedestrians[0].id})"
return f"✅ 已生成1个{query}行人 (ID: {pedestrians[0].id}),行人已开始自动行走"
else:
last_pedestrian = pedestrians[-1]
return f"✅ 已生成{len(pedestrians)}个{query}行人,最后一个行人ID: {last_pedestrian.id}"
return f"✅ 已生成{len(pedestrians)}个{query}行人,最后一个行人ID: {last_pedestrian.id},所有行人已开始自动行走"
return "❌ 行人生成失败,请确保CARLA服务器已连接且地图有可用导航点"


Expand Down Expand Up @@ -1120,6 +1152,90 @@ async def execute_fastmcp_tool_call(self, tool_call):
"t3": "Volkswagen T3"
}

# 车辆中文到英文的映射
VEHICLE_TYPE_MAP = {
# Tesla
"特斯拉": "model3",
"特斯拉model3": "model3",
"model3": "model3",
# Audi
"奥迪": "a2",
"奥迪a2": "a2",
"a2": "a2",
"奥迪etron": "etron",
"etron": "etron",
"奥迪tt": "tt",
"tt": "tt",
# BMW
"宝马": "grandtourer",
"宝马grandtourer": "grandtourer",
"grandtourer": "grandtourer",
"宝马i8": "i8",
"i8": "i8",
"宝马mini": "mini",
"mini": "mini",
# Chevrolet
"雪佛兰": "impala",
"雪佛兰impala": "impala",
"impala": "impala",
# Citroen
"雪铁龙": "c3",
"雪铁龙c3": "c3",
"c3": "c3",
# Dodge
"道奇": "charger2020",
"道奇警车": "charger_police",
"charger_police": "charger_police",
"道奇charger": "charger2020",
"charger2020": "charger2020",
# Ford
"福特": "mustang",
"福特野马": "mustang",
"野马": "mustang",
"mustang": "mustang",
"福特crown": "crown",
"crown": "crown",
# Jeep
"吉普": "wrangler_rubicon",
"吉普牧马人": "wrangler_rubicon",
"牧马人": "wrangler_rubicon",
"wrangler_rubicon": "wrangler_rubicon",
# Lincoln
"林肯": "mkz_2020",
"林肯mkz2017": "mkz_2017",
"mkz_2017": "mkz_2017",
"林肯mkz2020": "mkz_2020",
"mkz_2020": "mkz_2020",
# Mercedes
"奔驰": "benz_coupe",
"奔驰轿跑": "benz_coupe",
"benz_coupe": "benz_coupe",
"奔驰敞篷": "cabrio",
"cabrio": "cabrio",
"奔驰ccc": "ccc",
"ccc": "ccc",
# Mini
"迷你": "cooper_s",
"迷你cooper": "cooper_s",
"cooper_s": "cooper_s",
# Nissan
"日产": "patrol",
"日产micra": "micra",
"micra": "micra",
"日产patrol": "patrol",
"patrol": "patrol",
# Seat
"西雅特": "leon",
"西雅特leon": "leon",
"leon": "leon",
# Volkswagen
"大众": "t2",
"大众t2": "t2",
"t2": "t2",
"大众t3": "t3",
"t3": "t3"
}

PEDESTRIAN_TYPES = {
"pedestrian": "普通行人",
"elderly": "老年人",
Expand All @@ -1130,6 +1246,28 @@ async def execute_fastmcp_tool_call(self, tool_call):
"jogger": "慢跑者"
}

# 中文到英文的映射
PEDESTRIAN_TYPE_MAP = {
"普通行人": "pedestrian",
"行人": "pedestrian",
"人": "pedestrian",
"老年人": "elderly",
"老人": "elderly",
"儿童": "child",
"小孩": "child",
"孩子": "child",
"建筑工人": "construction_worker",
"工人": "construction_worker",
"警察": "police",
"警官": "police",
"商务人士": "business",
"商人": "business",
"白领": "business",
"慢跑者": "jogger",
"跑步者": "jogger",
"跑步的人": "jogger"
}

def _check_spawn_intent(self, message):
"""检测用户是否有生成车辆或行人的意图,但缺少必要参数

Expand All @@ -1146,10 +1284,12 @@ def _check_spawn_intent(self, message):
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())
# 检测行人类型
has_pedestrian_type = any(ptype in message for ptype in self.PEDESTRIAN_TYPES.keys())
# 检测车辆类型(支持英文和中文)
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)
Expand Down Expand Up @@ -1183,14 +1323,16 @@ def _generate_spawn_prompt(self, check_result):
prompt_parts = []

if check_result['needs_vehicle_type']:
vehicle_list = "\n".join([f" • {key} - {name}" for key, name in self.VEHICLE_TYPES.items()])
# 使用中文展示可用的车辆类型
vehicle_list = "\n".join([f" • {name} ({key})" for key, name in self.VEHICLE_TYPES.items()])
prompt_parts.append(f"🚗 **可用车辆类型:**\n{vehicle_list}")

if check_result['needs_vehicle_count']:
prompt_parts.append("🚗 **车辆数量:** 支持生成 1-100+ 辆车(取决于地图可用生成点数量)")

if check_result['needs_pedestrian_type']:
pedestrian_list = "\n".join([f" • {key} - {name}" for key, name in self.PEDESTRIAN_TYPES.items()])
# 使用中文展示可用的行人类型
pedestrian_list = "\n".join([f" • {name} ({key})" for key, name in self.PEDESTRIAN_TYPES.items()])
prompt_parts.append(f"🚶 **可用行人类型:**\n{pedestrian_list}")

if check_result['needs_pedestrian_count']:
Expand All @@ -1200,11 +1342,15 @@ def _generate_spawn_prompt(self, check_result):
prompt_parts.insert(0, "请提供以下信息以完成生成:\n")
prompt_parts.append("\n💡 **示例指令:**")
if check_result['needs_vehicle_type'] or check_result['needs_vehicle_count']:
prompt_parts.append(' • "生成5辆model3"')
prompt_parts.append(' • "来10辆mustang"')
prompt_parts.append(' • "生成5辆特斯拉"')
prompt_parts.append(' • "来10辆福特野马"')
prompt_parts.append(' • "生成3辆宝马"')
prompt_parts.append(' • "来5辆奔驰"')
if check_result['needs_pedestrian_type'] or check_result['needs_pedestrian_count']:
prompt_parts.append(' • "生成3个police"')
prompt_parts.append(' • "来5个pedestrian"')
prompt_parts.append(' • "生成3个老年人"')
prompt_parts.append(' • "来5个警察"')
prompt_parts.append(' • "生成2个儿童"')
prompt_parts.append(' • "来10个普通行人"')

return "\n\n".join(prompt_parts)

Expand Down Expand Up @@ -1243,8 +1389,12 @@ async def chat(self, user_message):
- 当用户提到"连接"、"服务器"、"CARLA"等明确要求连接时,使用connect_carla
- 当用户提到"车辆"、"生成"、"创建汽车"、"车"等,使用spawn_vehicle,count参数默认为1
- 当用户提到"多辆车"、"生成X辆车"、"几辆车"、指定数量(如5辆、10辆),必须设置count参数为对应数字
- 车辆类型支持中文:特斯拉(model3)、奥迪(a2/etron/tt)、宝马(grandtourer/i8/mini)、雪佛兰(impala)、雪铁龙(c3)、道奇(charger_police/charger2020)、福特(mustang/crown)、吉普(wrangler_rubicon)、林肯(mkz_2017/mkz_2020)、奔驰(benz_coupe/cabrio/ccc)、迷你(cooper_s)、日产(micra/patrol)、西雅特(leon)、大众(t2/t3)
- 当用户使用中文车辆类型(如"生成3辆特斯拉"),你需要将中文类型转换为对应的英文类型:model3、a2、etron、tt、grandtourer、i8、mini、impala、c3、charger_police、charger2020、mustang、crown、wrangler_rubicon、mkz_2017、mkz_2020、benz_coupe、cabrio、ccc、cooper_s、micra、patrol、leon、t2、t3
- 当用户提到"行人"、"生成行人"、"创建行人"、"人"等,直接使用spawn_pedestrian,count参数默认为1
- 当用户提到"多个行人"、"生成X个行人"、"几个行人"、指定数量(如5个、10个),必须设置count参数为对应数字
- 行人类型支持中文:普通行人/行人/人、老年人/老人、儿童/小孩/孩子、建筑工人/工人、警察/警官、商务人士/商人/白领、慢跑者/跑步者/跑步的人
- 当用户使用中文行人类型(如"生成5个老年人"),你需要将中文类型转换为对应的英文类型:elderly、child、construction_worker、police、business、jogger、pedestrian
- 当用户提到"自动驾驶"、"车辆运行"、"车自己开"等,使用setup_autopilot
- 当用户提到"行人移动"、"行人走路"、"行人运行"等,使用setup_pedestrian_movement
- 当用户提到"天气"、"下雨"、"晴天"、"雾天"等,使用set_weather
Expand Down Expand Up @@ -1272,12 +1422,20 @@ async def chat(self, user_message):
- "生成10辆车" -> spawn_vehicle(query="model3", count=10)
- "给我来3辆奥迪a2" -> spawn_vehicle(query="a2", count=3)
- "创建20辆车" -> spawn_vehicle(query="model3", count=20)
- "生成3辆特斯拉" -> spawn_vehicle(query="model3", count=3)
- "生成5辆宝马" -> spawn_vehicle(query="grandtourer", count=5)
- "生成2辆奔驰" -> spawn_vehicle(query="benz_coupe", count=2)
- "生成4辆福特野马" -> spawn_vehicle(query="mustang", count=4)
- "生成一个行人" -> spawn_pedestrian(query="pedestrian", count=1)
- "生成5个行人" -> spawn_pedestrian(query="pedestrian", count=5)
- "生成3个老年人" -> spawn_pedestrian(query="elderly", count=3)
- "生成10个警察" -> spawn_pedestrian(query="police", count=10)
- "生成一个人" -> spawn_pedestrian(query="pedestrian", count=1)
- "生成5个人" -> spawn_pedestrian(query="pedestrian", count=5)
- "生成3个小孩" -> spawn_pedestrian(query="child", count=3)
- "生成5个建筑工人" -> spawn_pedestrian(query="construction_worker", count=5)
- "生成2个商务人士" -> spawn_pedestrian(query="business", count=2)
- "生成4个慢跑者" -> spawn_pedestrian(query="jogger", count=4)
- "开启车辆自动驾驶" -> setup_autopilot(enable=True, radius=0.0)
- "让车辆自己开" -> setup_autopilot(enable=True)
- "开启行人移动" -> setup_pedestrian_movement(enable=True, radius=0.0)
Expand Down
Loading