164 lines
6.2 KiB
Python
164 lines
6.2 KiB
Python
# -*- 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,
|
|
}
|