From b90035984b97d2953b66d73c2a7f446864f60609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= Date: Fri, 29 May 2026 15:50:06 +0800 Subject: [PATCH] =?UTF-8?q?ai=E5=8A=A8=E6=80=81=E6=8A=A5=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yuthon_ai_agent/models/ai_agent.py | 43 +++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/yuthon_ai_agent/models/ai_agent.py b/yuthon_ai_agent/models/ai_agent.py index 8301a4b5c..869dce283 100644 --- a/yuthon_ai_agent/models/ai_agent.py +++ b/yuthon_ai_agent/models/ai_agent.py @@ -436,7 +436,7 @@ class AiConversation(models.Model): return None def _execute_generate_report(self, args): - """执行 generate_report 工具(增强版:支持 template_id + params)""" + """执行 generate_report 工具(支持 template_id + params + 企微推送)""" import json as _json model_name = args.get('model') @@ -470,14 +470,11 @@ class AiConversation(models.Model): template = self.env['ai.report.template'].sudo().browse(template_id) if template.exists(): vals['template_id'] = template_id - # 如果 AI 没传 fields,用模板的字段列表 if not args.get('fields') and template.field_list: vals['field_list'] = template.field_list - # 如果 AI 没传 field_labels,用模板的 if not args.get('field_labels') and template.field_labels: vals['field_labels'] = template.field_labels - # 如果有 params,序列化保存 if params: vals['params'] = _json.dumps(params, ensure_ascii=False) @@ -487,9 +484,34 @@ class AiConversation(models.Model): result = { 'success': True, 'url': url, - 'message': f'已生成报表链接,用户可点击查看: {url}', + 'message': f'已生成报表链接: {url}', } + # ===== 主动推送到用户企微 ===== + try: + employee = self.env['hr.employee'].sudo().search([ + ('user_id', '=', self.env.uid) + ], limit=1) + if employee and employee.wecom_userid: + self.sudo().env["wecom.apps"].sync_send_message_textcard( + category='oa', + touser=employee.wecom_userid, + title=f"📊 {report_name}", + description=f"数据来源:{model_name}\n生成时间:{fields.Datetime.now().strftime('%Y-%m-%d %H:%M')}\n点击下方按钮查看详细报表", + url=url, + btntxt="查看报表", + ) + result['wecom_sent'] = True + _logger.info(f"报表 {report.id} 已推送到用户 {employee.name} 的企微") + else: + result['wecom_sent'] = False + result['wecom_msg'] = '当前用户未绑定企微账号,无法推送' + _logger.warning(f"用户 {self.env.uid} 未找到企微账号,报表未推送") + except Exception as we: + _logger.exception(f"推送报表到企微失败: {we}") + result['wecom_sent'] = False + result['wecom_msg'] = f'企微推送失败: {we}' + return result except Exception as e: _logger.exception('generate_report failed: %s', e) @@ -621,22 +643,23 @@ class AiConversation(models.Model): '常见模型:res.partner(联系人)、product.product/product.template(产品)、' 'sale.order(销售订单)、purchase.order(采购单)、account.move(发票/账单)、' 'stock.picking(出入库)、hr.employee(员工)、res.users(用户)、res.company(公司)。\n' - '当用户提到“查/搜/统计/创建/修改/删除”等数据相关需求时,必须主动调用相应工具,' + '当用户提到"查/搜/统计/创建/修改/删除"等数据相关需求时,必须主动调用相应工具,' '不要凭空编造结果。不确定字段名时先调用 odoo_fields_get。\n' '所有回答使用中文,简洁清晰。\n' '【格式要求】回复不要使用 Markdown 语法(禁止使用 | 表格、** 加粗、# 标题等)。\n' '少量数据(≤5条)直接用编号列表展示,如:\n' '1. 张三 / 研发部 / 2025-03-01\n' '2. 李四 / 财务部 / 2025-03-15\n' - '【报表链接】当查询结果超过5条,或用户要求“列表/报表/明细”时,' + '【报表与推送】当查询结果超过5条,或用户要求"列表/报表/明细"时,' '必须调用 generate_report 工具生成报表链接。' - '回复时简要说明查询结果并附上链接,如:\n' - '查询到 XX 条记录,请点击查看详细数据:\n' + '生成报表后系统会自动尝试推送到用户的企微。无论推送是否成功,' + '回复时都要说明查询结果并附上链接,如:\n' + '已为您生成报表,共查询到 XX 条记录:\n' 'URL链接\n' '查询结果中的时间已经转换为北京时间(UTC+8),直接展示即可,无需再做时区转换。\n\n' '【重要】你具有记忆能力。当对话中发现用户的新偏好、工作内容、习惯等值得长期记住的信息时,' '主动调用 save_memory 工具保存。下次对话你会自动获取这些记忆。\n' - '称呼用户时使用其设定的称呼,不要说“您”、“亲”等通用称谓。\n' + '称呼用户时使用其设定的称呼,不要说"您"、"亲"等通用称谓。\n' ) # —— 注入 AI 规则 ——