# -*- coding: utf-8 -*- import json from odoo import http from odoo.http import request from odoo.tools import format_datetime class AiChatController(http.Controller): """AI 聊天 API""" def _check_ai_access(self): """检查用户是否有 AI Agent 使用权限""" if not request.env.user.has_group('yuthon_ai_agent.group_ai_agent_user'): return {'error': '您没有使用 AI 助手的权限,请联系管理员开通。'} return None @http.route('/ai/chat/send', type='json', auth='user', methods=['POST'], csrf=False) def chat_send(self, conversation_id, message): """发送消息""" err = self._check_ai_access() if err: return err conv = request.env['ai.conversation'].browse(conversation_id) if not conv.exists(): return {'error': '对话不存在'} reply = conv.send_message(message) if isinstance(reply, dict) and 'error' in reply: return reply last_msg = conv.message_ids.filtered(lambda m: m.role == 'assistant')[-1:] return { 'content': reply, 'message_id': last_msg.id if last_msg else False, } @http.route('/ai/chat/history', type='json', auth='user') def chat_history(self, conversation_id): """获取对话历史""" conv = request.env['ai.conversation'].browse(conversation_id) if not conv.exists(): return {'error': '对话不存在'} user_tz = request.env.user.tz or 'Asia/Shanghai' from pytz import timezone, utc local_tz = timezone(user_tz) messages = [] for msg in conv.message_ids: if msg.create_date: utc_dt = msg.create_date.replace(tzinfo=utc) local_dt = utc_dt.astimezone(local_tz) time_str = local_dt.strftime('%H:%M') else: time_str = '' messages.append({ 'id': msg.id, 'role': msg.role, 'content': msg.content, 'date': time_str, }) return {'messages': messages} @http.route('/ai/chat/clear', type='json', auth='user', methods=['POST'], csrf=False) def chat_clear(self, conversation_id): """清空对话""" conv = request.env['ai.conversation'].browse(conversation_id) if not conv.exists(): return {'error': '对话不存在'} conv.message_ids.unlink() return {'success': True} @http.route('/ai/conversation/create', type='json', auth='user', methods=['POST'], csrf=False) def conversation_create(self): """创建新对话并返回ID""" provider = request.env['ai.provider'].search([('active', '=', True)], limit=1) if not provider: return {'error': '请先在服务商配置中设置 AI 服务'} conv = request.env['ai.conversation'].create({ 'name': '新对话', 'provider_id': provider.id, }) return {'id': conv.id} @http.route('/ai/conversation/get_or_create_personal', type='json', auth='user') def get_or_create_personal(self): """获取或创建当前用户的个人对话(浮动聊天用)""" err = self._check_ai_access() if err: return err conv = request.env['ai.conversation'].search([ ('create_uid', '=', request.env.uid), ], limit=1, order='create_date desc') if not conv: provider = request.env['ai.provider'].search([('active', '=', True)], limit=1) if not provider: return {'error': '请先在服务商配置中设置 AI 服务'} conv = request.env['ai.conversation'].create({ 'name': '个人对话', 'provider_id': provider.id, }) return {'id': conv.id, 'name': conv.name} @http.route('/ai/conversation/list', type='json', auth='user') def conversation_list(self): """获取当前用户的所有对话列表""" err = self._check_ai_access() if err: return err convs = request.env['ai.conversation'].search([ ('create_uid', '=', request.env.uid), ], order='create_date desc', limit=50) return { 'conversations': [{ 'id': c.id, 'name': c.name, 'message_count': c.message_count, } for c in convs] } @http.route('/ai/conversation/new', type='json', auth='user', methods=['POST'], csrf=False) def conversation_new(self): """新建对话""" err = self._check_ai_access() if err: return err provider = request.env['ai.provider'].search([('active', '=', True)], limit=1) if not provider: return {'error': '请先在服务商配置中设置 AI 服务'} conv = request.env['ai.conversation'].create({ 'name': '新对话', 'provider_id': provider.id, }) return {'id': conv.id, 'name': conv.name} @http.route('/ai/conversation/delete', type='json', auth='user', methods=['POST'], csrf=False) def conversation_delete(self, conversation_id): """删除对话""" err = self._check_ai_access() if err: return err conv = request.env['ai.conversation'].browse(conversation_id) if not conv.exists(): return {'error': '对话不存在'} if conv.create_uid.id != request.env.uid: return {'error': '只能删除自己的对话'} conv.unlink() return {'success': True} @http.route('/ai/profile/get', type='json', auth='user') def get_profile(self): """获取当前用户的 AI 画像(含记忆摘要)""" err = self._check_ai_access() if err: return err profile = request.env['ai.user.profile'].get_or_create() return { 'id': profile.id, 'nickname': profile.nickname or '', 'role': profile.role or '', 'department': profile.department or '', 'style_preference': profile.style_preference or 'concise', 'memory_count': profile.memory_count, }