mirror of
https://github.com/guohuadeng/app-odoo.git
synced 2025-02-23 04:11:36 +02:00
add deepseek
This commit is contained in:
4
app_deepseek/models/__init__.py
Normal file
4
app_deepseek/models/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import ai_robot
|
||||
from . import mail_channel
|
||||
72
app_deepseek/models/ai_robot.py
Normal file
72
app_deepseek/models/ai_robot.py
Normal file
@@ -0,0 +1,72 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import base64
|
||||
import os
|
||||
import requests, json
|
||||
import logging
|
||||
from openai import OpenAI
|
||||
from http import HTTPStatus
|
||||
from odoo import api, fields, models, modules, tools, _
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AiRobot(models.Model):
|
||||
_inherit = 'ai.robot'
|
||||
|
||||
provider = fields.Selection(selection_add=[('deepseek', 'Deepseek')], ondelete={'deepseek': 'set default'})
|
||||
set_ai_model = fields.Selection(
|
||||
selection_add=[
|
||||
('deepseek-chat', 'Deepseek Chat'),
|
||||
],
|
||||
ondelete={'deepseek-chat': 'set default'})
|
||||
|
||||
@api.onchange('provider')
|
||||
def _onchange_provider(self):
|
||||
if self.provider == 'deepseek':
|
||||
if self.ai_model == 'deepseek-chat':
|
||||
self.endpoint = 'https://api.deepseek.com'
|
||||
# 取头像
|
||||
module_path = modules.get_module_path('app_ai', display_warning=False)
|
||||
if module_path:
|
||||
path = modules.check_resource_path(module_path, ('static/description/src/%s.png' % self.provider))
|
||||
if path:
|
||||
image_file = tools.file_open(path, 'rb')
|
||||
self.image_avatar = base64.b64encode(image_file.read())
|
||||
return super()._onchange_provider()
|
||||
|
||||
def get_deepseek(self, data, author_id, answer_id, param={}):
|
||||
self.ensure_one()
|
||||
api_key = self.openapi_api_key
|
||||
if not api_key or not self.endpoint:
|
||||
raise UserError(_("Please provide Ai Robot [%s] API Key and Endpoint URL first." % self.name))
|
||||
|
||||
if isinstance(data, list):
|
||||
messages = data
|
||||
else:
|
||||
messages = [{"role": "user", "content": data}]
|
||||
|
||||
url = self.endpoint
|
||||
|
||||
client = OpenAI(api_key=api_key, base_url=self.endpoint)
|
||||
response = client.chat.completions.create(
|
||||
model=self.ai_model,
|
||||
messages=messages
|
||||
)
|
||||
res = response.model_dump()
|
||||
if 'choices' in res:
|
||||
return res
|
||||
else:
|
||||
_logger.warning('=====================deepseek output data: %s' % response.json())
|
||||
|
||||
return _("Response Timeout, please speak again.")
|
||||
|
||||
def get_ai_post(self, res, author_id=False, answer_id=False, param={}):
|
||||
if self.provider == 'deepseek':
|
||||
usage = res['usage']
|
||||
content = res['choices'][0]['message']['content']
|
||||
return content, usage, True
|
||||
else:
|
||||
return super().get_ai_post(res, author_id, answer_id, param)
|
||||
60
app_deepseek/models/mail_channel.py
Normal file
60
app_deepseek/models/mail_channel.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import logging
|
||||
import datetime
|
||||
from odoo import api, fields, models, tools, _
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.osv import expression
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Channel(models.Model):
|
||||
_inherit = 'mail.channel'
|
||||
|
||||
def get_openai_context(self, channel_id, author_id, answer_id, minutes=30, chat_count=0):
|
||||
gpt_id = False
|
||||
if self.ai_partner_id:
|
||||
ai_user = self.env['res.users'].search([('partner_id', '=', self.ai_partner_id.id)], limit=1)
|
||||
gpt_id = ai_user.mapped('gpt_id')
|
||||
if gpt_id and gpt_id.provider == 'deepseek':
|
||||
context_history = []
|
||||
afterTime = fields.Datetime.now() - datetime.timedelta(minutes=minutes)
|
||||
message_model = self.env['mail.message'].sudo()
|
||||
domain = [('res_id', '=', channel_id),
|
||||
('model', '=', 'mail.channel'),
|
||||
('message_type', '!=', 'user_notification'),
|
||||
('parent_id', '!=', False),
|
||||
('is_ai', '=', True),
|
||||
('body', '!=', '<p>%s</p>' % _('Response Timeout, please speak again.')),
|
||||
('body', '!=', _('温馨提示:您发送的内容含有敏感词,请修改内容后再向我发送。'))]
|
||||
if self.channel_type in ['group', 'channel']:
|
||||
# 群聊增加时间限制,当前找所有人,不限制 author_id
|
||||
domain = expression.AND([domain, [('date', '>=', afterTime)]])
|
||||
else:
|
||||
domain = expression.AND([domain, [('author_id', '=', answer_id.id)]])
|
||||
if chat_count == 0:
|
||||
ai_msg_list = []
|
||||
else:
|
||||
ai_msg_list = message_model.with_context(tz='UTC').search(domain, order="id asc", limit=chat_count)
|
||||
for ai_msg in ai_msg_list:
|
||||
# 判断这个 ai_msg 是不是ai发,有才 insert。 判断 user_msg 是不是 user发的,有才 insert
|
||||
user_msg = ai_msg.parent_id.sudo()
|
||||
ai_content = str(ai_msg.body).replace("<p>", "").replace("</p>", "").replace("<p>", "")
|
||||
if ai_msg.author_id.sudo().gpt_id and answer_id.sudo().gpt_id and ai_msg.author_id.sudo().gpt_id == answer_id.sudo().gpt_id:
|
||||
context_history.insert(0, {
|
||||
'role': 'assistant',
|
||||
'content': ai_content,
|
||||
})
|
||||
if not user_msg.author_id.gpt_id:
|
||||
user_content = user_msg.body.replace("<p>", "").replace("</p>", "").replace('@%s' % answer_id.name, '').lstrip()
|
||||
context_history.append({
|
||||
'role': 'user',
|
||||
'content': user_content,
|
||||
})
|
||||
context_history.append({
|
||||
'role': 'assistant',
|
||||
'content': ai_content,
|
||||
})
|
||||
return context_history
|
||||
else:
|
||||
return super(Channel, self).get_openai_context(channel_id, author_id, answer_id, minutes, chat_count)
|
||||
Reference in New Issue
Block a user