diff --git a/app_chatgpt/__init__.py b/app_chatgpt/__init__.py
new file mode 100644
index 00000000..8a67bc5a
--- /dev/null
+++ b/app_chatgpt/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020-Present InTechual Solutions. ()
+
+# from . import controllers
+from . import models
diff --git a/app_chatgpt/__manifest__.py b/app_chatgpt/__manifest__.py
new file mode 100644
index 00000000..509a2c27
--- /dev/null
+++ b/app_chatgpt/__manifest__.py
@@ -0,0 +1,50 @@
+# -*- 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. ()
+
+{
+ 'name': 'ChatGPT Robot Multi Chat and Training(Under Construction)',
+ 'version': '16.23.02.15',
+ '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',
+ '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': [
+ 'data/mail_channel_data.xml',
+ 'data/user_partner_data.xml',
+ 'data/ir_config_parameter.xml',
+ 'views/res_config_settings_views.xml',
+ ],
+ 'external_dependencies': {'python': ['openai']},
+ 'images': ['static/description/banner.png'],
+ 'installable': True,
+ 'application': False,
+ 'auto_install': False,
+}
diff --git a/app_chatgpt/controllers/__init__.py b/app_chatgpt/controllers/__init__.py
new file mode 100644
index 00000000..dcd9a093
--- /dev/null
+++ b/app_chatgpt/controllers/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020-Present InTechual Solutions. ()
+
+
+from . import main
diff --git a/app_chatgpt/controllers/main.py b/app_chatgpt/controllers/main.py
new file mode 100644
index 00000000..e85192b4
--- /dev/null
+++ b/app_chatgpt/controllers/main.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020-Present InTechual Solutions. ()
+
+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')
diff --git a/app_chatgpt/data/ir_config_parameter.xml b/app_chatgpt/data/ir_config_parameter.xml
new file mode 100644
index 00000000..728f78cb
--- /dev/null
+++ b/app_chatgpt/data/ir_config_parameter.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+ app_chatgpt.openapi_context_timeout
+ 600
+
+
+
+
\ No newline at end of file
diff --git a/app_chatgpt/data/mail_channel_data.xml b/app_chatgpt/data/mail_channel_data.xml
new file mode 100644
index 00000000..f56b40d1
--- /dev/null
+++ b/app_chatgpt/data/mail_channel_data.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ ChatGPT群聊
+ ChatGPT企业内部频道
+
+
+
+
+ mail.channel
+
+ email
+
+ 欢迎来到ChatGPT的odoo群聊频道!
+ 欢迎进行 #ChatGPT 群聊.
+ 向ChatGPT咨询你的问题.
]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app_chatgpt/data/user_partner_data.xml b/app_chatgpt/data/user_partner_data.xml
new file mode 100644
index 00000000..0071b111
--- /dev/null
+++ b/app_chatgpt/data/user_partner_data.xml
@@ -0,0 +1,17 @@
+
+
+
+
+ ChatGPT的odoo机器人
+
+
+
+ chatgpt@sunpop.cn
+ chatgpt
+
+
+
+
+
+
+
diff --git a/app_chatgpt/models/__init__.py b/app_chatgpt/models/__init__.py
new file mode 100644
index 00000000..381d5ad3
--- /dev/null
+++ b/app_chatgpt/models/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020-Present InTechual Solutions. ()
+
+from . import mail_channel
+from . import res_config_settings
diff --git a/app_chatgpt/models/mail_channel.py b/app_chatgpt/models/mail_channel.py
new file mode 100644
index 00000000..0dd713c6
--- /dev/null
+++ b/app_chatgpt/models/mail_channel.py
@@ -0,0 +1,145 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020-Present InTechual Solutions. ()
+
+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": 1000,
+ "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', '!=', '获取结果超时,请重新跟我聊聊。
')])
+ if ai_msg:
+ prompt.append("Human:%s\nAI:%s" % (
+ msg.body.replace("", "").replace("
", ""), ai_msg.body.replace("", "").replace("
", "")))
+ # print(msg.body.replace("", "").replace("
", ""))
+ # print(ai_msg.body.replace("", "").replace("
", ""))
+ 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}')
+ chatgpt_channel_id = self.env.ref('app_chatgpt.channel_chatgpt')
+ user_chatgpt = self.env.ref("app_chatgpt.user_chatgpt")
+ partner_chatgpt = self.env.ref("app_chatgpt.partner_chatgpt")
+ author_id = msg_vals.get('author_id')
+ # print('author_id:',author_id)
+ # print('partner_chatgpt.id:',partner_chatgpt.id)
+ chatgpt_name = str(partner_chatgpt.name or '') + ', '
+ # print('chatgpt_name:', chatgpt_name)
+ 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')
+ 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 = self.env['res.partner']
+ partner_name = ''
+ if author_id:
+ partner_id = Partner.browse(author_id)
+ if partner_id:
+ partner_name = partner_id.name
+ # print(msg_vals)
+ # print(msg_vals.get('record_name', ''))
+ # print('self.channel_type :',self.channel_type)
+ if author_id != partner_chatgpt.id and (chatgpt_name in msg_vals.get('record_name', '') or 'ChatGPT,' in msg_vals.get('record_name', '') ) and self.channel_type == 'chat':
+ _logger.info(f'私聊:author_id:{author_id},partner_chatgpt.id:{partner_chatgpt.id}')
+ try:
+ channel = self.env[msg_vals.get('model')].browse(msg_vals.get('res_id'))
+ prompt = self.get_openai_context(channel.id, partner_chatgpt.id, prompt,openapi_context_timeout)
+ print(prompt)
+ # res = self.get_chatgpt_answer(prompt,partner_name)
+ res = self.get_openai(api_key, prompt, partner_name)
+ # print('res:',res)
+ # print('channel:',channel)
+ channel.with_user(user_chatgpt).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 != partner_chatgpt.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:{partner_chatgpt.id}')
+ try:
+ prompt = self.get_openai_context(chatgpt_channel_id.id, partner_chatgpt.id, prompt,openapi_context_timeout)
+ # print(prompt)
+ # res = self.get_chatgpt_answer(prompt, partner_name)
+ res = self.get_openai(api_key, prompt, partner_name)
+ chatgpt_channel_id.with_user(user_chatgpt).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
diff --git a/app_chatgpt/models/res_config_settings.py b/app_chatgpt/models/res_config_settings.py
new file mode 100644
index 00000000..c7fcfcf6
--- /dev/null
+++ b/app_chatgpt/models/res_config_settings.py
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020-Present InTechual Solutions. ()
+
+from odoo import fields, models
+
+
+class ResConfigSettings(models.TransientModel):
+ _inherit = "res.config.settings"
+
+ openapi_api_key = fields.Char(string="API Key", help="Provide the API key here", config_parameter="app_chatgpt.openapi_api_key")
+ openapi_context_timeout = fields.Integer(string="上下文连接超时", help="多少秒以内的聊天信息作为上下文继续", config_parameter="app_chatgpt.openapi_context_timeout")
diff --git a/app_chatgpt/static/description/api_key.png b/app_chatgpt/static/description/api_key.png
new file mode 100644
index 00000000..43ddb036
Binary files /dev/null and b/app_chatgpt/static/description/api_key.png differ
diff --git a/app_chatgpt/static/description/banner.png b/app_chatgpt/static/description/banner.png
new file mode 100644
index 00000000..517d9dea
Binary files /dev/null and b/app_chatgpt/static/description/banner.png differ
diff --git a/app_chatgpt/static/description/chatgpt.png b/app_chatgpt/static/description/chatgpt.png
new file mode 100644
index 00000000..20a03f9d
Binary files /dev/null and b/app_chatgpt/static/description/chatgpt.png differ
diff --git a/app_chatgpt/static/description/chatgpt_chat.png b/app_chatgpt/static/description/chatgpt_chat.png
new file mode 100644
index 00000000..7a253e46
Binary files /dev/null and b/app_chatgpt/static/description/chatgpt_chat.png differ
diff --git a/app_chatgpt/static/description/icon.png b/app_chatgpt/static/description/icon.png
new file mode 100644
index 00000000..ac07f385
Binary files /dev/null and b/app_chatgpt/static/description/icon.png differ
diff --git a/app_chatgpt/static/description/icon1.png b/app_chatgpt/static/description/icon1.png
new file mode 100644
index 00000000..1a45580f
Binary files /dev/null and b/app_chatgpt/static/description/icon1.png differ
diff --git a/app_chatgpt/static/description/index.html b/app_chatgpt/static/description/index.html
new file mode 100644
index 00000000..c246a854
--- /dev/null
+++ b/app_chatgpt/static/description/index.html
@@ -0,0 +1,176 @@
+
+
+
ChatGPT Robot Multi Chat and Training(Under Construction)
+
Base on Integrate Odoo with ChatGPT from InTechual Solutions
+
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
+
+
+

+
+
+
+
+
+
+
+
Configure ChatGPT API Key
+
Get your OpenAPI API Key
+
+
+
+
+
+
+
+
Get Best from ChatGPT
+
+
Give your promts to ChatGPT and get best out of AI.
+
+

+
+
+
+
+
+
+
+
+
Requirements
+
+
+ openai python library -
sudo python3 -m pip install openai
+
+ - OR -
+
+ pip install openai
+ Note: Contact us if you find any difficulties in setup/installation.
+
+
+
+
+
+
+
+
+ Our other apps you may like!
+
+
+
+
diff --git a/app_chatgpt/static/description/logo.png b/app_chatgpt/static/description/logo.png
new file mode 100644
index 00000000..3cf57902
Binary files /dev/null and b/app_chatgpt/static/description/logo.png differ
diff --git a/app_chatgpt/static/description/main_screenshot.png b/app_chatgpt/static/description/main_screenshot.png
new file mode 100644
index 00000000..4a9c0774
Binary files /dev/null and b/app_chatgpt/static/description/main_screenshot.png differ
diff --git a/app_chatgpt/static/description/whatsapp_delivery_integration.png b/app_chatgpt/static/description/whatsapp_delivery_integration.png
new file mode 100644
index 00000000..43c5d224
Binary files /dev/null and b/app_chatgpt/static/description/whatsapp_delivery_integration.png differ
diff --git a/app_chatgpt/static/description/whatsapp_invoice_integration.png b/app_chatgpt/static/description/whatsapp_invoice_integration.png
new file mode 100644
index 00000000..93b96f3c
Binary files /dev/null and b/app_chatgpt/static/description/whatsapp_invoice_integration.png differ
diff --git a/app_chatgpt/static/description/whatsapp_payment_integration.png b/app_chatgpt/static/description/whatsapp_payment_integration.png
new file mode 100644
index 00000000..4db589ad
Binary files /dev/null and b/app_chatgpt/static/description/whatsapp_payment_integration.png differ
diff --git a/app_chatgpt/static/description/whatsapp_pos_integration.png b/app_chatgpt/static/description/whatsapp_pos_integration.png
new file mode 100644
index 00000000..29222f53
Binary files /dev/null and b/app_chatgpt/static/description/whatsapp_pos_integration.png differ
diff --git a/app_chatgpt/static/description/whatsapp_purchase_integration.png b/app_chatgpt/static/description/whatsapp_purchase_integration.png
new file mode 100644
index 00000000..1717290a
Binary files /dev/null and b/app_chatgpt/static/description/whatsapp_purchase_integration.png differ
diff --git a/app_chatgpt/static/description/whatsapp_sale_integration.png b/app_chatgpt/static/description/whatsapp_sale_integration.png
new file mode 100644
index 00000000..7da97127
Binary files /dev/null and b/app_chatgpt/static/description/whatsapp_sale_integration.png differ
diff --git a/app_chatgpt/static/description/wp_all_in_one.gif b/app_chatgpt/static/description/wp_all_in_one.gif
new file mode 100644
index 00000000..d8a86e70
Binary files /dev/null and b/app_chatgpt/static/description/wp_all_in_one.gif differ
diff --git a/app_chatgpt/views/res_config_settings_views.xml b/app_chatgpt/views/res_config_settings_views.xml
new file mode 100644
index 00000000..f9260998
--- /dev/null
+++ b/app_chatgpt/views/res_config_settings_views.xml
@@ -0,0 +1,30 @@
+
+
+
+ res.config.settings.view.form.is.chatgpt.inherit
+ res.config.settings
+
+
+
+ ChatGPT
+
+
+
+
+
diff --git a/app_web_enterprise/__manifest__.py b/app_web_enterprise/__manifest__.py
index baf83463..0509d5aa 100644
--- a/app_web_enterprise/__manifest__.py
+++ b/app_web_enterprise/__manifest__.py
@@ -61,13 +61,17 @@
('before', 'web_enterprise/static/src/scss/primary_variables.scss', 'app_web_enterprise/static/src/scss/primary_variables.scss'),
],
'web.assets_backend': [
+ ('after', 'web/static/src/views/**/*', 'app_web_enterprise/static/src/scss/views_style.scss'),
'app_web_enterprise/static/src/components/*/*.xml',
+ 'app_web_enterprise/static/src/webclient/**/*.xml',
+ # 'app_web_enterprise/static/src/xml/base.xml',
],
# 这里是改样式,要 after处理
'web.assets_common': [
('after', 'web_enterprise/static/src/webclient/home_menu/home_menu_background.scss', 'app_web_enterprise/static/src/scss/home_menu_background.scss'),
],
'web.assets_frontend': [
+ # ('after', 'web/static/src/core/**/*', 'app_web_enterprise/static/src/xml/base.xml'),
('after', 'web_enterprise/static/src/webclient/home_menu/home_menu_background.scss', 'app_web_enterprise/static/src/scss/home_menu_background.scss'),
],
},
diff --git a/app_web_enterprise/static/src/scss/views_style.scss b/app_web_enterprise/static/src/scss/views_style.scss
new file mode 100644
index 00000000..8dc39173
--- /dev/null
+++ b/app_web_enterprise/static/src/scss/views_style.scss
@@ -0,0 +1,12 @@
+//list 改标头背景
+.o_list_renderer {
+ .o_list_table {
+ :not(.o_field_x2many_list) > & thead, tfoot {
+ tr > :not(:empty) {
+ padding-top: var(--ListRenderer-thead-padding-v);
+ padding-bottom: var(--ListRenderer-thead-padding-v);
+ background-color: $o-gray-100;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app_web_enterprise/static/src/webclient/navbar.xml b/app_web_enterprise/static/src/webclient/navbar.xml
new file mode 100644
index 00000000..1f328e95
--- /dev/null
+++ b/app_web_enterprise/static/src/webclient/navbar.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app_web_enterprise/static/src/xml/base.xml b/app_web_enterprise/static/src/xml/base.xml
index f41591d1..d79a6f83 100644
--- a/app_web_enterprise/static/src/xml/base.xml
+++ b/app_web_enterprise/static/src/xml/base.xml
@@ -1,15 +1,17 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
- {show: state.open}
+
+ {{ directionCaretClass || ''}}
+ {{ state.open ? 'show' : ''}}
diff --git a/app_web_enterprise/static/src/xml/res_config_edition.xml b/app_web_enterprise/static/src/xml/res_config_edition.xml
index e7c02f5c..886d72d6 100644
--- a/app_web_enterprise/static/src/xml/res_config_edition.xml
+++ b/app_web_enterprise/static/src/xml/res_config_edition.xml
@@ -1,13 +1,13 @@
-
-
-
- odooApp (Sunpop.cn Edition)
-
-
-
- GNU LGPL Licensed
-
-
+
+
+
+
+
+
+
+
+
+