diff --git a/yuthon_ai_agent/models/ai_agent.py b/yuthon_ai_agent/models/ai_agent.py index 5d2a4e4e8..657ed464d 100644 --- a/yuthon_ai_agent/models/ai_agent.py +++ b/yuthon_ai_agent/models/ai_agent.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- import json import logging +from datetime import datetime +import pytz import requests from odoo import models, fields, api @@ -334,6 +336,8 @@ class AiConversation(models.Model): limit = min(int(args.get('limit') or DEFAULT_LIMIT), MAX_LIMIT) order = args.get('order') or None records = Model.search_read(domain, fields_, limit=limit, order=order) + # 将 UTC 时间转换为用户时区 + records = self._convert_records_timezone(records, model_name, fields_) return {'success': True, 'count': len(records), 'records': records} if name == 'odoo_search_count': @@ -438,6 +442,56 @@ class AiConversation(models.Model): except (KeyError, IndexError, ValueError) as e: return None, f'错误:解析 AI 响应失败 — {e}' + def _convert_records_timezone(self, records, model_name, fields_list): + """将查询结果中的 datetime 字段从 UTC 转换为用户时区""" + if not records: + return records + # 获取用户时区 + user_tz_name = self.env.user.tz or 'Asia/Shanghai' + try: + user_tz = pytz.timezone(user_tz_name) + except pytz.exceptions.UnknownTimeZoneError: + user_tz = pytz.timezone('Asia/Shanghai') + utc_tz = pytz.UTC + + # 获取模型的 datetime 字段列表 + try: + model_fields = self.env[model_name].fields_get(attributes=['type']) + except Exception: + return records + + datetime_fields = set() + for fname, finfo in model_fields.items(): + if finfo.get('type') == 'datetime': + datetime_fields.add(fname) + + # 如果指定了fields_list,只处理请求的字段 + if fields_list: + datetime_fields = datetime_fields & set(fields_list) + + if not datetime_fields: + return records + + # 转换每条记录中的 datetime 字段 + for record in records: + for fname in datetime_fields: + val = record.get(fname) + if not val: + continue + try: + if isinstance(val, str): + dt_utc = datetime.strptime(val, '%Y-%m-%d %H:%M:%S') + elif isinstance(val, datetime): + dt_utc = val + else: + continue + dt_utc = utc_tz.localize(dt_utc) + dt_local = dt_utc.astimezone(user_tz) + record[fname] = dt_local.strftime('%Y-%m-%d %H:%M:%S') + except (ValueError, TypeError): + continue + return records + # --------------------------------------------------------- # 主入口 # --------------------------------------------------------- @@ -465,16 +519,22 @@ class AiConversation(models.Model): user_context = profile.get_system_context() system_msg = ( - '你是一个 Odoo 18 ERP 系统的智能助手,可以调用工具直接查询/操作数据库。\n' + '你是一个 Odoo 17 ERP 系统的智能助手,可以调用工具直接查询/操作数据库。\n' '常见模型: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\n' + '所有回答使用中文,简洁清晰。\n' + '【格式要求】回复不要使用 Markdown 语法(禁止使用 | 表格、** 加粗、# 标题等)。\n' + '列表数据请用编号+冒号格式,每条一行,字段用空格分隔,例如:\n' + '1. 张三 研发部 2025-03-01\n' + '2. 李四 财务部 2025-03-15\n' + '多字段时用“ / ”分隔,保持简洁可读。\n' + '查询结果中的时间已经转换为北京时间(UTC+8),直接展示即可,无需再做时区转换。\n\n' '【重要】你具有记忆能力。当对话中发现用户的新偏好、工作内容、习惯等值得长期记住的信息时,' '主动调用 save_memory 工具保存。下次对话你会自动获取这些记忆。\n' - '称呼用户时使用其设定的称呼,不要说"您"、"亲"等通用称谓。\n' + '称呼用户时使用其设定的称呼,不要说“您”、“亲”等通用称谓。\n' ) # —— 注入 AI 规则 ——