# -*- coding: utf-8 -*- import datetime from http import HTTPStatus import dashscope import pytz from bs4 import BeautifulSoup from dashscope import Generation from odoo import models, fields, _ LLM_MODELS = { 'aigc': 'qwen-14b-chat', 'qwen': 'qwen-14b-chat', 'baichuan': 'baichuan2-7b-chat-v1', 'chatglm': 'chatglm-6b-v2', 'llama2': 'llama2-13b-chat-v2', } class ResConfigSettings(models.TransientModel): _inherit = ['res.config.settings'] apikey_qwen = fields.Char(string='Qwen API Key', config_parameter='qwen_api_key') class ResUsers(models.Model): _inherit = 'res.users' odoobot_state = fields.Selection(selection_add=[ ('aigc', 'AIGC'), ('qwen', 'Qwen'), ('chatglm', 'ChatGLM'), ('baichuan', 'Baichuan'), ('llama2', 'Llama2'), ]) class MailBot(models.AbstractModel): _inherit = 'mail.bot' def _get_answer(self, record, body, values, command): odoobot_state = self.env.user.odoobot_state odoobot_mode = self.env['ir.config_parameter'].sudo().get_param('odoobot_mode') if body == "#help": return _( "输入如下命令,激活相应的功能:
" "#enable 激活AIGC模式
" "#disable 退出AIGC模式
" "#clear 清理聊天记录
" "#qwen 通义千问模型
" "#baichuan 百川大语言模型
" "#chatglm chatglm大语言模型
" ) elif body == "#enable": self.env.user.odoobot_state = 'aigc' return "AIGC enabled" elif body == "#disable": self.env.user.odoobot_state = 'disabled' return "AIGC disabled" elif body == "#clear": message_ids = self.env['mail.channel'].search([('id', '=', record.id)]).message_ids.ids self.env['mail.message'].search([('id', 'in', message_ids[1:])], order='id desc').unlink() return # "cleared all the messages" elif body == "#qwen": self.env.user.odoobot_state = 'qwen' return "Qwen enabled" elif body == "#baichuan": self.env.user.odoobot_state = 'baichuan' return "Baichuan enabled" elif body == "#chatglm": self.env.user.odoobot_state = 'chatglm' return "ChatGLM enabled" exclusion = {'o_mail_notification', 'o_mail_redirect', 'o_channel_redirect'} msg_sys = [ele for ele in exclusion if (ele in body)] if msg_sys: return super(MailBot, self)._get_answer(record, body, values, command) if odoobot_state not in ['aigc', 'qwen', 'chatglm', 'baichuan']: return super(MailBot, self)._get_answer(record, body, values, command) message_new = [] message_ids = self.env['mail.channel'].search([('id', '=', record.id)]).message_ids.ids message_ids = self.env['mail.message'].search([('id', 'in', message_ids)], order='id desc', limit=32, offset=1) # llm_model = LLM_MODELS[odoobot_state] prompt, history = self.prompt(llm_model=odoobot_state, message_ids=message_ids) # print(history) message_new.append({'role': 'system', 'content': prompt}) if odoobot_state not in ['chatglm'] else None for item in history: message_new.append(item) message_new.append({"role": "user", "content": body}) if odoobot_state not in ['chatglm'] else None if odoobot_mode == 'streaming': self.with_delay().respond(odoobot_state, odoobot_mode, record, message_new, body) else: return self.respond(odoobot_state,odoobot_mode, record, message_new, body) def prompt(self, llm_model, message_ids): lang = self.env.user.lang tz = self.env.user.tz local = pytz.timezone(tz) now = datetime.datetime.strftime(pytz.utc.localize(datetime.datetime.utcnow()).astimezone(local), "%Y-%m-%d %H:%M:%S") lang = self.env['res.lang'].search([('code', '=', lang)]).name app = self.env['ir.module.module'].search([('state', '=', 'installed'), ('application', '=', True)]).mapped('name') message_ids = list(reversed(message_ids)) length = len(message_ids) bot_id = self.env.ref("base.partner_root") history = [] prompt = f""" You are an assistant and work for this company with name {self.env.company.name}; 你是{self.env.company.name}助手; the date and time now is {now} with timezone {tz}; 当前日期和时间 {now} 时区 {tz}; Apps installed: {str(app)}; 已经安装的应用: {str(app)}; answer in: {lang}; 回答使用: {lang} """ if llm_model in ['chatglm']: history.append(['我的身份背景信息,名字等?', prompt]) i = 0 for message_id in message_ids: i += 1 if message_id.author_id.id != bot_id.id and i != length: message_user = BeautifulSoup(message_id.body, 'html.parser').get_text() if message_ids[i].author_id.id == bot_id.id: message_assistant = BeautifulSoup(message_ids[i].body, 'html.parser').get_text() if message_user and message_assistant: item_user = {"role": "user", "content": message_user} if llm_model not in ['chatglm'] else message_user item_assistant = {"role": "assistant", "content": message_assistant} if llm_model not in ['chatglm'] else message_assistant if llm_model in ['chatglm']: history.append([item_user, item_assistant]) else: history.append(item_user) history.append(item_assistant) return prompt, history def respond(self, llm_model, mode, record, messages, prompt=None): dashscope.api_key = self.env['ir.config_parameter'].sudo().get_param('qwen_api_key') gen = Generation() content = '' model = LLM_MODELS[llm_model] if llm_model in ['chatglm']: response = gen.call(model=model, prompt=prompt, history=messages) if response.status_code == HTTPStatus.OK: # print(response) content = response.output['text'] elif llm_model in ['qwen', 'baichuan']: response = gen.call(model, messages=messages, result_format='message', enable_search=True) if response.status_code == HTTPStatus.OK: content = response.output.choices[0]['message']['content'] else: response = gen.call(model, messages=messages, result_format='message', enable_search=True) if response.status_code == HTTPStatus.OK: content = response.output.choices[0]['message']['content'] if not content: msg = ('Request id: %s, Status code: %s, error code: %s, error message: %s' % ( response.request_id, response.status_code, response.code, response.message )) content = msg + str(response) if mode == 'streaming': odoobot_id = self.env.ref("base.partner_root") mod_response = self.env['mail.channel'].with_context(chatgpt=True).browse(record.id).message_post( body=content, message_type='comment', subtype_xmlid='mail.mt_comment', author_id=odoobot_id.id ) return mod_response return content