add gpt
5
app_chatgpt/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020-Present InTechual Solutions. (<https://intechualsolutions.com/>)
|
||||
|
||||
# from . import controllers
|
||||
from . import models
|
||||
62
app_chatgpt/__manifest__.py
Normal file
@@ -0,0 +1,62 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Created on 2023-02-016
|
||||
# author: 广州尚鹏,https://www.sunpop.cn
|
||||
# email: 300883@qq.com
|
||||
# resource of Sunpop
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
# Copyright (c) 2020-Present InTechual Solutions. (<https://intechualsolutions.com/>)
|
||||
|
||||
{
|
||||
'name': 'ChatGPT Robot Multi Chat and Training(Under Construction)',
|
||||
'version': '16.23.02.20',
|
||||
'author': 'Sunpop.cn',
|
||||
'company': 'Sunpop.cn',
|
||||
'maintainer': 'Sunpop.cn',
|
||||
'category': 'Website/Website',
|
||||
'website': 'https://www.sunpop.cn',
|
||||
'license': 'LGPL-3',
|
||||
'sequence': 10,
|
||||
'license': 'AGPL-3',
|
||||
'images': ['static/description/banner.png'],
|
||||
'summary': '''
|
||||
Multi Odoo ChatGPT Robot. Integration All ChatGpt Api.
|
||||
Chat channel with several ChatGPT Robots.
|
||||
Whitelist and blacklist for Users or IP.
|
||||
Base on is_chatgpt_integration from InTechual Solutions.
|
||||
''',
|
||||
'description': '''
|
||||
Allows the application to leverage the capabilities of the GPT language model to generate human-like responses,
|
||||
providing a more natural and intuitive user experience.
|
||||
1. Multi ChatGpt robot Connector. Chat and train.
|
||||
2. Multi User Chat with ChatGpt
|
||||
3. ChatGpt Channel for Group Chat
|
||||
4. White and black List for ChatGpt
|
||||
5. Demo Chat time for new user
|
||||
6. Easy Start and Stop ChatGpt
|
||||
''',
|
||||
'depends': ['base', 'base_setup', 'mail'],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'data/mail_channel_data.xml',
|
||||
'data/ai_robot_data.xml',
|
||||
'data/user_partner_data.xml',
|
||||
'data/ir_config_parameter.xml',
|
||||
'views/res_config_settings_views.xml',
|
||||
'views/ai_robot_views.xml',
|
||||
'views/res_users_views.xml',
|
||||
],
|
||||
# 'assets': {
|
||||
# 'mail.assets_messaging': [
|
||||
# 'app_chatgpt/static/src/models/*.js',
|
||||
# ],
|
||||
# 'mail.assets_model_data': [
|
||||
# 'app_chatgpt/static/src/models_data/*.js',
|
||||
# ],
|
||||
# },
|
||||
'external_dependencies': {'python': ['openai']},
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
5
app_chatgpt/controllers/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020-Present InTechual Solutions. (<https://intechualsolutions.com/>)
|
||||
|
||||
|
||||
from . import main
|
||||
11
app_chatgpt/controllers/main.py
Normal file
@@ -0,0 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020-Present InTechual Solutions. (<https://intechualsolutions.com/>)
|
||||
|
||||
from odoo import http
|
||||
|
||||
|
||||
class ChatgptController(http.Controller):
|
||||
@http.route(['/chatgpt_form'], type='http', auth="public", csrf=False,
|
||||
website=True)
|
||||
def question_submit(self):
|
||||
return http.request.render('app_chatgpt.connector')
|
||||
15
app_chatgpt/data/ai_robot_data.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="chatgpt_robot" model="ai.robot">
|
||||
<field name="name">ChatGPT odoo</field>
|
||||
<field name="sequence">1</field>
|
||||
</record>
|
||||
<record id="chatgpt_robot1" model="ai.robot">
|
||||
<field name="name">ChatGPT Coding</field>
|
||||
<field name="sequence">6</field>
|
||||
</record>
|
||||
<record id="chatgpt_robot2" model="ai.robot">
|
||||
<field name="name">ChatGPT Finance</field>
|
||||
<field name="sequence">7</field>
|
||||
</record>
|
||||
</odoo>
|
||||
11
app_chatgpt/data/ir_config_parameter.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="config_openapi_context_timeout" model="ir.config_parameter">
|
||||
<field name="key">app_chatgpt.openapi_context_timeout</field>
|
||||
<field name="value">600</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
31
app_chatgpt/data/mail_channel_data.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record model="mail.channel" id="channel_chatgpt">
|
||||
<field name="name">ChatGPT Group Chat</field>
|
||||
<field name="description">ChatGPT企业内部频道</field>
|
||||
<field name="image_128" type="base64" file="app_chatgpt/static/description/chatgpt.png"/>
|
||||
</record>
|
||||
|
||||
<record model="mail.message" id="module_install_notification">
|
||||
<field name="model">mail.channel</field>
|
||||
<field name="res_id" ref="app_chatgpt.channel_chatgpt"/>
|
||||
<field name="message_type">email</field>
|
||||
<field name="subtype_id" ref="mail.mt_comment"/>
|
||||
<field name="subject">Welcome to ChatGPT Group Chat</field>
|
||||
<field name="body"><![CDATA[<p>Welcome to ChatGPT Group Chat.</p>
|
||||
<p>Pleas answer me any question.</p>]]></field>
|
||||
</record>
|
||||
|
||||
<record model="mail.channel.member" id="channel_member_chatgtp_channel_for_admin">
|
||||
<field name="partner_id" ref="base.partner_admin"/>
|
||||
<field name="channel_id" ref="app_chatgpt.channel_chatgpt"/>
|
||||
<field name="fetched_message_id" ref="app_chatgpt.module_install_notification"/>
|
||||
<field name="seen_message_id" ref="app_chatgpt.module_install_notification"/>
|
||||
</record>
|
||||
|
||||
<record model="mail.channel" id="app_chatgpt.channel_chatgpt">
|
||||
<field name="group_ids" eval="[Command.link(ref('base.group_user'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
50
app_chatgpt/data/user_partner_data.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="partner_chatgpt" model="res.partner">
|
||||
<field name="name">ChatGPT odoo</field>
|
||||
<field name="image_1920" type="base64" file="app_chatgpt/static/description/chatgpt.png"/>
|
||||
</record>
|
||||
<record id="user_chatgpt" model="res.users">
|
||||
<field name="login">chatgpt@sunpop.cn</field>
|
||||
<field name="password">chatgpt</field>
|
||||
<field name="partner_id" ref="app_chatgpt.partner_chatgpt"/>
|
||||
<field name="gpt_id" ref="app_chatgpt.chatgpt_robot"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="company_ids" eval="[Command.link(ref('base.main_company'))]"/>
|
||||
<field name="groups_id" eval="[Command.link(ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="partner_chatgpt1" model="res.partner">
|
||||
<field name="name">ChatGPT Coding</field>
|
||||
<field name="image_1920" type="base64" file="app_chatgpt/static/description/chatgpt.png"/>
|
||||
</record>
|
||||
|
||||
<record id="user_chatgpt1" model="res.users">
|
||||
<field name="login">chatgpt1@sunpop.cn</field>
|
||||
<field name="email">chatgpt1@sunpop.cn</field>
|
||||
<field name="password">chatgpt</field>
|
||||
<field name="partner_id" ref="app_chatgpt.partner_chatgpt1"/>
|
||||
<field name="gpt_id" ref="app_chatgpt.chatgpt_robot1"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="company_ids" eval="[Command.link(ref('base.main_company'))]"/>
|
||||
<field name="groups_id" eval="[Command.link(ref('base.group_user'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="partner_chatgpt2" model="res.partner">
|
||||
<field name="name">ChatGPT Finance</field>
|
||||
<field name="image_1920" type="base64" file="app_chatgpt/static/description/chatgpt.png"/>
|
||||
</record>
|
||||
|
||||
<record id="user_chatgpt2" model="res.users">
|
||||
<field name="login">chatgpt2@sunpop.cn</field>
|
||||
<field name="email">chatgpt2@sunpop.cn</field>
|
||||
<field name="password">chatgpt</field>
|
||||
<field name="partner_id" ref="app_chatgpt.partner_chatgpt2"/>
|
||||
<field name="gpt_id" ref="app_chatgpt.chatgpt_robot2"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="company_ids" eval="[Command.link(ref('base.main_company'))]"/>
|
||||
<field name="groups_id" eval="[Command.link(ref('base.group_user'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
27014
app_chatgpt/i18n/zh_CN.po
Normal file
8
app_chatgpt/models/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020-Present InTechual Solutions. (<https://intechualsolutions.com/>)
|
||||
|
||||
from . import mail_channel
|
||||
from . import res_config_settings
|
||||
from . import ai_robot
|
||||
from . import res_users
|
||||
from . import mail_message
|
||||
19
app_chatgpt/models/ai_robot.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import requests
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
|
||||
class AiRobot(models.Model):
|
||||
_name = 'ai.robot'
|
||||
_description = 'Gpt Robot'
|
||||
_order = 'sequence, name'
|
||||
|
||||
name = fields.Char(string='Name', translate=True)
|
||||
openapi_api_key = fields.Char(string="API Key", help="Provide the API key here")
|
||||
temperature = fields.Float(string='Temperature', default=0.9)
|
||||
sequence = fields.Integer('Sequence', help="Determine the display order", default=10)
|
||||
|
||||
def action_disconnect(self):
|
||||
requests.delete('https://chatgpt.com/v1/disconnect')
|
||||
|
||||
183
app_chatgpt/models/mail_channel.py
Normal file
@@ -0,0 +1,183 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020-Present InTechual Solutions. (<https://intechualsolutions.com/>)
|
||||
|
||||
import openai
|
||||
import requests,json
|
||||
import datetime
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.exceptions import UserError
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Channel(models.Model):
|
||||
_inherit = 'mail.channel'
|
||||
|
||||
@api.model
|
||||
def get_openai(self, api_key, data, user="Odoo"):
|
||||
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}
|
||||
pdata = {
|
||||
"model": "text-davinci-003",
|
||||
"prompt": data,
|
||||
"temperature": 0.9,
|
||||
"max_tokens": 2000,
|
||||
"top_p": 1,
|
||||
"frequency_penalty": 0.0,
|
||||
"presence_penalty": 0.6,
|
||||
"user": user,
|
||||
"stop": ["Human:", "AI:"]
|
||||
}
|
||||
response = requests.post("https://api.openai.com/v1/completions", data=json.dumps(pdata), headers=headers)
|
||||
res = response.json()
|
||||
if 'choices' in res:
|
||||
return '\n'.join([x['text'] for x in res['choices']])
|
||||
|
||||
_logger.error(res)
|
||||
return "获取结果超时,请重新跟我聊聊。"
|
||||
|
||||
@api.model
|
||||
def get_openai_context(self, channel_id, partner_chatgpt, current_prompt, seconds=600):
|
||||
afterTime = fields.Datetime.now() - datetime.timedelta(seconds=seconds)
|
||||
message_model = self.env['mail.message'].sudo()
|
||||
prompt = [f"Human:{current_prompt}\nAI:", ]
|
||||
domain = [('res_id', '=', channel_id),
|
||||
('model', '=', 'mail.channel'),
|
||||
('message_type', '!=', 'user_notification'),
|
||||
('parent_id', '=', False),
|
||||
('date', '>=', afterTime),
|
||||
('author_id', '=', self.env.user.partner_id.id)]
|
||||
messages = message_model.with_context(tz='UTC').search(domain, order="id desc", limit=15)
|
||||
# print('domain:',domain)
|
||||
# print('messages:',messages)
|
||||
for msg in messages:
|
||||
ai_msg = message_model.search([("res_id", "=", channel_id),
|
||||
('model', '=', msg.model),
|
||||
('parent_id', '=', msg.id),
|
||||
('author_id', '=', partner_chatgpt),
|
||||
('body', '!=', '<p>获取结果超时,请重新跟我聊聊。</p>')])
|
||||
if ai_msg:
|
||||
prompt.append("Human:%s\nAI:%s" % (
|
||||
msg.body.replace("<p>", "").replace("</p>", ""), ai_msg.body.replace("<p>", "").replace("</p>", "")))
|
||||
# print(msg.body.replace("<p>", "").replace("</p>", ""))
|
||||
# print(ai_msg.body.replace("<p>", "").replace("</p>", ""))
|
||||
else:
|
||||
_logger.error(f"not find for id:{str(msg.id)}")
|
||||
|
||||
return '\n'.join(prompt[::-1])
|
||||
|
||||
def get_chatgpt_answer(self, prompt, partner_name):
|
||||
response = openai.Completion.create(
|
||||
model="text-davinci-003",
|
||||
prompt=prompt,
|
||||
temperature=0.6,
|
||||
max_tokens=3000,
|
||||
top_p=1,
|
||||
frequency_penalty=0,
|
||||
presence_penalty=0,
|
||||
user=partner_name,
|
||||
)
|
||||
res = response['choices'][0]['text']
|
||||
return res
|
||||
|
||||
def _notify_thread(self, message, msg_vals=False, **kwargs):
|
||||
rdata = super(Channel, self)._notify_thread(message, msg_vals=msg_vals, **kwargs)
|
||||
# print(f'rdata:{rdata}')
|
||||
to_partner_id = self.env['res.partner']
|
||||
user_id = self.env['res.users']
|
||||
author_id = msg_vals.get('author_id')
|
||||
gpt_id = self.env['ai.robot']
|
||||
channel_type = self.channel_type
|
||||
if channel_type == 'chat':
|
||||
channel_partner_ids = self.channel_partner_ids
|
||||
to_partner_id = channel_partner_ids - message.author_id
|
||||
user_id = to_partner_id.mapped('user_ids').filtered(lambda r: r.gpt_id)[:1]
|
||||
if user_id:
|
||||
gpt_policy = user_id.gpt_policy
|
||||
gpt_wl_users = user_id.gpt_wl_users
|
||||
is_allow = message.create_uid.id in gpt_wl_users.ids
|
||||
if gpt_policy == 'all' or (gpt_policy == 'limit' and is_allow):
|
||||
gpt_id = user_id.gpt_id
|
||||
|
||||
elif channel_type in ['group', 'channel']:
|
||||
# partner_ids = @ ids
|
||||
partner_ids = list(msg_vals.get('partner_ids'))
|
||||
if partner_ids:
|
||||
partners = self.env['res.partner'].search([('id', 'in', partner_ids)])
|
||||
# user_id = user has binded gpt robot
|
||||
user_id = partners.mapped('user_ids').filtered(lambda r: r.gpt_id)[:1]
|
||||
if user_id:
|
||||
gpt_policy = user_id.gpt_policy
|
||||
gpt_wl_users = user_id.gpt_wl_users
|
||||
is_allow = message.create_uid.id in gpt_wl_users.ids
|
||||
to_partner_id = user_id.partner_id
|
||||
if gpt_policy == 'all' or (gpt_policy == 'limit' and is_allow):
|
||||
gpt_id = user_id.gpt_id
|
||||
|
||||
chatgpt_channel_id = self.env.ref('app_chatgpt.channel_chatgpt')
|
||||
|
||||
# print('author_id:',author_id)
|
||||
|
||||
# print('partner_chatgpt.id:',partner_chatgpt.id)
|
||||
|
||||
prompt = msg_vals.get('body')
|
||||
# print('prompt:', prompt)
|
||||
# print('-----')
|
||||
if not prompt:
|
||||
return rdata
|
||||
# api_key = self.env['ir.config_parameter'].sudo().get_param('app_chatgpt.openapi_api_key')
|
||||
api_key = ''
|
||||
if gpt_id:
|
||||
api_key = gpt_id.openapi_api_key
|
||||
if not api_key:
|
||||
_logger.warning(_("ChatGPT Robot【%s】have not set open api key."))
|
||||
return rdata
|
||||
try:
|
||||
openapi_context_timeout = int(self.env['ir.config_parameter'].sudo().get_param('app_chatgpt.openapi_context_timeout')) or 600
|
||||
except:
|
||||
openapi_context_timeout = 600
|
||||
|
||||
openai.api_key = api_key
|
||||
partner_name = ''
|
||||
# print(msg_vals)
|
||||
# print(msg_vals.get('record_name', ''))
|
||||
# print('self.channel_type :',self.channel_type)
|
||||
if gpt_id:
|
||||
chatgpt_name = str(gpt_id.name or '') + ', '
|
||||
# print('chatgpt_name:', chatgpt_name)
|
||||
# if author_id != to_partner_id.id and (chatgpt_name in msg_vals.get('record_name', '') or 'ChatGPT' in msg_vals.get('record_name', '') ) and self.channel_type == 'chat':
|
||||
if author_id != to_partner_id.id and self.channel_type == 'chat':
|
||||
_logger.info(f'私聊:author_id:{author_id},partner_chatgpt.id:{to_partner_id.id}')
|
||||
try:
|
||||
channel = self.env[msg_vals.get('model')].browse(msg_vals.get('res_id'))
|
||||
prompt = self.get_openai_context(channel.id, to_partner_id.id, prompt,openapi_context_timeout)
|
||||
print(prompt)
|
||||
# res = self.get_chatgpt_answer(prompt,partner_name)
|
||||
res = self.get_openai(api_key, prompt, partner_name)
|
||||
res = res.replace('\n', '<br/>')
|
||||
# print('res:',res)
|
||||
# print('channel:',channel)
|
||||
channel.with_user(user_id).message_post(body=res, message_type='comment',subtype_xmlid='mail.mt_comment',parent_id=message.id)
|
||||
# channel.with_user(user_chatgpt).message_post(body=res, message_type='notification', subtype_xmlid='mail.mt_comment')
|
||||
# channel.sudo().message_post(
|
||||
# body=res,
|
||||
# author_id=partner_chatgpt.id,
|
||||
# message_type="comment",
|
||||
# subtype_xmlid="mail.mt_comment",
|
||||
# )
|
||||
# self.with_user(user_chatgpt).message_post(body=res, message_type='comment', subtype_xmlid='mail.mt_comment')
|
||||
except Exception as e:
|
||||
raise UserError(_(e))
|
||||
|
||||
elif author_id != to_partner_id.id and msg_vals.get('model', '') == 'mail.channel' and msg_vals.get('res_id', 0) == chatgpt_channel_id.id:
|
||||
_logger.info(f'频道群聊:author_id:{author_id},partner_chatgpt.id:{to_partner_id.id}')
|
||||
try:
|
||||
prompt = self.get_openai_context(chatgpt_channel_id.id, to_partner_id.id, prompt,openapi_context_timeout)
|
||||
# print(prompt)
|
||||
# res = self.get_chatgpt_answer(prompt, partner_name)
|
||||
res = self.get_openai(api_key, prompt, partner_name)
|
||||
res = res.replace('\n', '<br/>')
|
||||
chatgpt_channel_id.with_user(user_id).message_post(body=res, message_type='comment', subtype_xmlid='mail.mt_comment',parent_id=message.id)
|
||||
except Exception as e:
|
||||
raise UserError(_(e))
|
||||
|
||||
return rdata
|
||||
13
app_chatgpt/models/mail_message.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class Message(models.Model):
|
||||
_inherit = "mail.message"
|
||||
|
||||
def _message_add_reaction(self, content):
|
||||
super(Message, self)._message_add_reaction(content)
|
||||
if self.create_uid.gpt_id:
|
||||
# 处理反馈
|
||||
pass
|
||||
10
app_chatgpt/models/res_config_settings.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) 2020-Present InTechual Solutions. (<https://intechualsolutions.com/>)
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = "res.config.settings"
|
||||
|
||||
openapi_context_timeout = fields.Integer(string="上下文连接超时", help="多少秒以内的聊天信息作为上下文继续", config_parameter="app_chatgpt.openapi_context_timeout")
|
||||
15
app_chatgpt/models/res_users.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResUsers(models.Model):
|
||||
_inherit = "res.users"
|
||||
|
||||
gpt_id = fields.Many2one('ai.robot', string='Bind to ChatGpt')
|
||||
gpt_policy = fields.Selection([
|
||||
('all', 'All Users'),
|
||||
('limit', 'Selected Users')
|
||||
], string='Allowed Conversation Mode', default='all', ondelete='set default')
|
||||
gpt_wl_users = fields.Many2many('res.users', 'res_users_res_users_rel', 'robot_id', 'user_id', string='Allowed Users', domain="[('id', '!=', id)]")
|
||||
gpt_demo_time = fields.Integer('Default Demo Time', default=0)
|
||||
2
app_chatgpt/security/ir.model.access.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_gpt_robt_user,AiRobotUser,model_ai_robot,base.group_user,1,1,1,1
|
||||
|
BIN
app_chatgpt/static/description/api_key.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
app_chatgpt/static/description/banner.png
Normal file
|
After Width: | Height: | Size: 261 KiB |
BIN
app_chatgpt/static/description/chatgpt.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
app_chatgpt/static/description/chatgpt_chat.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
app_chatgpt/static/description/icon.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
app_chatgpt/static/description/icon1.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
189
app_chatgpt/static/description/index.html
Normal file
@@ -0,0 +1,189 @@
|
||||
<section class="oe_container">
|
||||
<div class="oe_row oe_spaced">
|
||||
<h1 class="oe_slogan" style="color:#875A7B;">ChatGPT Robot Multi Chat and Training</h1>
|
||||
<h2 class="oe_slogan" style="color:#875A7B;">More powerful features. Multi chatgpt training at the same time. Base on Integrate Odoo with ChatGPT from InTechual Solutions</h2>
|
||||
<h3 class="oe_slogan">Allows the application to leverage the capabilities of the GPT language model to generate human-like responses, providing a more natural and intuitive user experience</h3>
|
||||
<div class="oe_demo oe_picture oe_screenshot">
|
||||
<img src="banner.png">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<br/>
|
||||
<br/>
|
||||
<section class="oe_container oe_mt32">
|
||||
<div class="oe_row oe_spaced">
|
||||
<h2 class="oe_slogan" style="color:#875A7B;">Configure ChatGPT API Key</h2>
|
||||
<h3 class="oe_slogan">Get your OpenAPI API Key</h3>
|
||||
<div class="oe_span12">
|
||||
<p class="oe_mt32 oe_mb32 text-justify">Get your OpenAPI API Key from: <a href="https://platform.openai.com/account/api-keys">https://platform.openai.com/account/api-keys</a></p>
|
||||
<div class="oe_demo oe_picture oe_screenshot">
|
||||
<img class='img-responsive' src="api_key.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
<section class="oe_container oe_mt32">
|
||||
<div class="oe_row oe_spaced">
|
||||
<h2 class="oe_slogan" style="color:#875A7B;">Get Best from ChatGPT</h2>
|
||||
<div class="oe_span12">
|
||||
<p class="oe_mt32 oe_mb32 text-justify">Give your promts to ChatGPT and get best out of AI.</p>
|
||||
<div class="oe_demo oe_picture oe_screenshot">
|
||||
<img class='img-responsive' src="chatgpt_chat.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<br/>
|
||||
<br/>
|
||||
<section class="oe_container oe_mt32">
|
||||
<div class="oe_row oe_spaced">
|
||||
<h2 class="oe_slogan" style="color:#875A7B;">Training Chatgpt robot</h2>
|
||||
<div class="oe_span12">
|
||||
<p class="oe_mt32 oe_mb32 text-justify">You can mark the answer from chatGpt as Good / Bad / Neutral / Redundant / Unhelpful.</p>
|
||||
<div class="oe_demo oe_picture oe_screenshot">
|
||||
<img class='img-responsive' src="chatgpt_chat.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<br/>
|
||||
<br/>
|
||||
<section class="oe_container oe_mt32">
|
||||
<div class="oe_row oe_spaced">
|
||||
<h2 class="oe_slogan" style="color:#875A7B;">Requirements</h2>
|
||||
<div class="oe_span12">
|
||||
<p class="oe_mt32 oe_mb32">
|
||||
<strong>openai</strong> python library - <br/><code>sudo python3 -m pip install openai</code>
|
||||
<br/>
|
||||
- OR -
|
||||
<br/>
|
||||
<code>pip install openai</code>
|
||||
Note: Contact us if you find any difficulties in setup/installation.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<br/>
|
||||
<br/>
|
||||
<section class="oe_container">
|
||||
<div class="oe_row oe_spaced">
|
||||
<div class="oe_span12">
|
||||
<h4 class="oe_slogan"> <a href="https://youtu.be/KwkWk4terrs" target="_blank" style="color: #FFFFFF !important; border-radius: 0; background-color: #f05c4e; border-color: #005ca7; padding: 15px; font-weight: bold;">
|
||||
<i class="fa fa-youtube"></i>
|
||||
Watch on YouTube
|
||||
</a></h4>
|
||||
<center>
|
||||
</center>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="oe_container">
|
||||
<h2 class="oe_slogan" style="color:#875A7B;">Our other apps you may like!</h2>
|
||||
<div id="slides" class="row carousel slide mt64 mb32" data-ride="carousel">
|
||||
<div class="carousel-inner">
|
||||
<div class="carousel-item active" style="min-height: 0px;">
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left;">
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/whatsapp_all_in_one" target="_blank">
|
||||
<div style="box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);border-radius: 10px;">
|
||||
<img class="img img-responsive center-block" style="border-top-left-radius: 10px; width: 360px; height: 180px; border-top-right-radius: 10px;" src="wp_all_in_one.gif">
|
||||
<h4 class="mt0" style="padding:6% 4%;text-align: center;white-space: nowrap;width: 100%;overflow: hidden;text-overflow: ellipsis;font-family: Roboto-medium;">
|
||||
WhatsApp All In One
|
||||
</h4>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left;">
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/whatsapp_sale_integration" target="_blank">
|
||||
<div style="box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);border-radius: 10px;">
|
||||
<img class="img img-responsive center-block"
|
||||
style="border-top-left-radius: 10px; width: 360px; height: 180px; border-top-right-radius: 10px;"
|
||||
src="whatsapp_sale_integration.png"/>
|
||||
<h4 class="mt0" style="padding:6% 4%;text-align: center;white-space: nowrap;width: 100%;overflow: hidden;text-overflow: ellipsis;font-family: Roboto-medium;">
|
||||
WhatsApp Delivery Integration
|
||||
</h4>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left;">
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/whatsapp_invoice_integration" target="_blank">
|
||||
<div style="box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);border-radius: 10px;">
|
||||
<img class="img img-responsive center-block"
|
||||
style="border-top-left-radius: 10px; width: 360px; height: 180px; border-top-right-radius: 10px;"
|
||||
src="whatsapp_invoice_integration.png"/>
|
||||
<h4 class="mt0" style="padding:6% 4%;text-align: center;white-space: nowrap;width: 100%;overflow: hidden;text-overflow: ellipsis;font-family: Roboto-medium;">
|
||||
WhatsApp Invoice Integration
|
||||
</h4>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left;">
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/whatsapp_pos_integration" target="_blank">
|
||||
<div style="box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);border-radius: 10px;">
|
||||
<img class="img img-responsive center-block"
|
||||
style="border-top-left-radius: 10px; width: 360px; height: 180px; border-top-right-radius: 10px;"
|
||||
src="whatsapp_pos_integration.png"/>
|
||||
<h4 class="mt0" style="padding:6% 4%;text-align: center;white-space: nowrap;width: 100%;overflow: hidden;text-overflow: ellipsis;font-family: Roboto-medium;">
|
||||
WhatsApp PoS Integration
|
||||
</h4>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left;">
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/whatsapp_purchase_integration" target="_blank">
|
||||
<div style="box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);border-radius: 10px;">
|
||||
<img class="img img-responsive center-block"
|
||||
style="border-top-left-radius: 10px; width: 360px; height: 180px; border-top-right-radius: 10px;"
|
||||
src="whatsapp_purchase_integration.png"/>
|
||||
<h4 class="mt0" style="padding:6% 4%;text-align: center;white-space: nowrap;width: 100%;overflow: hidden;text-overflow: ellipsis;font-family: Roboto-medium;">
|
||||
WhatsApp Purchase Integration
|
||||
</h4>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float: left;">
|
||||
<a href="https://apps.odoo.com/apps/modules/16.0/whatsapp_payment_integration" target="_blank">
|
||||
<div style="box-shadow: 0 15px 35px rgba(50, 50, 93, 0.1), 0 5px 15px rgba(0, 0, 0, 0.07);border-radius: 10px;">
|
||||
<img class="img img-responsive center-block"
|
||||
style="border-top-left-radius: 10px; width: 360px; height: 180px; border-top-right-radius: 10px;"
|
||||
src="whatsapp_payment_integration.png"/>
|
||||
<h4 class="mt0" style="padding:6% 4%;text-align: center;white-space: nowrap;width: 100%;overflow: hidden;text-overflow: ellipsis;font-family: Roboto-medium;">
|
||||
WhatsApp Payments Integration
|
||||
</h4>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a class="carousel-control-prev" href="#slides" data-slide="prev" style="left:-25px;width: 35px;color: #000;">
|
||||
<span class="carousel-control-prev-icon"><i class="fa fa-chevron-left" style="font-size:24px"></i></span>
|
||||
</a>
|
||||
<a class="carousel-control-next" href="#slides" data-slide="next" style="right:-25px;width: 35px;color: #000;">
|
||||
<span class="carousel-control-next-icon"><i class="fa fa-chevron-right" style="font-size:24px"></i></span>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="oe_container">
|
||||
<div class="oe_row oe_spaced">
|
||||
<div class="oe_span12">
|
||||
<h2 class="oe_slogan" style="color:#875A7B;">Support</h2>
|
||||
<p class="text-center">
|
||||
<a href="https://intechualsolutions.com" target="_blank" style="font-weight:bold; font-size:30px; color:#777 !important"><img class="img img-responsive center-block"
|
||||
style="border-top-left-radius: 10px; width: 360px; height: 115px; border-top-right-radius: 10px;" src="logo.png"/></a>
|
||||
</p>
|
||||
<p class="oe_slogan">
|
||||
Please contact us if you need customization/support for this module <a href="mailto:info@intechualsolutions.com">info@intechualsolutions.com</a>
|
||||
</p>
|
||||
<p class="text-center">
|
||||
<a class="btn btn-success mt8" title="Website" style="background-color: #ff824c; color: #FFFFFF !important;" href="https://intechualsolutions.com" target="_blank"> https://intechualsolutions.com </a>
|
||||
<a class="btn btn-success mt8" title="Website" style="background-color: #3b406d; color: #FFFFFF !important;" href="mailto:info@intechualsolutions.com"> Support </a><br/><br/>
|
||||
<span>Note: We have changed our company name from <b>Ascents Entrepreneurs</b> to <b>InTechual Solutions</b></span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
BIN
app_chatgpt/static/description/logo.png
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
app_chatgpt/static/description/main_screenshot.png
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
app_chatgpt/static/description/whatsapp_delivery_integration.png
Normal file
|
After Width: | Height: | Size: 171 KiB |
BIN
app_chatgpt/static/description/whatsapp_invoice_integration.png
Normal file
|
After Width: | Height: | Size: 192 KiB |
BIN
app_chatgpt/static/description/whatsapp_payment_integration.png
Normal file
|
After Width: | Height: | Size: 173 KiB |
BIN
app_chatgpt/static/description/whatsapp_pos_integration.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
app_chatgpt/static/description/whatsapp_purchase_integration.png
Normal file
|
After Width: | Height: | Size: 187 KiB |
BIN
app_chatgpt/static/description/whatsapp_sale_integration.png
Normal file
|
After Width: | Height: | Size: 191 KiB |
BIN
app_chatgpt/static/description/wp_all_in_one.gif
Normal file
|
After Width: | Height: | Size: 505 KiB |
48
app_chatgpt/static/src/models/emoji_registry.js
Normal file
@@ -0,0 +1,48 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { insert } from '@mail/model/model_field_command';
|
||||
import { getBundle, loadBundle } from '@web/core/assets';
|
||||
import { registerPatch } from '@mail/model/model_core';
|
||||
|
||||
registerPatch({
|
||||
name: 'EmojiRegistry',
|
||||
recordMethods: {
|
||||
async loadEmojiData() {
|
||||
this.update({isLoading: true});
|
||||
await getBundle('mail.assets_model_data').then(loadBundle);
|
||||
//优化 data 文件
|
||||
const {emojiCategoriesData, emojisData} = await odoo.runtimeImport("@app_chatgpt/models_data/emoji_data");
|
||||
if (!this.exists()) {
|
||||
return;
|
||||
}
|
||||
this._populateFromEmojiData(emojiCategoriesData, emojisData);
|
||||
},
|
||||
async _populateFromEmojiData(dataCategories, dataEmojis) {
|
||||
dataCategories.map(category => {
|
||||
const emojiCount = dataEmojis.reduce((acc, emoji) => emoji.category === category.name ? acc + 1 : acc, 0);
|
||||
this.update({
|
||||
dataCategories: insert({
|
||||
name: category.name,
|
||||
displayName: category.displayName,
|
||||
title: category.title,
|
||||
sortId: category.sortId,
|
||||
emojiCount,
|
||||
}),
|
||||
});
|
||||
});
|
||||
this.models['Emoji'].insert(dataEmojis.map(emojiData => ({
|
||||
codepoints: emojiData.codepoints,
|
||||
shortcodes: emojiData.shortcodes,
|
||||
emoticons: emojiData.emoticons,
|
||||
name: emojiData.name,
|
||||
keywords: emojiData.keywords,
|
||||
emojiDataCategory: {name: emojiData.category},
|
||||
})));
|
||||
this.update({
|
||||
isLoaded: true,
|
||||
isLoading: false,
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
21921
app_chatgpt/static/src/models_data/emoji_data.js
Normal file
63
app_chatgpt/views/ai_robot_views.xml
Normal file
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="ai_robot_tree_view" model="ir.ui.view">
|
||||
<field name="name">ai.robot.tree</field>
|
||||
<field name="model">ai.robot</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="openapi_api_key" password="True"/>
|
||||
<field name="temperature"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="ai_robot_form_view" model="ir.ui.view">
|
||||
<field name="name">ai.robot.form</field>
|
||||
<field name="model">ai.robot</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="openapi_api_key" password="True"/>
|
||||
<field name="temperature"/>
|
||||
<field name="sequence"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_ai_robot" model="ir.actions.act_window">
|
||||
<field name="name">GPT Robot</field>
|
||||
<field name="res_model">ai.robot</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Let's create a GPT Robot.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="model_ai_robot_action_disconnect" model="ir.actions.server">
|
||||
<field name="name">Disconnect</field>
|
||||
<field name="model_id" ref="app_chatgpt.model_ai_robot"/>
|
||||
<field name="binding_model_id" ref="app_chatgpt.model_ai_robot"/>
|
||||
<field name="binding_view_types">list,form</field>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = records.action_disconnect()</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
id="menu_ai_robot"
|
||||
name="GPT Robot"
|
||||
parent="base.menu_users"
|
||||
sequence="2"
|
||||
action="action_ai_robot"
|
||||
groups="base.group_system"/>
|
||||
|
||||
</odoo>
|
||||
26
app_chatgpt/views/res_config_settings_views.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
<record id="is_res_config_settings_view" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.view.form.is.chatgpt.inherit</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='integration']" position="after">
|
||||
<h2>ChatGPT</h2>
|
||||
<div class="col-xs-12 row o_settings_container" id="chatgpt_integraion">
|
||||
<div class="col-xs-12 col-md-10 o_setting_box">
|
||||
<div class="o_setting_right_pane border-start-0">
|
||||
<div class="content-group">
|
||||
<div class="row mt0">
|
||||
<label class="col-lg-2" string="上下文连接超时" for="openapi_context_timeout"/>
|
||||
<field name="openapi_context_timeout" title="上下文连接超时 秒数" style="width: 10% !important;"/>秒
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
22
app_chatgpt/views/res_users_views.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="app_chatgpt_res_users_form" model="ir.ui.view">
|
||||
<field name="name">app.chatgpt.res.users.form</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='preferences']" position="after">
|
||||
<page name="page_chatgpt" string="ChatGPT">
|
||||
<group>
|
||||
<group>
|
||||
<field name="gpt_id"/>
|
||||
<field name="gpt_policy"/>
|
||||
<field name="gpt_wl_users" widget="many2many_tags" attrs="{'invisible': [('gpt_policy', '=', 'all')]}"/>
|
||||
<field name="gpt_demo_time"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||