Files
DPM/backend/app/ai_tools.py
T
Pine 18d28be943 feat: 添加后端部署和API基本检索的Docker Compose配置
- 引入新的`docker-compose.yml`文件,便于后端和MQTT代理(EMQX)的部署。
- 更新多个组件中的API基本检索,使用函数进行动态解析。
- 加强了多个组件中API调用的错误处理和日志记录。
- 优化了AI聊天面板离线场景的回退响应。
- 更新DataScreen和MediaScreen组件中的数据显示和统计,以反映准确的指标。
- 重构MQTT连接逻辑,以支持动态凭证和客户端ID。
2026-08-18 06:50:50 +08:00

175 lines
11 KiB
Python

# -*- coding: utf-8 -*-
"""AI 助手工具调用引擎
后端收到对话 → 规则引擎判断意图 → 产出文字回复 + 工具调用列表
工具执行时通过 MQTT 广播 opc/display/command,前端(所有大屏)同步响应
工具:navigate(切页) / control(媒体控制) / alert(通知) / show_card(展示卡片)
"""
from .mqtt import hub
# ---------------- 工具执行 ----------------
def execute_tool(tool):
"""执行一个工具调用:发布 MQTT 控制指令,返回是否发布成功"""
t = tool.get("type")
params = tool.get("params") or {}
if t == "navigate":
return hub.publish_command("navigate", {"page": params.get("page", "home")}).get("published", False)
if t == "control":
action = params.get("action")
if action in ("play", "pause", "next", "prev"):
return hub.publish_command(action).get("published", False)
if action == "set_mode":
return hub.publish_command("set_mode", {"mode": params.get("mode", "auto")}).get("published", False)
return False
if t == "alert":
return hub.publish_command("alert", {"title": params.get("title", "提示"), "content": params.get("content", "")}).get("published", False)
if t == "show_card":
return hub.publish_command("show_card", params).get("published", False)
return False
def run_tools(tools):
"""执行一组工具,返回 [{type, ok}] 并汇总是否全部发布成功"""
results = []
all_ok = True
for tool in tools or []:
ok = bool(execute_tool(tool))
results.append({"type": tool.get("type"), "ok": ok})
all_ok = all_ok and ok
return results, all_ok
# ---------------- 意图 → 回复 + 工具 ----------------
PAGES = {
"home": "/", "数据大屏": "/", "首页": "/",
"twin": "/twin", "数字孪生": "/twin", "3d": "/twin", "孪生": "/twin",
"ai": "/ai", "ai助手": "/ai", "智能助手": "/ai",
"screen": "/screen", "媒体": "/screen", "轮播": "/screen", "媒体轮播": "/screen",
}
RULES = [
{
"match": ["入驻", "申请", "入孵", "入园", "如何加入", "怎样加入"],
"reply": "入驻流程(按《入驻管理规程》,每年原则上两次):\n\n1. 提出申请:提交《入驻申请表》《创业计划书》、身份证(外籍提供护照签证)、学历证明、营业执照、资质专利证书等材料\n2. 项目初审:服务机构初审,材料不齐一次性告知补全\n3. 入驻评审:从《昆明市就业创业导师库》抽取 3 名评审专家,路演答辩,量化打分 100 分制,80 分及以上通过\n4. 评审公示:报主管部门备案后在昆明市人社局官网公示\n5. 签署协议:签订《入驻孵化协议》,分配场地/工位,正式入驻\n\n按官方统计(2026年7月)园区实际入驻企业 38 家。咨询电话:18087174891。",
"tools": [{"type": "show_card", "params": {"card": "overview"}}],
},
{
"match": ["政策", "补贴", "优惠", "扶持", "减免", "奖励", "资助"],
"reply": "园区政策服务覆盖「七位一体」中的政策维度:\n\n· 场地租金减免:符合条件的大学生创业项目可享受场地优惠\n· 创业补贴:协助对接省、市两级创业补贴与一次性创业资助\n· 税费优惠:对接小微企业所得税减免、增值税优惠等政策\n· 项目申报:协助高新技术企业认定、科技型中小企业备案申报辅导\n\n更多政策细节可咨询园区政策服务窗口(电话:18087174891)。",
"tools": [],
},
{
"match": ["场地", "办公室", "工位", "租金", "收费", "面积", "多少钱", "价格"],
"reply": "园区建筑面积约 3000 ㎡(官方统计口径),可容纳约 50 个创业团队,按发展阶段设置四大孵化区域(《宣传册》):\n\n· OPC创业空间:AI技术支撑、数字经济/AI应用/软件开发/文创设计/电商直播等轻资产领域,拎包入驻,最长 2 年\n· 创业苗圃区:创意阶段未注册团队,开放式共享工位,最长 2 年\n· 孵化加速区:已注册初创企业,独立办公空间,基础 2 年可延 1 年(累计≤3年)\n· 国际创客区:归国/外籍留学生,个性化办公空间,参照加速区\n\n办公场地免费提供(含桌椅、文件柜、高速网络等基础配套),水电网络全配套、拎包入驻。",
"tools": [{"type": "show_card", "params": {"card": "zones"}}],
},
{
"match": ["企业", "公司", "名录", "名单", "入驻企业", "有哪些企业", "查企业"],
"reply": "按官方统计(2026年7月),园区实际入驻企业 38 家;《入驻企业信息表》收录本期入驻企业(项目)名录 39 家,包括云南派音人工智能科技(PineSound)、米勒克尔蓝宝石珠宝、云南宸中低空经济、仰光客厅、中越生物医疗、酷享野农AI农业、研X同行者网络等。\n\n行业分布:人工智能 7 家、跨境电商 5 家、教育培训 4 家、文旅康养 4 家、文化创意 4 家、生物医药 4 家、低空经济 3 家、现代农业 3 家、绿色环保 2 家、企业服务 2 家、新材料 1 家。\n\n我已在屏幕上为您展示企业分布卡片。",
"tools": [{"type": "show_card", "params": {"card": "companies"}}],
},
{
"match": ["融资", "投资", "资金", "贷款", "估值", "资本"],
"reply": "园区融资服务包含:\n\n· 融资对接:定期组织路演与投资机构对接活动\n· 经营成效:入驻团队累计经营收入约 2.19 亿元(省级绩效累计口径,截至2026年5月)\n· 金融支持:协助对接银行创业贷款、政府创业担保贷款\n· 财务辅导:提供融资方案设计与商业计划书辅导",
"tools": [],
},
{
"match": ["就业", "招聘", "岗位", "人才", "用工"],
"reply": "园区就业数据(口径说明):\n\n· 官方统计(2026年7月):当年累计带动就业 213 人\n· 省级绩效累计口径(截至2026年5月):累计带动就业 1,529 人(本年度 106 人)\n\n· 企业招聘:在驻企业持续发布岗位\n· 人才对接:与在昆高校共建实习实训基地\n· 创业带动:园区鼓励以创业带动就业",
"tools": [],
},
{
"match": ["导师", "培训", "课程", "辅导", "孵化服务", "孵化器"],
"reply": "园区组建创业指导专家团队 50 人(省级绩效材料口径),提供全周期孵化服务:\n\n· 一对一辅导:创业导师定期坐诊,覆盖商业模式、法律财税、市场营销\n· 培训课程:创业训练营、行业专题沙龙、政策解读会\n· 资源对接:技术、供应链、渠道等产业资源链接\n· 公共服务:工商注册、知识产权、法律咨询一站式代办",
"tools": [],
},
{
"match": ["AI", "模型", "算力", "tokens", "token", "工具", "智能", "赋能", "大模型"],
"reply": "园区 AI 赋能服务是「七位一体」的核心特色:\n\n· 大模型推理:接入 DeepSeek-V3、通义千问、智谱 GLM-4、豆包、讯飞星火等多模型\n· 工具调用:文档生成、数据查询、图像创作、代码执行、语音合成等智能工具\n· 算力与成本:实时提供 token 消耗统计与速率监控\n\n今日园区 AI 推理任务持续运行,服务节点 12/12 在线。",
"tools": [],
},
{
"match": ["加速区", "国际区", "成长区", "分区", "区域", "区别", "布局"],
"reply": "园区按创业企业(项目)发展阶段设置四大孵化区域(《宣传册》《入驻管理规程》):\n\n· OPC创业空间:AI技术支撑、轻资产领域,拎包入驻,孵化周期最长 2 年\n· 创业苗圃区:创意阶段未注册团队,共享工位,最长 2 年\n· 孵化加速区:已注册初创企业,独立办公,基础 2 年可延 1 年(累计≤3年)\n· 国际创客区:归国/外籍留学生,个性化空间,参照加速区\n\n我已在屏幕上为您展示分区介绍卡片。",
"tools": [{"type": "show_card", "params": {"card": "zones"}}],
},
{
"match": ["", "", "打开", "显示", "进入"],
"reply": None, # 由下方页面/控制规则补充
},
{
"match": ["你好", "您好", "hi", "hello", "", "在吗"],
"reply": "您好!我是 OPC 园区 AI 智能助手。\n\n可以问我:入驻流程、政策扶持、场地收费、AI 赋能、企业名录、融资服务等问题;也可以让我「切换到数字孪生页」「打开媒体轮播」或「展示企业卡片」。",
"tools": [],
},
{
"match": ["谢谢", "感谢", "好的", "明白"],
"reply": "不客气,随时为您服务。您也可以让我展示园区数据卡片,或切换到任意展示页面。",
"tools": [],
},
]
DEFAULT_REPLY = "园区提供「空间 + 孵化 + 融资 + 政策 + 资源 + AI 赋能 + 综合服务」七位一体服务。\n\n按官方统计(2026年7月):实际入驻企业 38 家,当年累计带动就业 213 人,当年生产经营总额 252.15 万元;省级绩效累计口径(截至2026年5月):累计孵化企业 181 家、累计带动就业 1,529 人、累计经营收入约 2.19 亿元。\n\n您可以这样问我:\n· 如何申请入驻园区?\n· 展示入驻企业卡片\n· 切换到数字孪生页面"
def _detect_page(text):
for key, path in PAGES.items():
if key in text:
return path
return None
def _detect_control(text):
if any(k in text for k in ["播放", "继续播放", "开始播放"]):
return "play"
if any(k in text for k in ["暂停", "停止播放"]):
return "pause"
if any(k in text for k in ["下一个", "下一张", "下一屏", "切换下一"]):
return "next"
if any(k in text for k in ["上一个", "上一张", "上一屏", "切换上一"]):
return "prev"
return None
def run_chat(messages):
"""输入对话消息列表([{"role","content"}]),返回 {reply, tools}"""
text = ""
for m in reversed(messages or []):
if m.get("role") in ("user", "me"):
text = (m.get("content") or "").strip()
break
reply = None
tools = []
# 1) 页面切换意图(优先级最高)
page = _detect_page(text)
if page:
label = {"/": "数据大屏", "/twin": "数字孪生", "/ai": "AI 助手", "/screen": "媒体轮播"}.get(page, page)
reply = f"好的,已为您切换到「{label}」页面。"
tools = [{"type": "navigate", "params": {"page": page}}]
return {"reply": reply, "tools": tools}
# 2) 媒体控制意图
ctrl = _detect_control(text)
if ctrl:
names = {"play": "播放", "pause": "暂停", "next": "切换下一项", "prev": "切换上一项"}
reply = f"好的,已执行:{names[ctrl]}"
tools = [{"type": "control", "params": {"action": ctrl}}]
return {"reply": reply, "tools": tools}
# 3) 知识库规则
for rule in RULES:
if any(k in text for k in rule["match"]):
reply = rule["reply"]
tools = rule["tools"]
break
if reply is None:
reply = DEFAULT_REPLY
# 工具已在后端通过 MQTT 广播;返回值供请求端本地同步执行
return {"reply": reply, "tools": tools}