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 your OpenAPI API Key from: https://platform.openai.com/account/api-keys

+
+ +
+
+
+
+
+
+
+
+

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!

+ +
+ +
+
+
+

Support

+

+ +

+

+ Please contact us if you need customization/support for this module info@intechualsolutions.com +

+

+ https://intechualsolutions.com + Support

+ Note: We have changed our company name from Ascents Entrepreneurs to InTechual Solutions +

+
+
+
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 @@ - - - Logo - - - - + + + + + + + - {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 - -
+ + + + + + + + + +