| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- from __future__ import annotations
- from plugins_func.register import Action, ActionResponse, ToolType, register_function
- from plugins_func.nav_copilot.service import get_service
- nav_start_record_desc = {
- "type": "function",
- "function": {
- "name": "nav_start_record",
- "description": (
- "开始记录路线。"
- "如果设备接了外部 STM32 串口计数器,就默认使用计数路线模式;"
- "计数路线模式下,这一步只进入准备状态,不要求立刻收到串口值。"
- "后续用户说“标记急转弯”时,再抓取当前串口值作为标记点;说“结束录制”后自动进入监听预警。"
- "否则退回 GPS 路线模式。"
- "当用户说“开始记录路线”“开始录制路线”“录制路线”“开始记录”“开始记路线”时,"
- "不要只做自然语言回应,必须优先直接调用这个工具。"
- ),
- "parameters": {
- "type": "object",
- "properties": {
- "route_name": {
- "type": "string",
- "description": "路线名称,可选",
- },
- "sample_hz": {
- "type": "integer",
- "description": "采样频率,计数模式建议 10Hz 左右",
- },
- "mode": {
- "type": "string",
- "description": "auto 表示自动选择;counter 表示串口计数;gps 表示 GNSS 轨迹",
- "enum": ["auto", "counter", "gps"],
- },
- },
- "required": [],
- },
- },
- }
- @register_function("nav_start_record", nav_start_record_desc, ToolType.SYSTEM_CTL)
- async def nav_start_record(
- conn,
- route_name: str | None = None,
- sample_hz: int = 10,
- mode: str = "auto",
- ):
- svc = get_service(conn)
- route_id = await svc.start_recording(
- route_name=route_name,
- sample_hz=sample_hz,
- mode=mode,
- )
- route_mode = svc.record_mode or "auto"
- if route_mode == "counter":
- text = (
- f"已经进入计数路线录制准备状态,路线 ID 是 {route_id}。"
- "你到目标点时直接说“标记急转弯”或“标记障碍”,说“结束录制”后会自动开始监听预警。"
- )
- else:
- text = (
- f"已经开始记录 GPS 路线,路线 ID 是 {route_id}。"
- "你到目标点时可以直接说“标记急转弯”或“标记障碍”。"
- )
- return ActionResponse(action=Action.RESPONSE, result=str(route_id), response=text)
- nav_stop_record_desc = {
- "type": "function",
- "function": {
- "name": "nav_stop_record",
- "description": "结束当前路线记录并保存。计数路线模式下,如果已经标记过风险点,会自动进入监听预警。",
- "parameters": {"type": "object", "properties": {}, "required": []},
- },
- }
- @register_function("nav_stop_record", nav_stop_record_desc, ToolType.SYSTEM_CTL)
- async def nav_stop_record(conn):
- svc = get_service(conn)
- result = await svc.stop_recording()
- if result is None:
- return ActionResponse(action=Action.RESPONSE, response="当前没有正在记录的路线。")
- if result.mode == "counter":
- if result.monitor_started:
- response = (
- f"路线录制已结束,路线 ID 是 {result.route_id}。"
- f"已记录 {result.hazard_count} 个风险点,并且已经自动开始监听预警。"
- )
- else:
- response = (
- f"路线录制已结束,路线 ID 是 {result.route_id}。"
- "但你还没有标记风险点,所以还没有启动监听预警。"
- )
- else:
- response = f"路线记录已结束,路线 ID 是 {result.route_id}。"
- return ActionResponse(
- action=Action.RESPONSE,
- result=str(result.route_id),
- response=response,
- )
- nav_mark_hazard_desc = {
- "type": "function",
- "function": {
- "name": "nav_mark_hazard",
- "description": (
- "在当前位置标记一个风险点。"
- "计数路线模式下,会把当前 STM32 串口传来的最新计数值保存成标记点。"
- "典型口令包括“标记急转弯”“标记起转弯”“标记大坑”“标记障碍”。"
- ),
- "parameters": {
- "type": "object",
- "properties": {
- "hazard_type": {
- "type": "string",
- "description": "风险点类型",
- "enum": [
- "sharp_turn",
- "bump",
- "jump",
- "slope",
- "water",
- "obstacle",
- "other",
- ],
- },
- "note": {
- "type": "string",
- "description": "补充说明,可选",
- },
- },
- "required": ["hazard_type"],
- },
- },
- }
- @register_function("nav_mark_hazard", nav_mark_hazard_desc, ToolType.SYSTEM_CTL)
- async def nav_mark_hazard(conn, hazard_type: str, note: str | None = None):
- svc = get_service(conn)
- result = await svc.mark_hazard(hazard_type=hazard_type, note=note or "")
- if result.mode == "counter" and result.counter_value is not None:
- response = f"已标记风险点,当前串口值是 {result.counter_value}。"
- else:
- response = "已标记风险点。"
- return ActionResponse(
- action=Action.RESPONSE,
- result=str(result.hazard_id),
- response=response,
- )
- nav_mark_hazard_reject_desc = {
- "type": "function",
- "function": {
- "name": "nav_mark_hazard_reject",
- "description": "当用户进入风险点录制口令但没有说出有效风险类型时,提示其保持安静并等待重新录入。",
- "parameters": {"type": "object", "properties": {}, "required": []},
- },
- }
- @register_function("nav_mark_hazard_reject", nav_mark_hazard_reject_desc, ToolType.SYSTEM_CTL)
- async def nav_mark_hazard_reject(conn):
- return ActionResponse(
- action=Action.RESPONSE,
- response="请保持安静,等待录入风险点。",
- )
- nav_start_run_desc = {
- "type": "function",
- "function": {
- "name": "nav_start_run",
- "description": (
- "开始预警播报。"
- "对于串口计数路线,会在计数快接近标记点时播报“注意急转弯”,到达标记点时播报“当前急转弯”。"
- "通常计数路线在“结束录制”后会自动开始监听预警,这个工具主要用于手动补启。"
- "当用户说“开始预警”“开始领航”“开始播报”时,不要只做自然语言回应,必须优先直接调用这个工具。"
- ),
- "parameters": {
- "type": "object",
- "properties": {
- "route_id": {
- "type": "integer",
- "description": "指定路线 ID,可选",
- },
- "tick_hz": {
- "type": "integer",
- "description": "刷新频率,计数模式建议 10Hz 左右",
- },
- "mode": {
- "type": "string",
- "description": "可选。通常不必传,服务端会按路线类型自动选择",
- "enum": ["auto", "counter", "gps"],
- },
- },
- "required": [],
- },
- },
- }
- @register_function("nav_start_run", nav_start_run_desc, ToolType.SYSTEM_CTL)
- async def nav_start_run(
- conn,
- route_id: int | None = None,
- tick_hz: int = 10,
- mode: str = "auto",
- ):
- svc = get_service(conn)
- active_route_id = await svc.start_run(route_id=route_id, tick_hz=tick_hz, mode=mode)
- response = f"已经开始预警,使用路线 ID={active_route_id}。"
- if svc.run_mode == "counter":
- response = f"已经开始监听预警,使用路线 ID={active_route_id}。"
- return ActionResponse(
- action=Action.RESPONSE,
- result=str(active_route_id),
- response=response,
- )
- nav_stop_run_desc = {
- "type": "function",
- "function": {
- "name": "nav_stop_run",
- "description": "停止当前预警播报。",
- "parameters": {"type": "object", "properties": {}, "required": []},
- },
- }
- @register_function("nav_stop_run", nav_stop_run_desc, ToolType.SYSTEM_CTL)
- async def nav_stop_run(conn):
- svc = get_service(conn)
- route_id = await svc.stop_run()
- if route_id is None:
- return ActionResponse(action=Action.RESPONSE, response="当前没有正在运行的预警。")
- return ActionResponse(
- action=Action.RESPONSE,
- result=str(route_id),
- response="预警已停止。",
- )
- nav_status_desc = {
- "type": "function",
- "function": {
- "name": "nav_status",
- "description": "查询路线记录和预警状态。",
- "parameters": {"type": "object", "properties": {}, "required": []},
- },
- }
- @register_function("nav_status", nav_status_desc, ToolType.SYSTEM_CTL)
- async def nav_status(conn):
- svc = get_service(conn)
- return ActionResponse(action=Action.RESPONSE, response=svc.status_text())
- nav_list_routes_desc = {
- "type": "function",
- "function": {
- "name": "nav_list_routes",
- "description": "列出最近保存的路线。",
- "parameters": {
- "type": "object",
- "properties": {
- "limit": {
- "type": "integer",
- "description": "返回数量,默认 10",
- }
- },
- "required": [],
- },
- },
- }
- @register_function("nav_list_routes", nav_list_routes_desc, ToolType.SYSTEM_CTL)
- async def nav_list_routes(conn, limit: int = 10):
- svc = get_service(conn)
- routes = svc.db.list_routes(limit=int(limit or 10))
- if not routes:
- return ActionResponse(action=Action.RESPONSE, response="暂无路线,请先开始记录路线。")
- lines = []
- for route in routes:
- active = "(激活)" if route.active else ""
- lines.append(
- f"路线 {route.id}{active}:{route.name},模式 {route.mode},点数 {route.points},风险点 {route.hazards}"
- )
- return ActionResponse(action=Action.RESPONSE, response=";".join(lines))
- nav_set_active_route_desc = {
- "type": "function",
- "function": {
- "name": "nav_set_active_route",
- "description": "将某条路线设置为当前激活路线。",
- "parameters": {
- "type": "object",
- "properties": {
- "route_id": {
- "type": "integer",
- "description": "路线 ID",
- }
- },
- "required": ["route_id"],
- },
- },
- }
- @register_function("nav_set_active_route", nav_set_active_route_desc, ToolType.SYSTEM_CTL)
- async def nav_set_active_route(conn, route_id: int):
- svc = get_service(conn)
- svc.db.set_active_route(int(route_id))
- return ActionResponse(
- action=Action.RESPONSE,
- response=f"已激活路线 ID={int(route_id)}。",
- )
|