@ -0,0 +1,52 @@ |
|||||
|
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg |
||||
|
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
ChatGPT Odoo Connector |
||||
|
====================== |
||||
|
This module simplifies content creation and editing by integrating ChatGPT. |
||||
|
It also facilitates the generation of images for newly created products and |
||||
|
when modifying product names. Additionally, it includes a Speech-to-Text feature |
||||
|
that allows users to convert spoken language into written text, making hands-free |
||||
|
interaction possible and further streamlining the content creation process. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
The user should install 'openai' for Python by running: |
||||
|
'sudo pip install openai' for authorization code flow. |
||||
|
|
||||
|
Company |
||||
|
------- |
||||
|
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
||||
|
|
||||
|
License |
||||
|
------- |
||||
|
Affero General Public License, Version 3 (AGPL v3). |
||||
|
(https://www.gnu.org/licenses/agpl-3.0-standalone.html) |
||||
|
|
||||
|
Credits |
||||
|
------- |
||||
|
Developer: (V16) Ashwin A, Contact: odoo@cybrosys.com |
||||
|
|
||||
|
Contacts |
||||
|
-------- |
||||
|
* Mail Contact : odoo@cybrosys.com |
||||
|
* Website : https://cybrosys.com |
||||
|
|
||||
|
Bug Tracker |
||||
|
----------- |
||||
|
Bugs are tracked on GitHub Issues. In case of trouble, please check there if |
||||
|
your issue has already been reported. |
||||
|
|
||||
|
Maintainer |
||||
|
========== |
||||
|
.. image:: https://cybrosys.com/images/logo.png |
||||
|
:target: https://cybrosys.com |
||||
|
|
||||
|
This module is maintained by Cybrosys Technologies. |
||||
|
|
||||
|
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
||||
|
|
||||
|
Further information |
||||
|
=================== |
||||
|
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,23 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
from . import controllers |
||||
|
from . import models |
@ -0,0 +1,63 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
{ |
||||
|
"name": "ChatGPT Odoo Connector", |
||||
|
"version": "16.0.1.0.0", |
||||
|
"category": "Productivity, Extra Tools ", |
||||
|
"summary": "User can create content, Generate product image and Convert spoken language into written text using AI.", |
||||
|
"description": """ This module simplifies content creation and editing by integrating ChatGPT. |
||||
|
It also facilitates the generation of images for newly created products and |
||||
|
when modifying product names. Additionally, it includes a Speech-to-Text feature |
||||
|
that allows users to convert spoken language into written text, making hands-free |
||||
|
interaction possible and further streamlining the content creation process.""", |
||||
|
'author': 'Cybrosys Techno Solutions', |
||||
|
'company': 'Cybrosys Techno Solutions', |
||||
|
'maintainer': 'Cybrosys Techno Solutions', |
||||
|
'website': "https://www.cybrosys.com", |
||||
|
'depends': ['mail', 'product', 'web_editor'], |
||||
|
'data': [ |
||||
|
'security/ir.model.access.csv', |
||||
|
'views/res_config_settings_views.xml', |
||||
|
'views/product_template.xml', |
||||
|
'views/product_product.xml', |
||||
|
], |
||||
|
'assets': { |
||||
|
'web_editor.assets_wysiwyg': [ |
||||
|
'chatgpt_odoo_connector/static/src/xml/web_editor_toolbar.xml', |
||||
|
'chatgpt_odoo_connector/static/src/xml/alternative_chatgpt.xml', |
||||
|
], |
||||
|
'web.assets_backend': [ |
||||
|
'chatgpt_odoo_connector/static/src/css/chatgpt_odoo.css', |
||||
|
'chatgpt_odoo_connector/static/src/js/wysiwyg.js', |
||||
|
'chatgpt_odoo_connector/static/src/js/open_chatgpt.js', |
||||
|
'chatgpt_odoo_connector/static/src/js/recordAudio.js', |
||||
|
'chatgpt_odoo_connector/static/src/js/custom_toolbar.js', |
||||
|
'chatgpt_odoo_connector/static/src/js/alternative_chatgpt.js', |
||||
|
], |
||||
|
}, |
||||
|
'external_dependencies': {'python': ['openai']}, |
||||
|
'images': ['static/description/banner.png'], |
||||
|
'license': 'AGPL-3', |
||||
|
'installable': True, |
||||
|
'auto_install': False, |
||||
|
'application': False, |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
from . import chatgpt_odoo_connector |
@ -0,0 +1,43 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
from odoo import http |
||||
|
from pathlib import Path |
||||
|
from odoo.http import request |
||||
|
import os |
||||
|
from odoo.tools import json |
||||
|
|
||||
|
|
||||
|
class SpeechToText(http.Controller): |
||||
|
@http.route('/upload_audio', type='http', auth='public', methods=['POST'], csrf=False) |
||||
|
def upload_audio(self, **kwargs): |
||||
|
""" |
||||
|
Function for uploading audio file into a file and |
||||
|
returns the path of the file as json format |
||||
|
""" |
||||
|
upload_dir = Path(__file__).parent |
||||
|
file = kwargs.get('file') |
||||
|
if file: |
||||
|
file_path = os.path.join(upload_dir, file.filename) |
||||
|
with open(file_path, 'wb') as f: |
||||
|
f.write(file.read()) |
||||
|
return request.make_response(json.dumps({'filePath': file_path}), headers={'Content-Type': 'application/json'}) |
||||
|
return request.make_response(json.dumps({'error': 'No file uploaded'}), headers={'Content-Type': 'application/json'}) |
@ -0,0 +1,8 @@ |
|||||
|
## Module <chatgpt_odoo_connector> |
||||
|
|
||||
|
#### 27.05.2024 |
||||
|
#### Version 16.0.1.0.0 |
||||
|
#### ADD |
||||
|
|
||||
|
- Initial commit for ChatGPT Odoo Connector |
||||
|
|
@ -0,0 +1,25 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
from . import open_chatgpt |
||||
|
from . import product_product |
||||
|
from . import product_template |
||||
|
from . import res_config_settings |
@ -0,0 +1,91 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
from os import remove |
||||
|
from openai import OpenAI |
||||
|
from odoo import api, models |
||||
|
|
||||
|
|
||||
|
class ChatGPTOdoo(models.Model): |
||||
|
_name = 'open.chatgpt' |
||||
|
_description = 'Open ChatGPT' |
||||
|
|
||||
|
@api.model |
||||
|
def get_response(self, message): |
||||
|
"""Function for getting response based on the message.""" |
||||
|
api_key = self.env['ir.config_parameter'].sudo().get_param('chatgpt_odoo_connector.api_key') |
||||
|
client = OpenAI(api_key=api_key) |
||||
|
try: |
||||
|
chat_completion = client.chat.completions.create( |
||||
|
messages=[ |
||||
|
{ |
||||
|
"role": "user", |
||||
|
"content": message, |
||||
|
} |
||||
|
], |
||||
|
model="gpt-3.5-turbo", |
||||
|
) |
||||
|
except Exception as e: |
||||
|
message = str(e).split("'message':")[1] |
||||
|
error_message = message.split(", 'type':")[0] |
||||
|
return error_message |
||||
|
return chat_completion.choices[0].message.content |
||||
|
|
||||
|
@api.model |
||||
|
def edit_content(self, message, message_type): |
||||
|
"""Function for editing(shortening, lengthening, and rephrasing) the description """ |
||||
|
api_key = self.env['ir.config_parameter'].sudo().get_param( |
||||
|
'chatgpt_odoo_connector.api_key') |
||||
|
client = OpenAI(api_key=api_key) |
||||
|
try: |
||||
|
chat_completion = client.chat.completions.create( |
||||
|
messages=[ |
||||
|
{ |
||||
|
"role": "user", |
||||
|
"content": f"{message_type}: {message}", |
||||
|
} |
||||
|
], |
||||
|
model="gpt-3.5-turbo", |
||||
|
) |
||||
|
except Exception as e: |
||||
|
message = str(e).split("'message':")[1] |
||||
|
error_message = message.split(", 'type':")[0] |
||||
|
return error_message |
||||
|
return chat_completion.choices[0].message.content |
||||
|
|
||||
|
@api.model |
||||
|
def convert_to_text(self, audio_path): |
||||
|
""" Function for converting the audio from the file into text using AI. |
||||
|
It returns the text. |
||||
|
""" |
||||
|
api_key = self.env['ir.config_parameter'].sudo().get_param( |
||||
|
'chatgpt_odoo_connector.api_key') |
||||
|
client = OpenAI(api_key=api_key) |
||||
|
try: |
||||
|
audio_file = open(audio_path, "rb") |
||||
|
transcription = client.audio.transcriptions.create( |
||||
|
model="whisper-1", |
||||
|
file=audio_file |
||||
|
) |
||||
|
remove(audio_path) |
||||
|
except Exception as e: |
||||
|
return f'Error: {str(e)}' |
||||
|
return transcription.text |
@ -0,0 +1,91 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
import base64 |
||||
|
import requests |
||||
|
from openai import OpenAI |
||||
|
from odoo import api, fields, models |
||||
|
|
||||
|
|
||||
|
class ProductProduct(models.Model): |
||||
|
_inherit = 'product.product' |
||||
|
|
||||
|
is_create_image = fields.Boolean(related='product_tmpl_id.is_create_image', |
||||
|
string='Generate Image', |
||||
|
readonly=False, |
||||
|
help='Check this box if you want to automatically generate an image for this product') |
||||
|
|
||||
|
is_update_image = fields.Boolean(related='product_tmpl_id.is_update_image', |
||||
|
string='Update Image', |
||||
|
readonly=False, |
||||
|
help='Check this box if you want to automatically update an image for this product while changing the name.') |
||||
|
|
||||
|
@api.model |
||||
|
def create(self, vals): |
||||
|
""" Method for generating images for product """ |
||||
|
res = super(ProductProduct, self).create(vals) |
||||
|
if not res.image_1920 and res.is_create_image: |
||||
|
image_base64 = self.generate_image(res.name) |
||||
|
if image_base64: |
||||
|
res.write({ |
||||
|
'image_1920': image_base64, |
||||
|
}) |
||||
|
else: |
||||
|
res.message_post( |
||||
|
body="Failed to generate image for product: '%s' due to 'Incorrect API key provided or Other issues. You can find your API key at https://platform.openai.com/account/api-keys." % res.name, |
||||
|
message_type='notification') |
||||
|
return res |
||||
|
|
||||
|
def write(self, vals): |
||||
|
""" Method for updating image if name of the product updates""" |
||||
|
if 'name' in vals and 'image_1920' not in vals: |
||||
|
is_update_image = vals.get('is_update_image', self.is_update_image) |
||||
|
if is_update_image: |
||||
|
image_base64 = self.generate_image(vals['name']) |
||||
|
if image_base64: |
||||
|
vals['image_1920'] = image_base64 |
||||
|
else: |
||||
|
self.message_post( |
||||
|
body="Failed to update image for product: '%s' due to 'Incorrect API key provided or Other issues. You can find your API key at https://platform.openai.com/account/api-keys." % |
||||
|
vals['name'], |
||||
|
message_type='notification') |
||||
|
return super(ProductProduct, self).write(vals) |
||||
|
|
||||
|
def generate_image(self, name): |
||||
|
""" Function for generating images with the help of AI based on the name |
||||
|
of the product""" |
||||
|
api_key = self.env['ir.config_parameter'].sudo().get_param( |
||||
|
'chatgpt_odoo_connector.api_key') |
||||
|
client = OpenAI(api_key=api_key) |
||||
|
try: |
||||
|
response = client.images.generate( |
||||
|
model="dall-e-3", |
||||
|
prompt=name, |
||||
|
size="1024x1024", |
||||
|
quality="standard", |
||||
|
n=1, |
||||
|
) |
||||
|
image_url = response.data[0].url |
||||
|
response = requests.get(image_url) |
||||
|
image_base64 = base64.b64encode(response.content) |
||||
|
except: |
||||
|
return None |
||||
|
return image_base64 |
@ -0,0 +1,88 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
import base64 |
||||
|
import requests |
||||
|
from openai import OpenAI |
||||
|
from odoo import api, fields, models |
||||
|
|
||||
|
|
||||
|
class ProductTemplate(models.Model): |
||||
|
_inherit = 'product.template' |
||||
|
|
||||
|
is_create_image = fields.Boolean(string='Generate Image', |
||||
|
default=True, |
||||
|
help='Check this box if you want to automatically generate an image for this product') |
||||
|
|
||||
|
is_update_image = fields.Boolean(string='Update Image', |
||||
|
help='Check this box if you want to automatically update an image for this product while changing the name.') |
||||
|
|
||||
|
@api.model |
||||
|
def create(self, vals): |
||||
|
""" Method for generating images for product """ |
||||
|
res = super(ProductTemplate, self).create(vals) |
||||
|
if not res.image_1920 and res.is_create_image: |
||||
|
image_base64 = self.generate_image(res.name) |
||||
|
if image_base64: |
||||
|
res.write({ |
||||
|
'image_1920': image_base64, |
||||
|
}) |
||||
|
else: |
||||
|
res.message_post( |
||||
|
body="Failed to generate image for product: '%s' due to 'Incorrect API key provided or Other issues. You can find your API key at https://platform.openai.com/account/api-keys." % res.name, |
||||
|
message_type='notification') |
||||
|
return res |
||||
|
|
||||
|
def write(self, vals): |
||||
|
""" Method for updating image if name of the product updates""" |
||||
|
if 'name' in vals and 'image_1920' not in vals: |
||||
|
is_update_image = vals.get('is_update_image', self.is_update_image) |
||||
|
if is_update_image: |
||||
|
image_base64 = self.generate_image(vals['name']) |
||||
|
if image_base64: |
||||
|
vals['image_1920'] = image_base64 |
||||
|
else: |
||||
|
self.message_post( |
||||
|
body="Failed to update image for product: '%s' due to 'Incorrect API key provided or Other issues. You can find your API key at https://platform.openai.com/account/api-keys." % |
||||
|
vals['name'], |
||||
|
message_type='notification') |
||||
|
return super(ProductTemplate, self).write(vals) |
||||
|
|
||||
|
def generate_image(self, name): |
||||
|
""" Function for generating images with the help of AI based on the name |
||||
|
of the product""" |
||||
|
api_key = self.env['ir.config_parameter'].sudo().get_param( |
||||
|
'chatgpt_odoo_connector.api_key') |
||||
|
client = OpenAI(api_key=api_key) |
||||
|
try: |
||||
|
response = client.images.generate( |
||||
|
model="dall-e-3", |
||||
|
prompt=name, |
||||
|
size="1024x1024", |
||||
|
quality="standard", |
||||
|
n=1, |
||||
|
) |
||||
|
image_url = response.data[0].url |
||||
|
response = requests.get(image_url) |
||||
|
image_base64 = base64.b64encode(response.content) |
||||
|
except: |
||||
|
return None |
||||
|
return image_base64 |
@ -0,0 +1,30 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
||||
|
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
||||
|
# |
||||
|
# You can modify it under the terms of the GNU AFFERO |
||||
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, |
||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
||||
|
# (AGPL v3) along with this program. |
||||
|
# If not, see <http://www.gnu.org/licenses/>. |
||||
|
# |
||||
|
############################################################################# |
||||
|
from odoo import fields, models |
||||
|
|
||||
|
|
||||
|
class ResConfigSettings(models.TransientModel): |
||||
|
"""Add field to configuration settings""" |
||||
|
_inherit = "res.config.settings" |
||||
|
|
||||
|
api_key = fields.Char(string="API Key", help="Provide the API Key here", |
||||
|
config_parameter="chatgpt_odoo_connector.api_key") |
|
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 967 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 127 KiB |
After Width: | Height: | Size: 121 KiB |
After Width: | Height: | Size: 121 KiB |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 135 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 150 KiB |
After Width: | Height: | Size: 133 KiB |
After Width: | Height: | Size: 119 KiB |
After Width: | Height: | Size: 119 KiB |
After Width: | Height: | Size: 141 KiB |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 140 KiB |
After Width: | Height: | Size: 154 KiB |
After Width: | Height: | Size: 121 KiB |
After Width: | Height: | Size: 143 KiB |
After Width: | Height: | Size: 157 KiB |
After Width: | Height: | Size: 120 KiB |
After Width: | Height: | Size: 160 KiB |
After Width: | Height: | Size: 153 KiB |
After Width: | Height: | Size: 169 KiB |
After Width: | Height: | Size: 242 KiB |
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 14 KiB |
@ -0,0 +1,752 @@ |
|||||
|
<div style="background-color: #714B67; height: 810px; width: 100%; padding: 15px; position: relative;"> |
||||
|
<!-- TITLE BAR --> |
||||
|
<div class="d-flex align-items-center justify-content-between" |
||||
|
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;"> |
||||
|
<img src="assets/misc/cybrosys-logo.png" width="42" height="42" |
||||
|
style="width: 42px; height: 42px;"/> |
||||
|
<div> |
||||
|
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" |
||||
|
class="mr-2"> |
||||
|
<i class="fa fa-check mr-1"></i>Community |
||||
|
</div> |
||||
|
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" |
||||
|
class="mr-2"> |
||||
|
<i class="fa fa-check mr-1"></i>Enterprise |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- END OF TITLE BAR --> |
||||
|
<div class="container"> |
||||
|
<div class="row"> |
||||
|
<div class="col-sm-12 col-md-12 col-lg-12"> |
||||
|
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;"> |
||||
|
ChatGPT Odoo Connector |
||||
|
</h1> |
||||
|
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;"> |
||||
|
User can create content, Generate product image and Convert |
||||
|
spoken language into written text using AI |
||||
|
</p> |
||||
|
<!-- END OF APP HERO --> |
||||
|
<img src="assets/screenshots/hero.gif" class="img-responsive" |
||||
|
style="width: 100%; margin-left: auto; margin-right: auto;" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
|
||||
|
<!-- NAVIGATION SECTION --> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;"> |
||||
|
<div class="d-flex justify-content-center align-items-center mr-2" |
||||
|
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
||||
|
<img src="assets/misc/compass.png"/> |
||||
|
</div> |
||||
|
<h2 class="mt-2" |
||||
|
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
||||
|
Explore This |
||||
|
Module</h2> |
||||
|
</div> |
||||
|
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;"> |
||||
|
<div class="col-sm-12 col-md-6 my-3"> |
||||
|
<a href="#overview"> |
||||
|
<div class="d-flex justify-content-between align-items-center" |
||||
|
style="background-color: #f5f5f5; padding: 30px; width: 100%;"> |
||||
|
<div> |
||||
|
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span> |
||||
|
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn more about this module</span> |
||||
|
</div> |
||||
|
<img src="assets/misc/right-arrow.png" width="36" height="36"/> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
<div class="col-sm-12 col-md-6 my-3"> |
||||
|
<a href="#features"> |
||||
|
<div class="d-flex justify-content-between align-items-center" |
||||
|
style="background-color: #f5f5f5; padding: 30px; width: 100%;"> |
||||
|
<div> |
||||
|
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span> |
||||
|
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View features of this module</span> |
||||
|
</div> |
||||
|
<img src="assets/misc/right-arrow.png" width="36" height="36"/> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
<div class="col-sm-12 col-md-6 my-3"> |
||||
|
<a href="#screenshots"> |
||||
|
<div class="d-flex justify-content-between align-items-center" |
||||
|
style="background-color: #f5f5f5; padding: 30px; width: 100%;"> |
||||
|
<div> |
||||
|
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span> |
||||
|
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View screenshots for this module</span> |
||||
|
</div> |
||||
|
<img src="assets/misc/right-arrow.png" width="36" height="36"/> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- END OF NAVIGATION SECTION --> |
||||
|
|
||||
|
<!-- OVERVIEW SECTION --> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" |
||||
|
id="overview"> |
||||
|
<div class="d-flex justify-content-center align-items-center mr-2" |
||||
|
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
||||
|
<img src="assets/misc/pie-chart.png"/> |
||||
|
</div> |
||||
|
<h2 class="mt-2" |
||||
|
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
||||
|
Overview |
||||
|
</h2> |
||||
|
</div> |
||||
|
<div class="row" |
||||
|
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;"> |
||||
|
<div class="col-sm-12 py-4"> |
||||
|
This module simplifies content creation and editing by integrating ChatGPT. |
||||
|
It also facilitates the generation of images for newly created products and |
||||
|
when modifying product names. Additionally, it includes a Speech-to-Text feature |
||||
|
that allows users to convert spoken language into written text, making hands-free |
||||
|
interaction possible and further streamlining the content creation process. |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- END OF OVERVIEW SECTION --> |
||||
|
|
||||
|
<!-- FEATURES SECTION --> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" |
||||
|
id="features"> |
||||
|
<div class="d-flex justify-content-center align-items-center mr-2" |
||||
|
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
||||
|
<img src="assets/misc/features.png"/> |
||||
|
</div> |
||||
|
<h2 class="mt-2" |
||||
|
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
||||
|
Features |
||||
|
</h2> |
||||
|
</div> |
||||
|
<div class="row" |
||||
|
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;"> |
||||
|
<div class="col-sm-12 col-md-6"> |
||||
|
|
||||
|
<div class="d-flex align-items-center" |
||||
|
style="margin-top: 30px; margin-bottom: 30px"> |
||||
|
<img src="assets/misc/check-box.png" class="mr-2"/> |
||||
|
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Available in Odoo 16.0 Community & Enterprise</span> |
||||
|
</div> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="margin-top: 30px; margin-bottom: 30px"> |
||||
|
<img src="assets/misc/check-box.png" class="mr-2"/> |
||||
|
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Easy to Set Up API Key of the ChatGPT</span> |
||||
|
</div> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="margin-top: 30px; margin-bottom: 30px"> |
||||
|
<img src="assets/misc/check-box.png" class="mr-2"/> |
||||
|
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Accessing questions and answers directly from the Odoo interface is as easy as interacting with ChatGPT</span> |
||||
|
</div> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="margin-top: 30px; margin-bottom: 30px"> |
||||
|
<img src="assets/misc/check-box.png" class="mr-2"/> |
||||
|
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Image generation for products using AI</span> |
||||
|
</div> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="margin-top: 30px; margin-bottom: 30px"> |
||||
|
<img src="assets/misc/check-box.png" class="mr-2"/> |
||||
|
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Speech to Text feature for hands-free interaction</span> |
||||
|
</div> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="margin-top: 30px; margin-bottom: 30px"> |
||||
|
<img src="assets/misc/check-box.png" class="mr-2"/> |
||||
|
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Speech to Text feature supports 57 languages</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- END OF FEATURES SECTION --> |
||||
|
|
||||
|
<!-- SCREENSHOTS SECTION --> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" |
||||
|
id="screenshots"> |
||||
|
<div class="d-flex justify-content-center align-items-center mr-2" |
||||
|
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
||||
|
<img src="assets/misc/pictures.png"/> |
||||
|
</div> |
||||
|
<h2 class="mt-2" |
||||
|
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
||||
|
Screenshots |
||||
|
</h2> |
||||
|
</div> |
||||
|
<div class="row"> |
||||
|
<div class="col-sm-12"> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
||||
|
Setting API Key |
||||
|
</h3> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
Simply set chatGPT API Key inside Settings. You can find your API key at |
||||
|
<a href="https://platform.openai.com/account/api-keys">https://platform.openai.com/account/api-keys</a> |
||||
|
</p> |
||||
|
<img src="assets/screenshots/1.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
We can access ChatGPT from Text field section by typing '/'. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/2.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
When we're selecting the ChatGPT option, we can have an interface for entering the question and click Send Icon. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/3.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
We can see the generated response and also an 'INSERT' button. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/4.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
While clicking the 'INSERT' button the generated response from AI will be added to the Notes field. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/5.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
We can use the ChatGPT option for generating mail content also. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/6.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
||||
|
Additional Feature |
||||
|
</h3> |
||||
|
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
||||
|
Edit Content |
||||
|
</h3> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
We can perform various process on the content |
||||
|
such as shortening , lengthening or rephrasing the content. |
||||
|
Access these features by selecting the content. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/7.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
Upon clicking the icon, a popup window emerges, presenting users |
||||
|
with various buttons for content processing options: shortening, |
||||
|
lengthening, or rephrasing. This interface allows users to select |
||||
|
their preferred method for modifying the content according to |
||||
|
their specific needs or objectives. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/8.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
By clicking any of the button it will generate response and shows |
||||
|
in the specified field, and we can replace the content by clicking |
||||
|
the 'REPLACE' button. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/9.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
If any errors while generating response it will return the response as error as shown in the image below. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/10.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
||||
|
Generate Image |
||||
|
</h3> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
Generate product image using AI while creating a new product or Updating name of a product. |
||||
|
To use the feature while creating a product, enable "Generate Image," enter a name for the product, and save. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/11.png" class="img-thumbnail"> |
||||
|
<img src="assets/screenshots/12.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
For updating the product image while changing the product name, enable "Update Image". |
||||
|
By turning on it will automatically generate an image and update it. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/13.png" class="img-thumbnail"> |
||||
|
<img src="assets/screenshots/14.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
If any errors encounter while generating or updating image using AI it will create a message in Log note. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/15.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> |
||||
|
Speech-to-text |
||||
|
</h3> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
Speech-to-Text using AI allows users to convert spoken language |
||||
|
into written text seamlessly. This feature leverages advanced artificial |
||||
|
intelligence to accurately transcribe voice inputs, enabling hands-free |
||||
|
interaction and improving efficiency in tasks such as note-taking, and content creation. |
||||
|
</p> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
We can access Speech-to-text from Text field section by typing '/'. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/16.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
When we're selecting the Speech-to-text option, we can have an interface for recoding audio. |
||||
|
Start the recording by clicking the button. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/17.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
After recording audio stop the recording by clicking the button. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/18.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
By stopping the recording, the system will process the audio and |
||||
|
provide the transcribed text in the response. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/19.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
<div style="display: block; margin: 30px auto;"> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"> |
||||
|
While clicking the 'INSERT' button the generated Text form audio using AI will be added to the Notes field. |
||||
|
</p> |
||||
|
<img src="assets/screenshots/20.png" class="img-thumbnail"> |
||||
|
<img src="assets/screenshots/21.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- END OF SCREENSHOTS SECTION --> |
||||
|
|
||||
|
<!-- RELATED PRODUCTS --> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
||||
|
<div class="d-flex justify-content-center align-items-center mr-2" |
||||
|
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
||||
|
<img src="assets/misc/categories.png"/> |
||||
|
</div> |
||||
|
<h2 class="mt-2" |
||||
|
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
||||
|
Related |
||||
|
Products |
||||
|
</h2> |
||||
|
</div> |
||||
|
<div class="row"> |
||||
|
<div class="col-sm-12"> |
||||
|
<div id="demo1" class="row carousel slide" data-ride="carousel"> |
||||
|
<!-- The slideshow --> |
||||
|
<div class="carousel-inner" style="padding: 30px;"> |
||||
|
<div class="carousel-item" style="min-height: 198.656px;"> |
||||
|
<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/hide_menu_user/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius: 0px;" |
||||
|
src="assets/modules/1.png"> |
||||
|
</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/odoo_dynamic_dashboard/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius: 0px;" |
||||
|
src="assets/modules/2.png"> |
||||
|
</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_mail_messaging/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius: 0px;" |
||||
|
src="assets/modules/3.png"> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="carousel-item active" |
||||
|
style="min-height: 198.656px;"> |
||||
|
<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/login_user_detail/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius: 0px;" |
||||
|
src="assets/modules/4.png"> |
||||
|
</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/all_in_one_dynamic_custom_fields/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius: 0px;" |
||||
|
src="assets/modules/5.png"> |
||||
|
</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/rest_api_odoo/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius: 0px;" |
||||
|
src="assets/modules/6.png"> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- Left and right controls --> |
||||
|
<a class="carousel-control-prev" href="#demo1" data-slide="prev" |
||||
|
style="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="#demo1" |
||||
|
data-slide="next" style="width:35px; color:#000"> |
||||
|
<span class="carousel-control-next-icon"><i |
||||
|
class="fa fa-chevron-right" |
||||
|
style="font-size:24px"></i></span> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- END OF RELATED PRODUCTS --> |
||||
|
|
||||
|
<!-- OUR SERVICES --> |
||||
|
<section class="container" style="margin-top: 6rem !important;"> |
||||
|
<div class="row"> |
||||
|
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center"> |
||||
|
<h2 style="color: #212529 !important;">Our Services</h2> |
||||
|
<hr style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
||||
|
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
||||
|
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
||||
|
<img src="assets/icons/cogs.png" class="img-responsive" |
||||
|
height="48px" width="48px"> |
||||
|
</div> |
||||
|
<h6 class="text-center" |
||||
|
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
||||
|
Odoo |
||||
|
Customization</h6> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
||||
|
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
||||
|
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
||||
|
<img src="assets/icons/wrench.png" class="img-responsive" |
||||
|
height="48px" width="48px"> |
||||
|
</div> |
||||
|
<h6 class="text-center" |
||||
|
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
||||
|
Odoo |
||||
|
Implementation</h6> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
||||
|
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
||||
|
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
||||
|
<img src="assets/icons/lifebuoy.png" class="img-responsive" |
||||
|
height="48px" width="48px"> |
||||
|
</div> |
||||
|
<h6 class="text-center" |
||||
|
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
||||
|
Odoo |
||||
|
Support</h6> |
||||
|
</div> |
||||
|
|
||||
|
|
||||
|
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
||||
|
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
||||
|
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
||||
|
<img src="assets/icons/user.png" class="img-responsive" |
||||
|
height="48px" width="48px"> |
||||
|
</div> |
||||
|
<h6 class="text-center" |
||||
|
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
||||
|
Hire |
||||
|
Odoo |
||||
|
Developer</h6> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
||||
|
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
||||
|
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
||||
|
<img src="assets/icons/puzzle.png" class="img-responsive" |
||||
|
height="48px" width="48px"> |
||||
|
</div> |
||||
|
<h6 class="text-center" |
||||
|
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
||||
|
Odoo |
||||
|
Integration</h6> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
||||
|
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
||||
|
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
||||
|
<img src="assets/icons/update.png" class="img-responsive" |
||||
|
height="48px" width="48px"> |
||||
|
</div> |
||||
|
<h6 class="text-center" |
||||
|
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
||||
|
Odoo |
||||
|
Migration</h6> |
||||
|
</div> |
||||
|
|
||||
|
|
||||
|
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
||||
|
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
||||
|
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
||||
|
<img src="assets/icons/consultation.png" class="img-responsive" |
||||
|
height="48px" width="48px"> |
||||
|
</div> |
||||
|
<h6 class="text-center" |
||||
|
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
||||
|
Odoo |
||||
|
Consultancy</h6> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
||||
|
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
||||
|
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
||||
|
<img src="assets/icons/training.png" class="img-responsive" |
||||
|
height="48px" width="48px"> |
||||
|
</div> |
||||
|
<h6 class="text-center" |
||||
|
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
||||
|
Odoo Implementation</h6> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
||||
|
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
||||
|
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
||||
|
<img src="assets/icons/license.png" class="img-responsive" |
||||
|
height="48px" width="48px"> |
||||
|
</div> |
||||
|
<h6 class="text-center" |
||||
|
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
||||
|
Odoo Licensing Consultancy</h6> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
<!-- END OF OUR SERVICES --> |
||||
|
|
||||
|
<!-- OUR INDUSTRIES --> |
||||
|
<section class="container" style="margin-top: 6rem !important;"> |
||||
|
<div class="row"> |
||||
|
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center"> |
||||
|
<h2 style="color: #212529 !important;">Our Industries</h2> |
||||
|
<hr |
||||
|
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-3"> |
||||
|
<div class="my-4 d-flex flex-column justify-content-center" |
||||
|
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
||||
|
<img src="./assets/icons/trading-black.png" |
||||
|
class="img-responsive mb-3" height="48px" width="48px"> |
||||
|
<h5 |
||||
|
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
||||
|
Trading |
||||
|
</h5> |
||||
|
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
||||
|
Easily procure and sell your products</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-3"> |
||||
|
<div class="my-4 d-flex flex-column justify-content-center" |
||||
|
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
||||
|
<img src="./assets/icons/pos-black.png" |
||||
|
class="img-responsive mb-3" height="48px" width="48px"> |
||||
|
<h5 |
||||
|
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
||||
|
POS |
||||
|
</h5> |
||||
|
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
||||
|
Easy |
||||
|
configuration |
||||
|
and convivial experience</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-3"> |
||||
|
<div class="my-4 d-flex flex-column justify-content-center" |
||||
|
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
||||
|
<img src="./assets/icons/education-black.png" |
||||
|
class="img-responsive mb-3" height="48px" |
||||
|
width="48px"> |
||||
|
<h5 |
||||
|
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
||||
|
Education |
||||
|
</h5> |
||||
|
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
||||
|
A platform for |
||||
|
educational management</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-3"> |
||||
|
<div class="my-4 d-flex flex-column justify-content-center" |
||||
|
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
||||
|
<img src="./assets/icons/manufacturing-black.png" |
||||
|
class="img-responsive mb-3" height="48px" |
||||
|
width="48px"> |
||||
|
<h5 |
||||
|
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
||||
|
Manufacturing |
||||
|
</h5> |
||||
|
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
||||
|
Plan, track and |
||||
|
schedule your operations</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-3"> |
||||
|
<div class="my-4 d-flex flex-column justify-content-center" |
||||
|
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
||||
|
<img src="./assets/icons/ecom-black.png" |
||||
|
class="img-responsive mb-3" height="48px" width="48px"> |
||||
|
<h5 |
||||
|
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
||||
|
E-commerce & Website |
||||
|
</h5> |
||||
|
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
||||
|
Mobile |
||||
|
friendly, |
||||
|
awe-inspiring product pages</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-3"> |
||||
|
<div class="my-4 d-flex flex-column justify-content-center" |
||||
|
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
||||
|
<img src="./assets/icons/service-black.png" |
||||
|
class="img-responsive mb-3" height="48px" width="48px"> |
||||
|
<h5 |
||||
|
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
||||
|
Service Management |
||||
|
</h5> |
||||
|
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
||||
|
Keep track of |
||||
|
services and invoice</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-3"> |
||||
|
<div class="my-4 d-flex flex-column justify-content-center" |
||||
|
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
||||
|
<img src="./assets/icons/restaurant-black.png" |
||||
|
class="img-responsive mb-3" height="48px" |
||||
|
width="48px"> |
||||
|
<h5 |
||||
|
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
||||
|
Restaurant |
||||
|
</h5> |
||||
|
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
||||
|
Run your bar or |
||||
|
restaurant methodically</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="col-lg-3"> |
||||
|
<div class="my-4 d-flex flex-column justify-content-center" |
||||
|
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
||||
|
<img src="./assets/icons/hotel-black.png" |
||||
|
class="img-responsive mb-3" height="48px" width="48px"> |
||||
|
<h5 |
||||
|
style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
||||
|
Hotel Management |
||||
|
</h5> |
||||
|
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
||||
|
An |
||||
|
all-inclusive |
||||
|
hotel management application</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
</section> |
||||
|
|
||||
|
<!-- END OF OUR INDUSTRIES --> |
||||
|
|
||||
|
<!-- FOOTER --> |
||||
|
<!-- Footer Section --> |
||||
|
<section class="container" style="margin: 5rem auto 2rem;"> |
||||
|
<div class="row" style="max-width:1540px;"> |
||||
|
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center"> |
||||
|
<h2 style="color: #212529 !important;">Need Help?</h2> |
||||
|
<hr |
||||
|
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- Contact Cards --> |
||||
|
<div class="row d-flex justify-content-center align-items-center" |
||||
|
style="max-width:1540px; margin: 0 auto 2rem auto;"> |
||||
|
|
||||
|
<div class="col-lg-12" |
||||
|
style="padding: 0rem 3rem 2rem; border-radius: 10px; margin-right: 3rem; "> |
||||
|
|
||||
|
<div class="row mt-4"> |
||||
|
<div class="col-lg-6"> |
||||
|
<a href="mailto:odoo@cybrosys.com" target="_blank" |
||||
|
class="btn btn-block mb-2 deep_hover" |
||||
|
style="text-decoration: none; background-color: #4d4d4d; color: #FFF; border-radius: 4px;"><i |
||||
|
class="fa fa-envelope mr-2"></i>odoo@cybrosys.com</a> |
||||
|
</div> |
||||
|
<div class="col-lg-6"> |
||||
|
<a href="https://api.whatsapp.com/send?phone=918606827707" |
||||
|
target="_blank" |
||||
|
class="btn btn-block mb-2 deep_hover" |
||||
|
style="text-decoration: none; background-color: #25D366; color: #FFF; border-radius: 4px;"><i |
||||
|
class="fa fa-whatsapp mr-2"></i>+91 86068 27707</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
<!-- End of Contact Cards --> |
||||
|
</section> |
||||
|
<!-- Footer --> |
||||
|
<section class="oe_container" style="padding: 2rem 3rem 1rem;"> |
||||
|
<div class="row" |
||||
|
style="max-width:1540px; margin: 0 auto; margin-right: 3rem; "> |
||||
|
<!-- Logo --> |
||||
|
<div class="col-lg-12 d-flex justify-content-center align-items-center" |
||||
|
style="margin-top: 3rem;"> |
||||
|
<img src="https://www.cybrosys.com/images/logo.png" width="200px" |
||||
|
height="auto"/> |
||||
|
</div> |
||||
|
<!-- End of Logo --> |
||||
|
<div class="col-lg-12"> |
||||
|
<hr |
||||
|
style="margin-top: 3rem;background: linear-gradient(90deg, rgba(2,0,36,0) 0%, rgba(229,229,229,1) 33%, rgba(229,229,229,1) 58%, rgba(0,212,255,0) 100%); height: 2px; border-style: none;"> |
||||
|
<!-- End of Footer Section --> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
<!-- END OF FOOTER --> |
After Width: | Height: | Size: 16 KiB |
@ -0,0 +1,94 @@ |
|||||
|
.popChatGPT{ |
||||
|
background-color: #2d2d2d; |
||||
|
width: 600px; |
||||
|
height: 360px; |
||||
|
position: fixed; |
||||
|
left: 28%; |
||||
|
top: 28%; |
||||
|
padding: 50px; |
||||
|
z-index: 9999; |
||||
|
border-radius: 25px; |
||||
|
} |
||||
|
|
||||
|
.popChatGPTAlter{ |
||||
|
background-color: #2d2d2d; |
||||
|
width: 600px; |
||||
|
height: 360px; |
||||
|
position: fixed; |
||||
|
left: 28%; |
||||
|
top: 28%; |
||||
|
padding: 50px; |
||||
|
z-index: 9999; |
||||
|
border-radius: 25px; |
||||
|
} |
||||
|
|
||||
|
.heading{ |
||||
|
color: white; |
||||
|
margin-left: 10px; |
||||
|
} |
||||
|
|
||||
|
.custom{ |
||||
|
width:48%; |
||||
|
border-radius:10px; |
||||
|
} |
||||
|
|
||||
|
.custom-input{ |
||||
|
padding: 0.375rem 0.75rem; |
||||
|
font-size: 1.08333333rem; |
||||
|
font-weight: 400; |
||||
|
line-height: 1.5; |
||||
|
color: #ffffff; |
||||
|
background-color: #353535; |
||||
|
background-clip: padding-box; |
||||
|
border: 1px solid #353535; |
||||
|
height:40px; |
||||
|
border-radius: 12px 0px 0px 12px; |
||||
|
} |
||||
|
|
||||
|
.custom-text{ |
||||
|
padding: 0.375rem 0.75rem; |
||||
|
font-size: 1.08333333rem; |
||||
|
font-weight: 400; |
||||
|
line-height: 1.5; |
||||
|
color: #ffffff; |
||||
|
background-color: #353535; |
||||
|
background-clip: padding-box; |
||||
|
border: 1px solid #353535; |
||||
|
resize:none; |
||||
|
border-radius: 12px; |
||||
|
} |
||||
|
|
||||
|
.alterButton{ |
||||
|
border-radius:10px; |
||||
|
width: 120px; |
||||
|
} |
||||
|
|
||||
|
#response::-webkit-scrollbar { |
||||
|
width: 5px; |
||||
|
} |
||||
|
|
||||
|
/* Track */ |
||||
|
#response::-webkit-scrollbar-track { |
||||
|
box-shadow: inset 0 0 5px grey; |
||||
|
border-radius: 10px; |
||||
|
} |
||||
|
|
||||
|
#response::-webkit-scrollbar-thumb { |
||||
|
background: white; |
||||
|
border-radius: 10px; |
||||
|
} |
||||
|
|
||||
|
#response::-webkit-scrollbar-thumb:hover { |
||||
|
background: #818281; |
||||
|
} |
||||
|
|
||||
|
.audio-record{ |
||||
|
display: flex; |
||||
|
justify-content: center |
||||
|
} |
||||
|
|
||||
|
.button-mic{ |
||||
|
border-radius: 13px; |
||||
|
height: 65px; |
||||
|
width: 55px; |
||||
|
} |
@ -0,0 +1,56 @@ |
|||||
|
odoo.define('chatgpt_odoo_connector.alternative_chatgpt', function (require) { |
||||
|
'use strict'; |
||||
|
var Widget = require('web.Widget'); |
||||
|
var rpc = require('web.rpc'); |
||||
|
/* Extending the widget */ |
||||
|
var AlternativeChatGPT = Widget.extend({ |
||||
|
template: 'alternativeChatGPT', |
||||
|
events: { |
||||
|
'click .alterButton': '_onClick', |
||||
|
'click .Replace': '_onClickReplace', |
||||
|
'click .Cancel': '_onClickCancel', |
||||
|
}, |
||||
|
init: function(parent, options) { |
||||
|
this._super(parent); |
||||
|
$(document).on('click', this._onOutSideClick.bind(this)); |
||||
|
}, |
||||
|
start: function() { |
||||
|
var self = this; |
||||
|
this._super.apply(this, arguments); |
||||
|
}, |
||||
|
/* Function for clicking the buttons for shortening, lengthening and rephrasing the content */ |
||||
|
_onClick: function(event){ |
||||
|
var dataValue = event.target.getAttribute('data-value'); |
||||
|
var message = this.__parentedParent.__parentedParent.el.innerText |
||||
|
this.response = rpc.query({ |
||||
|
model: 'open.chatgpt', |
||||
|
method: 'edit_content', |
||||
|
args: [message,dataValue], |
||||
|
}).then((response) => { |
||||
|
document.getElementById('response').value = response; |
||||
|
}) |
||||
|
}, |
||||
|
/* Function for inserting the created response into the description field */ |
||||
|
_onClickReplace: function(){ |
||||
|
var new_content = document.getElementById('response').value; |
||||
|
if (new_content.trim()){ |
||||
|
this.__parentedParent.__parentedParent.el.innerText = new_content |
||||
|
this._onClickCancel(); |
||||
|
} |
||||
|
}, |
||||
|
/* Function for closing the widget while clicking outside */ |
||||
|
_onOutSideClick: function(ev){ |
||||
|
var element = document.querySelector('.popChatGPTAlter'); |
||||
|
var element_button = document.getElementsByClassName('chatgpt'); |
||||
|
var isClickInsideElementButton = Array.from(element_button).some(button => button.contains(ev.target)); |
||||
|
if (element && !element.contains(ev.target) && !isClickInsideElementButton){ |
||||
|
this._onClickCancel(); |
||||
|
} |
||||
|
}, |
||||
|
/* Function for closing */ |
||||
|
_onClickCancel: function(){ |
||||
|
this.destroy() |
||||
|
} |
||||
|
}); |
||||
|
return AlternativeChatGPT; |
||||
|
}); |
@ -0,0 +1,21 @@ |
|||||
|
odoo.define('chatgpt_odoo_connector.custom_toolbar', function (require) { |
||||
|
'use strict'; |
||||
|
var web_editor = require('web_editor.toolbar'); |
||||
|
var Dialog = require('web.Dialog'); |
||||
|
var AlternativeChatGPT = require('chatgpt_odoo_connector.alternative_chatgpt'); |
||||
|
/* Adding a new button to the toolbar */ |
||||
|
var toolbar = web_editor.include({ |
||||
|
start: function () { |
||||
|
var res = this._super.apply(this, arguments); |
||||
|
this.$el.on('click', '#open-chatgpt', this._onButtonClick.bind(this)); |
||||
|
return res; |
||||
|
}, |
||||
|
/* Function for showing the widget while clicking the button. */ |
||||
|
_onButtonClick: function () { |
||||
|
if (!this.alternativeChatGPT || this.alternativeChatGPT.isDestroyed()) { |
||||
|
this.alternativeChatGPT = new AlternativeChatGPT(this); |
||||
|
} |
||||
|
this.alternativeChatGPT.appendTo(this.el.offsetParent); |
||||
|
}, |
||||
|
}); |
||||
|
}); |
@ -0,0 +1,93 @@ |
|||||
|
/** @odoo-module **/ |
||||
|
const { Component, useState, useExternalListener, xml } = owl; |
||||
|
import { registry } from "@web/core/registry"; |
||||
|
/* Extending the component and creating class OpenChatGPT */ |
||||
|
export class OpenChatGPT extends Component { |
||||
|
constructor() { |
||||
|
super(...arguments); |
||||
|
this.state = useState({ |
||||
|
message: '', |
||||
|
response: '' |
||||
|
}); |
||||
|
this.Send = this.Send.bind(this); |
||||
|
this.Cancel = this.Cancel.bind(this); |
||||
|
this.onWindowEnter = this.onWindowEnter.bind(this); |
||||
|
useExternalListener(window, "click", this.onWindowClick); |
||||
|
useExternalListener(window, "keydown", this.onWindowEnter); |
||||
|
} |
||||
|
/* Getting the response based on the message provided */ |
||||
|
async Send(ev){ |
||||
|
if (ev.state.message.trim()){ |
||||
|
this.state.response = await this.props.rpc.query({ |
||||
|
model: 'open.chatgpt', |
||||
|
method: 'get_response', |
||||
|
args: [ev.state.message], |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Function for inserting the response to the description field */ |
||||
|
insert(){ |
||||
|
var content = this.state.response |
||||
|
const lines = content.split('\n').filter(line => line.trim().length); |
||||
|
const fragment = document.createDocumentFragment(); |
||||
|
for (const line of lines) { |
||||
|
const block = document.createElement(line.startsWith('Title: ') ? 'h2' : 'p'); |
||||
|
block.innerText = line; |
||||
|
fragment.appendChild(block); |
||||
|
} |
||||
|
this.props.self.el.appendChild(fragment); |
||||
|
this.Cancel() |
||||
|
} |
||||
|
|
||||
|
/* Function for cancelling */ |
||||
|
Cancel(){ |
||||
|
var element = document.querySelector('.popChatGPT'); |
||||
|
element.remove(); |
||||
|
} |
||||
|
|
||||
|
/* Function for closing the widget while clicking outside */ |
||||
|
onWindowClick(ev) { |
||||
|
var element = document.querySelector('.popChatGPT'); |
||||
|
if (element && !element.contains(ev.target)){ |
||||
|
element.remove(); |
||||
|
} |
||||
|
} |
||||
|
/* Function for calling the function Send */ |
||||
|
onWindowEnter(ev){ |
||||
|
var element = document.querySelector('.popChatGPT'); |
||||
|
if (element && ev.key == 'Enter'){ |
||||
|
this.Send(this) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
OpenChatGPT.template = xml` |
||||
|
<div class="popChatGPT"> |
||||
|
<div style="display: flex; align-items: end;margin-top:-20px;"> |
||||
|
<img src="chatgpt_odoo_connector/static/src/Icons/icon.png" height="35px"/> |
||||
|
<div class="h2 heading">ChatGPT</div> |
||||
|
</div> |
||||
|
<hr/> |
||||
|
<div class="mb-3"> |
||||
|
<label for="message" class="form-label" style="color:white;">Message</label> |
||||
|
<div style="display: flex;"> |
||||
|
<input type="text" class="custom-input" id="message" placeholder="Enter message" |
||||
|
t-model="state.message"/> |
||||
|
<button class="btn btn-success" style="border-radius:0px 12px 12px 0px;" t-on-click="() => Send(this)"> |
||||
|
<i class="fa fa-paper-plane"></i> |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<label for="response" class="form-label" style="color:white;" t-if="state.response">Response</label> |
||||
|
<div t-if="state.response"> |
||||
|
<div class="mb-3"> |
||||
|
<textarea id="response" class="custom-text" rows="4" t-model="state.response"></textarea> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="display: flex;justify-content: space-around;"> |
||||
|
<button class="btn btn-primary custom" t-if="state.response" t-on-click="insert">Insert</button> |
||||
|
<button class="btn btn-secondary custom" t-on-click="Cancel">Cancel</button> |
||||
|
</div> |
||||
|
</div>`; |
||||
|
registry.category("actions").add("chatGPT", OpenChatGPT); |
@ -0,0 +1,128 @@ |
|||||
|
/** @odoo-module **/ |
||||
|
const { Component, useState, useRef, useExternalListener, xml } = owl; |
||||
|
import { registry } from "@web/core/registry"; |
||||
|
import { browser } from '@web/core/browser/browser'; |
||||
|
import {_t} from 'web.core'; |
||||
|
/* Extending the component and creating class recordAudio */ |
||||
|
export class recordAudio extends Component { |
||||
|
constructor() { |
||||
|
super(...arguments); |
||||
|
this.state = useState({ |
||||
|
startedRecording: '', |
||||
|
transcriptedText: '', |
||||
|
audioChunks: [], |
||||
|
}); |
||||
|
this.recordAudio = this.recordAudio.bind(this); |
||||
|
this.stopRecord = this.stopRecord.bind(this); |
||||
|
this.onWindowClick = this.onWindowClick.bind(this); |
||||
|
useExternalListener(window, "click", this.onWindowClick); |
||||
|
} |
||||
|
/* Function for recording audio and save the recording in a file. */ |
||||
|
async recordAudio(ev){ |
||||
|
this.state.startedRecording = true |
||||
|
this.state.audioChunks = []; |
||||
|
try { |
||||
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); |
||||
|
this.mediaRecorder = new MediaRecorder(stream); |
||||
|
this.mediaRecorder.ondataavailable = (e) => { |
||||
|
if (e.data.size > 0) { |
||||
|
this.state.audioChunks.push(e.data); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
this.mediaRecorder.onstop = async () => { |
||||
|
if (this.state.audioChunks.length > 0) { |
||||
|
const audioBlob = new Blob(this.state.audioChunks, { type: 'audio/wav' }); |
||||
|
const file = new File([audioBlob], 'recorded_audio.wav', { type: 'audio/wav' }); |
||||
|
const formData = new FormData(); |
||||
|
formData.append('file', file); |
||||
|
const response = await fetch('/upload_audio', { |
||||
|
method: 'POST', |
||||
|
body: formData, |
||||
|
}); |
||||
|
const { filePath } = await response.json(); |
||||
|
this.state.transcriptedText = await this.props.rpc.query({ |
||||
|
model: 'open.chatgpt', |
||||
|
method: 'convert_to_text', |
||||
|
args: [filePath], |
||||
|
}) |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
this.audioStream = stream; |
||||
|
this.mediaRecorder.start(); |
||||
|
} catch (error) { |
||||
|
this.props.self.displayNotification({ |
||||
|
title: _t('Warning'), |
||||
|
message: "Recording Error: Error accessing Microphone" |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
/* Function for stop audio recording */ |
||||
|
async stopRecord() { |
||||
|
this.state.startedRecording = false; |
||||
|
if (this.mediaRecorder && this.mediaRecorder.state !== 'inactive') { |
||||
|
this.mediaRecorder.stop(); |
||||
|
if (this.audioStream) { |
||||
|
this.audioStream.getTracks().forEach(track => track.stop()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Function for inserting the converted text from the audio file. */ |
||||
|
Insert(){ |
||||
|
var content = this.state.transcriptedText |
||||
|
const lines = content.split('\n').filter(line => line.trim().length); |
||||
|
const fragment = document.createDocumentFragment(); |
||||
|
for (const line of lines) { |
||||
|
const block = document.createElement(line.startsWith('Title: ') ? 'h2' : 'p'); |
||||
|
block.innerText = line; |
||||
|
fragment.appendChild(block); |
||||
|
} |
||||
|
this.props.self.el.appendChild(fragment); |
||||
|
this.Cancel() |
||||
|
} |
||||
|
|
||||
|
/* Function for cancelling it will remove the element popChatGPT*/ |
||||
|
Cancel(){ |
||||
|
var element = document.querySelector('.popChatGPT'); |
||||
|
element.remove(); |
||||
|
} |
||||
|
/* Function for closing the widget while clicking outside */ |
||||
|
onWindowClick(ev) { |
||||
|
var element = document.querySelector('.popChatGPT'); |
||||
|
if (element && !element.contains(ev.target)){ |
||||
|
this.Cancel() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
recordAudio.template = xml` |
||||
|
<div class="popChatGPT"> |
||||
|
<div style="display: flex; align-items: end;margin-top:-20px;"> |
||||
|
<img src="chatgpt_odoo_connector/static/src/Icons/icon.png" height="35px"/> |
||||
|
<div class="h2 heading">Speech-to-text</div> |
||||
|
</div> |
||||
|
<hr/> |
||||
|
<div class="mb-3 audio-record"> |
||||
|
<button class="btn btn-success button-mic" t-if="!state.startedRecording" t-on-click="() => recordAudio(this)"> |
||||
|
<i class="fa fa-microphone" style="font-size: 24px;color:black;"/> |
||||
|
</button> |
||||
|
<button class="btn btn-danger button-mic" t-if="state.startedRecording" style="border-radius:13px;" t-on-click="() => stopRecord(this)"> |
||||
|
<i class="fa fa-microphone-slash" style="font-size: 24px;color:black;"></i> |
||||
|
</button> |
||||
|
</div> |
||||
|
<label for="response" class="form-label" t-if="state.transcriptedText" |
||||
|
style="color:white;">Response</label> |
||||
|
<div t-if="state.transcriptedText"> |
||||
|
<div class="mb-3"> |
||||
|
<textarea id="response" class="custom-text" rows="4" t-model="state.transcriptedText"></textarea> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style="display: flex;justify-content: space-around;"> |
||||
|
<button class="btn btn-primary custom" t-if="state.transcriptedText" t-on-click="Insert">Insert</button> |
||||
|
<button class="btn btn-secondary custom" t-on-click="Cancel">Cancel</button> |
||||
|
</div> |
||||
|
</div>`; |
||||
|
registry.category("actions").add("recordAudio", recordAudio); |
@ -0,0 +1,62 @@ |
|||||
|
/** @odoo-module **/ |
||||
|
import Wysiwyg from 'web_editor.wysiwyg'; |
||||
|
import { browser } from '@web/core/browser/browser'; |
||||
|
import { _t } from 'web.core'; |
||||
|
var Dialog = require('web.Dialog'); |
||||
|
var core = require('web.core'); |
||||
|
var QWeb = core.qweb; |
||||
|
var rpc = require('web.rpc'); |
||||
|
import { OpenChatGPT } from "./open_chatgpt"; |
||||
|
import { recordAudio } from "./recordAudio"; |
||||
|
const { mount } = owl; |
||||
|
/* Appending new Category AI Tools, Chatgpt tool, and Speech-to-text tool in the powerbox options */ |
||||
|
Wysiwyg.include({ |
||||
|
init: function (parent, options) { |
||||
|
this._super.apply(this, arguments); |
||||
|
}, |
||||
|
/* Function for adding new category and tool */ |
||||
|
_getPowerboxOptions: function (){ |
||||
|
const options = this._super(); |
||||
|
const { commands, categories } = options; |
||||
|
const Category = { |
||||
|
name: _t('AI Tools'), |
||||
|
priority: 40 |
||||
|
}; |
||||
|
const itemSectionCommand = { |
||||
|
category: _t('AI Tools'), |
||||
|
name: _t('ChatGPT'), |
||||
|
priority: 40, |
||||
|
description: _t('Generate content with AI'), |
||||
|
fontawesome: 'fa-magic', |
||||
|
callback: this._openChatGPT.bind(this) |
||||
|
}; |
||||
|
const itemSpeechToAudio = { |
||||
|
category: _t('AI Tools'), |
||||
|
name: _t('Speech-To-Text'), |
||||
|
priority: 40, |
||||
|
description: _t('Speech to text'), |
||||
|
fontawesome: 'fa-microphone', |
||||
|
callback: this._recordVoice.bind(this) |
||||
|
}; |
||||
|
categories.push(Category); |
||||
|
commands.push(itemSectionCommand); |
||||
|
commands.push(itemSpeechToAudio); |
||||
|
return options; |
||||
|
}, |
||||
|
/* Function for mounting the element of chatgpt in the view */ |
||||
|
_openChatGPT: function () { |
||||
|
var element = $('.o_web_client')[0]; |
||||
|
if (element) { |
||||
|
const props = {rpc: rpc, self: this}; |
||||
|
mount(OpenChatGPT, element, {props: props}); |
||||
|
} |
||||
|
}, |
||||
|
/* Function for mounting the element speech-to-text in the view */ |
||||
|
_recordVoice: function () { |
||||
|
var element = $('.o_web_client')[0]; |
||||
|
if (element) { |
||||
|
const props = {rpc: rpc, self: this}; |
||||
|
mount(recordAudio, element, {props: props}); |
||||
|
} |
||||
|
}, |
||||
|
}); |
@ -0,0 +1,33 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<templates id="template" xml:space="preserve"> |
||||
|
<!-- Template for alternative chatgpt --> |
||||
|
<t t-name="alternativeChatGPT" id="chatGPTdialog"> |
||||
|
<div class="popChatGPTAlter"> |
||||
|
<div style="display: flex; align-items: end;margin-top:-20px;"> |
||||
|
<img src="chatgpt_odoo_connector/static/src/Icons/icon.png" height="35px"/> |
||||
|
<div class="h2 heading">ChatGPT</div> |
||||
|
</div> |
||||
|
<hr/> |
||||
|
<div style="display:flex;justify-content: space-evenly;"> |
||||
|
<div> |
||||
|
<button class="alterButton btn btn-outline-light" data-value="shorten">Shorten</button> |
||||
|
</div> |
||||
|
<div> |
||||
|
<button class="alterButton btn btn-outline-light" data-value="lengthen">Lengthen</button> |
||||
|
</div> |
||||
|
<div> |
||||
|
<button class="alterButton btn btn-outline-light" data-value="rephrase">Rephrase</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
<br/> |
||||
|
<div class="mb-3"> |
||||
|
<label for="response" style="color:white;" class="form-label">Response</label> |
||||
|
<textarea class="custom-text" id="response" rows="4"/> |
||||
|
</div> |
||||
|
<div style="display: flex;justify-content: space-around;"> |
||||
|
<button class="Replace custom btn btn-primary">Replace</button> |
||||
|
<button class="Cancel custom btn btn-secondary">Cancel</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</t> |
||||
|
</templates> |
@ -0,0 +1,13 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<templates xml:space="preserve"> |
||||
|
<!-- Adding new icon in the web_editor toolbar--> |
||||
|
<t t-name="toolbarCustom" t-inherit="web_editor.toolbar" t-inherit-mode="extension" owl="1"> |
||||
|
<xpath expr="//div[@id='link']" position="after"> |
||||
|
<div id="chatgpt" class="btn-group"> |
||||
|
<div id="open-chatgpt" title="Generate or transform content with AI" class="btn editor-ignore chatgpt"> |
||||
|
<span class="fa fa-magic fa-fw"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</xpath> |
||||
|
</t> |
||||
|
</templates> |
@ -0,0 +1,15 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<odoo> |
||||
|
<!-- Inheriting product_product view --> |
||||
|
<record id="product_normal_form_view" model="ir.ui.view"> |
||||
|
<field name="name">product.product.view.form</field> |
||||
|
<field name="model">product.product</field> |
||||
|
<field name="inherit_id" ref="product.product_normal_form_view"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//field[@name='product_tag_ids']" position="after"> |
||||
|
<field name="is_create_image"/> |
||||
|
<field name="is_update_image"/> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,16 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<odoo> |
||||
|
<!-- Inheriting product template view --> |
||||
|
<record id="product_template_only_form_view" model="ir.ui.view"> |
||||
|
<field name="name">product.template.view.form</field> |
||||
|
<field name="model">product.template</field> |
||||
|
<field name="inherit_id" ref="product.product_template_only_form_view"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//group[@name='group_standard_price']" position="inside"> |
||||
|
<field name="is_create_image"/> |
||||
|
<field name="is_update_image"/> |
||||
|
</xpath> |
||||
|
|
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |
@ -0,0 +1,26 @@ |
|||||
|
<?xml version="1.0"?> |
||||
|
<odoo> |
||||
|
<!-- Inheriting res config settings view--> |
||||
|
<record id="res_config_settings_view_form" model="ir.ui.view"> |
||||
|
<field name="name"> |
||||
|
res.config.settings.view.form.inherit.odoo.ai |
||||
|
</field> |
||||
|
<field name="model">res.config.settings</field> |
||||
|
<field name="priority" eval="20"/> |
||||
|
<field name="inherit_id" ref="base.res_config_settings_view_form"/> |
||||
|
<field name="arch" type="xml"> |
||||
|
<xpath expr="//div[@name='integration']" position="inside"> |
||||
|
<div class="col-12 col-lg-6 o_setting_box"> |
||||
|
<div class="o_setting_left_pane" id="chatgpt"> |
||||
|
</div> |
||||
|
<div class="o_setting_right_pane"> |
||||
|
<label string="ChatGPT" for="api_key"/> |
||||
|
<div class="text-muted"> |
||||
|
<field name="api_key"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</xpath> |
||||
|
</field> |
||||
|
</record> |
||||
|
</odoo> |