move and update 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
|
||||||
50
app_chatgpt/__manifest__.py
Normal file
@@ -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. (<https://intechualsolutions.com/>)
|
||||||
|
|
||||||
|
{
|
||||||
|
'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,
|
||||||
|
}
|
||||||
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')
|
||||||
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群聊</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">欢迎来到ChatGPT的odoo群聊频道!</field>
|
||||||
|
<field name="body"><![CDATA[<p>欢迎进行 #ChatGPT 群聊.</p>
|
||||||
|
<p>向ChatGPT咨询你的问题</b>.</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>
|
||||||
17
app_chatgpt/data/user_partner_data.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?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="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>
|
||||||
5
app_chatgpt/models/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2020-Present InTechual Solutions. (<https://intechualsolutions.com/>)
|
||||||
|
|
||||||
|
from . import mail_channel
|
||||||
|
from . import res_config_settings
|
||||||
145
app_chatgpt/models/mail_channel.py
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# -*- 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": 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', '!=', '<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}')
|
||||||
|
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
|
||||||
11
app_chatgpt/models/res_config_settings.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# -*- 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_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")
|
||||||
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 |
176
app_chatgpt/static/description/index.html
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
<section class="oe_container">
|
||||||
|
<div class="oe_row oe_spaced">
|
||||||
|
<h1 class="oe_slogan" style="color:#875A7B;">ChatGPT Robot Multi Chat and Training(Under Construction)</h1>
|
||||||
|
<h2 class="oe_slogan" style="color:#875A7B;">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="main_screenshot.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;">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 |
30
app_chatgpt/views/res_config_settings_views.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?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 mt12">
|
||||||
|
<label class="col-lg-3" string="API Key" for="openapi_api_key"/>
|
||||||
|
<field name="openapi_api_key" title="OpenAPI API Key" style="width: 90% !important;" password="True"/>
|
||||||
|
</div>
|
||||||
|
<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>
|
||||||
@@ -61,13 +61,17 @@
|
|||||||
('before', 'web_enterprise/static/src/scss/primary_variables.scss', 'app_web_enterprise/static/src/scss/primary_variables.scss'),
|
('before', 'web_enterprise/static/src/scss/primary_variables.scss', 'app_web_enterprise/static/src/scss/primary_variables.scss'),
|
||||||
],
|
],
|
||||||
'web.assets_backend': [
|
'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/components/*/*.xml',
|
||||||
|
'app_web_enterprise/static/src/webclient/**/*.xml',
|
||||||
|
# 'app_web_enterprise/static/src/xml/base.xml',
|
||||||
],
|
],
|
||||||
# 这里是改样式,要 after处理
|
# 这里是改样式,要 after处理
|
||||||
'web.assets_common': [
|
'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'),
|
('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': [
|
'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'),
|
('after', 'web_enterprise/static/src/webclient/home_menu/home_menu_background.scss', 'app_web_enterprise/static/src/scss/home_menu_background.scss'),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
12
app_web_enterprise/static/src/scss/views_style.scss
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
app_web_enterprise/static/src/webclient/navbar.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<templates xml:space="preserve">
|
||||||
|
|
||||||
|
<t t-name="app_web_enterprise.EnterpriseNavBar" t-inherit="web_enterprise.EnterpriseNavBar" t-inherit-mode="extension">
|
||||||
|
<!-- todo: 以下主要是测试,改这个主图标为 O -->
|
||||||
|
<xpath expr="//a[hasclass('o_menu_toggle')]" position="replace">
|
||||||
|
<a href="#" class="o_menu_toggle fa fa-2x fa-opera" style="font-size: 2em;" accesskey="h" t-ref="menuApps" t-on-click.prevent="() => this.hm.toggle()">
|
||||||
|
<!-- <svg width="14px" height="14px" viewBox="0 0 14 14" xmlns="http://www.w3.org/2000/svg" >-->
|
||||||
|
<!-- <g t-foreach="[0, 5, 10]" t-as="Y" t-att-id="'o_menu_toggle_row_' + Y_index" fill="currentColor" t-key="'o_menu_toggle_row_' + Y_index">-->
|
||||||
|
<!-- <rect t-foreach="[0, 5, 10]" t-as="X" width="4" height="4" t-att-x="X" t-att-y="Y" t-key="'o_menu_toggle_cell_' + X_index"/>-->
|
||||||
|
<!-- </g>-->
|
||||||
|
<!-- </svg>-->
|
||||||
|
</a>
|
||||||
|
</xpath>
|
||||||
|
</t>
|
||||||
|
<!-- web.NavBar.SectionsMenu-->
|
||||||
|
<!-- 没有子菜单时,调用web.DropdownItem-->
|
||||||
|
<!-- web.UserMenu-->
|
||||||
|
|
||||||
|
|
||||||
|
</templates>
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<templates id="template" xml:space="preserve">
|
<templates id="template" xml:space="preserve">
|
||||||
|
|
||||||
<t t-extend="HomeMenu.Content">
|
<!-- <t t-extend="HomeMenu.Content">-->
|
||||||
<t t-jquery=".o_home_menu_footer" t-operation="inner">
|
<!-- <t t-jquery=".o_home_menu_footer" t-operation="inner">-->
|
||||||
<img src='/web/binary/company_logo' alt="Logo"/>
|
<!-- <img src='/web/binary/company_logo' alt="Logo"/>-->
|
||||||
</t>
|
<!-- </t>-->
|
||||||
</t>
|
<!-- </t>-->
|
||||||
<!-- 菜单有下拉箭头-->
|
<!-- 菜单有下拉箭头, owl的在 web.NavBar.SectionsMenu, 有group的用 MenuDropdown, 直接操作的用 DropdownItem -->
|
||||||
<t t-inherit="web.Dropdown" t-inherit-mode="extension">
|
<t t-name="app_web_enterprise.Dropdown" t-inherit="web.Dropdown">
|
||||||
<xpath expr="//div[hasclass('o-dropdown')]" position="attributes">
|
<xpath expr="//div[hasclass('o-dropdown')]" position="attributes">
|
||||||
<attribute name="t-att-class">{show: state.open}</attribute>
|
<attribute name="t-att-class">
|
||||||
|
{{ directionCaretClass || ''}}
|
||||||
|
{{ state.open ? 'show' : ''}}</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
</t>
|
</t>
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<templates xml:space="preserve">
|
<templates xml:space="preserve">
|
||||||
<t t-extend="res_config_edition">
|
<!-- <t t-extend="res_config_edition">-->
|
||||||
<t t-jquery=".user-heading h3" t-operation="replace">
|
<!-- <t t-jquery=".user-heading h3" t-operation="replace">-->
|
||||||
<h3>
|
<!-- <h3>-->
|
||||||
odooApp <t t-esc="widget.server_version"/> (Sunpop.cn Edition)
|
<!-- odooApp <t t-esc="widget.server_version"/> (Sunpop.cn Edition)-->
|
||||||
</h3>
|
<!-- </h3>-->
|
||||||
</t>
|
<!-- </t>-->
|
||||||
<t t-jquery=".user-o_web_settings_compact_subtitle small" t-operation="replace">
|
<!-- <t t-jquery=".user-o_web_settings_compact_subtitle small" t-operation="replace">-->
|
||||||
<small><a target="_blank" href="http://www.gnu.org/licenses/lgpl.html" style="text-decoration: underline;">GNU LGPL Licensed</a></small>
|
<!-- <small><a target="_blank" href="http://www.gnu.org/licenses/lgpl.html" style="text-decoration: underline;">GNU LGPL Licensed</a></small>-->
|
||||||
</t>
|
<!-- </t>-->
|
||||||
</t>
|
<!-- </t>-->
|
||||||
</templates>
|
</templates>
|
||||||
|
|||||||