diff --git a/chatgpt_bot/__init__.py b/chatgpt_bot/__init__.py
new file mode 100644
index 0000000..19240f4
--- /dev/null
+++ b/chatgpt_bot/__init__.py
@@ -0,0 +1,2 @@
+from . import controllers
+from . import models
\ No newline at end of file
diff --git a/chatgpt_bot/__manifest__.py b/chatgpt_bot/__manifest__.py
new file mode 100644
index 0000000..ebd16d2
--- /dev/null
+++ b/chatgpt_bot/__manifest__.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+{
+ 'name': "OdooBot ChatGPT AI integration",
+
+ 'summary': """
+ This module integrates the response from ChatGPT into Odoo's built-in chatbot, OdooBot.
+ """,
+
+ 'description': """
+ This module allows users to leverage the advanced natural language processing capabilities
+ of ChatGPT within Odoo's user-friendly interface. By integrating ChatGPT's responses into OdooBot,
+ users can easily access the powerful language model's insights and capabilities without having to
+ navigate away from the Odoo platform. This integration can be used to enhance the functionality of
+ OdooBot, providing more accurate and detailed responses to user queries and improving overall user experience.
+ """,
+
+ 'author': "FL1 sro",
+ 'website': "https://fl1.cz",
+ "images": ["static/description/banner.png", "static/description/gif_chat.gif"],
+ # Categories can be used to filter modules in modules listing
+ # Check https://github.com/odoo/odoo/blob/18.0/odoo/addons/base/data/ir_module_category_data.xml
+ # for the full list
+ 'category': 'Odex25-base',
+ 'version': '18.0.0.1',
+ 'license': 'AGPL-3',
+
+ # any module necessary for this one to work correctly
+ 'depends': ['base', 'mail', 'queue_job'],
+'installable': True,
+ 'application': True, # <-- Important if you want it to appear in "Apps"
+ 'auto_install': False,
+ # always loaded
+ 'data': [
+ # 'security/ir.model.access.csv',
+ 'views/res_config_settings.xml',
+
+ ],
+ # only loaded in demonstration mode
+ 'demo': [
+ 'demo/demo.xml',
+ ],
+ "external_dependencies": {
+ "python": ["openai"]
+ },
+ 'price': 0.00,
+ 'currency': 'EUR',
+
+}
\ No newline at end of file
diff --git a/chatgpt_bot/controllers/__init__.py b/chatgpt_bot/controllers/__init__.py
new file mode 100644
index 0000000..15c7016
--- /dev/null
+++ b/chatgpt_bot/controllers/__init__.py
@@ -0,0 +1,2 @@
+
+from . import controllers
\ No newline at end of file
diff --git a/chatgpt_bot/controllers/controllers.py b/chatgpt_bot/controllers/controllers.py
new file mode 100644
index 0000000..e69de29
diff --git a/chatgpt_bot/demo/demo.xml b/chatgpt_bot/demo/demo.xml
new file mode 100644
index 0000000..17ad66e
--- /dev/null
+++ b/chatgpt_bot/demo/demo.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/chatgpt_bot/images/gif_chat.gif b/chatgpt_bot/images/gif_chat.gif
new file mode 100644
index 0000000..2403faf
Binary files /dev/null and b/chatgpt_bot/images/gif_chat.gif differ
diff --git a/chatgpt_bot/images/image1.png b/chatgpt_bot/images/image1.png
new file mode 100644
index 0000000..da579e6
Binary files /dev/null and b/chatgpt_bot/images/image1.png differ
diff --git a/chatgpt_bot/images/image2.png b/chatgpt_bot/images/image2.png
new file mode 100644
index 0000000..bcca92e
Binary files /dev/null and b/chatgpt_bot/images/image2.png differ
diff --git a/chatgpt_bot/images/image3.png b/chatgpt_bot/images/image3.png
new file mode 100644
index 0000000..953294d
Binary files /dev/null and b/chatgpt_bot/images/image3.png differ
diff --git a/chatgpt_bot/images/image4.png b/chatgpt_bot/images/image4.png
new file mode 100644
index 0000000..7ab9256
Binary files /dev/null and b/chatgpt_bot/images/image4.png differ
diff --git a/chatgpt_bot/models/__init__.py b/chatgpt_bot/models/__init__.py
new file mode 100644
index 0000000..2c78fad
--- /dev/null
+++ b/chatgpt_bot/models/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+
+from . import res_config_setting
+from . import mail_bot
+from . import res_users
\ No newline at end of file
diff --git a/chatgpt_bot/models/__pycache__/__init__.cpython-311.pyc b/chatgpt_bot/models/__pycache__/__init__.cpython-311.pyc
new file mode 100644
index 0000000..2a95cc7
Binary files /dev/null and b/chatgpt_bot/models/__pycache__/__init__.cpython-311.pyc differ
diff --git a/chatgpt_bot/models/__pycache__/mail_bot.cpython-311.pyc b/chatgpt_bot/models/__pycache__/mail_bot.cpython-311.pyc
new file mode 100644
index 0000000..b1b84c2
Binary files /dev/null and b/chatgpt_bot/models/__pycache__/mail_bot.cpython-311.pyc differ
diff --git a/chatgpt_bot/models/__pycache__/res_config_setting.cpython-311.pyc b/chatgpt_bot/models/__pycache__/res_config_setting.cpython-311.pyc
new file mode 100644
index 0000000..cc133ca
Binary files /dev/null and b/chatgpt_bot/models/__pycache__/res_config_setting.cpython-311.pyc differ
diff --git a/chatgpt_bot/models/__pycache__/res_users.cpython-311.pyc b/chatgpt_bot/models/__pycache__/res_users.cpython-311.pyc
new file mode 100644
index 0000000..fe1924f
Binary files /dev/null and b/chatgpt_bot/models/__pycache__/res_users.cpython-311.pyc differ
diff --git a/chatgpt_bot/models/mail_bot.py b/chatgpt_bot/models/mail_bot.py
new file mode 100644
index 0000000..7c9279b
--- /dev/null
+++ b/chatgpt_bot/models/mail_bot.py
@@ -0,0 +1,195 @@
+# -*- coding: utf-8 -*-
+from odoo import api, models, _
+from odoo.exceptions import UserError, ValidationError
+from bs4 import BeautifulSoup as BS
+
+# Note: Use the modern OpenAI client
+# pip install openai
+try:
+ from openai import OpenAI
+except Exception: # pragma: no cover
+ OpenAI = None
+
+
+class ChatGptBot(models.AbstractModel):
+ _inherit = 'mail.bot'
+ _description = 'ChatGPT OdooBot'
+
+ #################################################################################################
+ # ORM FUNCTIONS #
+ #################################################################################################
+
+ def create_content(self):
+ """
+ Generates HTML content and SEO JSON via OpenAI and writes back to fields if present.
+ Expected optional fields on the record:
+ - text_chatgpt (input prompt)
+ - content (HTML output)
+ - website_meta_title / website_meta_description / website_meta_keywords (SEO)
+ - is_publish_now / is_published / is_elaborate
+ This method is defensive: if fields do not exist on the record, it skips setting them.
+ """
+ # Ensure running on a single record or abstractly use 'self' as context holder
+ record = self
+
+ # Validate input field existence
+ text = getattr(record, 'text_chatgpt', None)
+ if not text:
+ raise UserError(_("Please provide a prompt (text_chatgpt) before generating content."))
+
+ api_key = self.env['ir.config_parameter'].sudo().get_param('chatgpt_api_key')
+ if not api_key:
+ raise UserError(_("No OpenAI API key configured. Set it in Settings → ChatGPT OdooBot."))
+
+ if OpenAI is None:
+ raise UserError(_("The OpenAI Python package is not installed. Please install 'openai'."))
+
+ # Define an example JSON schema for SEO guidance
+ ex_json = {
+ "title": "Sample Title",
+ "description": "Short description (max 160 characters)",
+ "keywords": "keyword1, keyword2, keyword3"
+ }
+
+ client = OpenAI(api_key=api_key)
+
+ # Prompt instructs the model to output: 1) an HTML
...
, then 2) a pure JSON block
+ system_msg = "You are a helpful assistant that writes clean HTML and valid JSON."
+ user_msg = (
+ f"{text}\n\n"
+ "Output requirements:\n"
+ "1) First, return an HTML block wrapped strictly between and
with headings, paragraphs, and links.\n"
+ "2) Immediately after the closing , return ONLY a valid JSON object (no backticks, no labels)\n"
+ f"matching this schema and rules (description max 160 chars): {ex_json}\n"
+ )
+
+ try:
+ resp = client.chat.completions.create(
+ model="gpt-3.5-turbo",
+ messages=[
+ {"role": "system", "content": system_msg},
+ {"role": "user", "content": user_msg},
+ ],
+ max_tokens=1200,
+ temperature=0.7,
+ )
+ full = resp.choices[0].message.content or ""
+ except Exception as e:
+ raise UserError(_("OpenAI request failed: %s") % str(e))
+
+ # Split HTML and JSON by the first
+ html_part, json_part = "", ""
+ if "" in full:
+ html_part = full.split("", 1)[0] + ""
+ json_part = full.split("", 1)[1].strip()
+
+ # Parse SEO JSON if present
+ title = descr = kw = None
+ if json_part:
+ import json
+ try:
+ seo = json.loads(json_part)
+ title = seo.get("title")
+ descr = seo.get("description")
+ kw = seo.get("keywords")
+ except Exception:
+ # We don't hard-fail if JSON is malformed; raise a friendly error
+ raise ValidationError(_("The SEO JSON response is not valid JSON."))
+
+ # Assign fields defensively if they exist on the record
+ def safe_set(rec, field, value):
+ if hasattr(rec, field):
+ try:
+ setattr(rec, field, value)
+ except Exception:
+ pass
+
+ safe_set(record, 'content', html_part or "")
+ if title:
+ safe_set(record, 'website_meta_title', title)
+ if descr:
+ safe_set(record, 'website_meta_description', descr)
+ if kw:
+ safe_set(record, 'website_meta_keywords', kw)
+
+ # Handle publish flags if the model uses them
+ is_publish_now = getattr(record, 'is_publish_now', False)
+ if is_publish_now and hasattr(record, 'is_published'):
+ safe_set(record, 'is_published', True)
+ elif hasattr(record, 'is_published'):
+ safe_set(record, 'is_published', False)
+
+ safe_set(record, 'is_elaborate', True)
+
+ return True
+
+ #################################################################################################
+ # CUSTOM FUNCTIONS #
+ #################################################################################################
+
+ def _get_answer(self, record, body, values, command=None):
+ """
+ Odoo 18-compatible signature. Adds #enable / #disable and routes to ChatGPT if enabled.
+ """
+ res = super()._get_answer(record, body, values, command=command)
+
+ # Simple toggles
+ if body.strip().lower() == "#enable":
+ self.env.user.odoobot_state = 'chatgpt'
+ return _("ChatGPT enabled")
+ if body.strip().lower() == "#disable":
+ self.env.user.odoobot_state = 'disabled'
+ return _("ChatGPT disabled")
+
+ # Build a short context from last messages (plaintext only)
+ channel = self.env['mail.channel'].browse(record.id)
+ last_ids = channel.message_ids.ids
+ messages = self.env['mail.message'].search([('id', 'in', last_ids)], order='id desc', limit=2).mapped('body')
+ old_conv = ""
+ for msg in messages:
+ if msg:
+ old_conv += BS(msg, 'html.parser').get_text() + "\n"
+
+ # Route to ChatGPT if enabled
+ if self.env.user.odoobot_state == 'chatgpt':
+ return self._chatgpt_reply(record, body, old_conv)
+ return res
+
+ def _chatgpt_reply(self, record, body, context_text=""):
+ api_key = self.env['ir.config_parameter'].sudo().get_param('chatgpt_api_key')
+ if not api_key:
+ raise UserError(_("No OpenAI API key configured. Set it in Settings → ChatGPT OdooBot."))
+
+ if OpenAI is None:
+ raise UserError(_("The OpenAI Python package is not installed. Please install 'openai'."))
+
+ client = OpenAI(api_key=api_key)
+
+ try:
+ messages = []
+ if context_text:
+ messages.append({"role": "system", "content": f"Conversation context:\n{context_text.strip()}"})
+ messages.append({"role": "user", "content": body})
+
+ resp = client.chat.completions.create(
+ model="gpt-3.5-turbo",
+ messages=messages,
+ max_tokens=800,
+ temperature=0.7,
+ )
+ reply = resp.choices[0].message.content or ""
+ except Exception as e:
+ raise UserError(_("OpenAI request failed: %s") % str(e))
+
+ gpt_html = "OpenAI: " + reply
+
+ author_id = self.env.ref("base.partner_root").id
+ subtype_id = self.env.ref("mail.mt_comment").id
+
+ self.env['mail.channel'].browse(record.id).message_post(
+ body=gpt_html,
+ message_type='comment',
+ subtype_id=subtype_id,
+ author_id=author_id,
+ )
+ return gpt_html
diff --git a/chatgpt_bot/models/res_config_setting.py b/chatgpt_bot/models/res_config_setting.py
new file mode 100644
index 0000000..9ec7ac9
--- /dev/null
+++ b/chatgpt_bot/models/res_config_setting.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models, fields
+
+class ResConfigSettings(models.TransientModel):
+ _inherit = 'res.config.settings'
+
+ apikey = fields.Char(
+ string="API Key",
+ config_parameter="chatgpt_blog.apikey"
+ )
diff --git a/chatgpt_bot/models/res_users.py b/chatgpt_bot/models/res_users.py
new file mode 100644
index 0000000..739266c
--- /dev/null
+++ b/chatgpt_bot/models/res_users.py
@@ -0,0 +1,10 @@
+from odoo import api, fields, models, _
+
+
+class ResUsers(models.Model):
+ _inherit = 'res.users'
+
+ odoobot_state = fields.Selection(
+ selection_add=[('chatgpt', 'ChatGPT')],
+
+ )
\ No newline at end of file
diff --git a/chatgpt_bot/security/ir.model.access.csv b/chatgpt_bot/security/ir.model.access.csv
new file mode 100644
index 0000000..37ce15d
--- /dev/null
+++ b/chatgpt_bot/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_chatgpt_blog_chatgpt_blog,chatgpt_blog.chatgpt_blog,model_chatgpt_blog_chatgpt_blog,base.group_user,1,1,1,1
\ No newline at end of file
diff --git a/chatgpt_bot/static/description/banner.png b/chatgpt_bot/static/description/banner.png
new file mode 100644
index 0000000..d6ff33f
Binary files /dev/null and b/chatgpt_bot/static/description/banner.png differ
diff --git a/chatgpt_bot/static/description/icon.png b/chatgpt_bot/static/description/icon.png
new file mode 100644
index 0000000..fe52f1f
Binary files /dev/null and b/chatgpt_bot/static/description/icon.png differ
diff --git a/chatgpt_bot/static/description/images/banner.png b/chatgpt_bot/static/description/images/banner.png
new file mode 100644
index 0000000..5799230
Binary files /dev/null and b/chatgpt_bot/static/description/images/banner.png differ
diff --git a/chatgpt_bot/static/description/images/gif_chat.gif b/chatgpt_bot/static/description/images/gif_chat.gif
new file mode 100644
index 0000000..2403faf
Binary files /dev/null and b/chatgpt_bot/static/description/images/gif_chat.gif differ
diff --git a/chatgpt_bot/static/description/images/image1.png b/chatgpt_bot/static/description/images/image1.png
new file mode 100644
index 0000000..da579e6
Binary files /dev/null and b/chatgpt_bot/static/description/images/image1.png differ
diff --git a/chatgpt_bot/static/description/images/image2.png b/chatgpt_bot/static/description/images/image2.png
new file mode 100644
index 0000000..bcca92e
Binary files /dev/null and b/chatgpt_bot/static/description/images/image2.png differ
diff --git a/chatgpt_bot/static/description/images/image3.png b/chatgpt_bot/static/description/images/image3.png
new file mode 100644
index 0000000..953294d
Binary files /dev/null and b/chatgpt_bot/static/description/images/image3.png differ
diff --git a/chatgpt_bot/static/description/images/image4.png b/chatgpt_bot/static/description/images/image4.png
new file mode 100644
index 0000000..7ab9256
Binary files /dev/null and b/chatgpt_bot/static/description/images/image4.png differ
diff --git a/chatgpt_bot/static/description/images/main_screenshot.png b/chatgpt_bot/static/description/images/main_screenshot.png
new file mode 100644
index 0000000..8a5d3f3
Binary files /dev/null and b/chatgpt_bot/static/description/images/main_screenshot.png differ
diff --git a/chatgpt_bot/static/description/index.html b/chatgpt_bot/static/description/index.html
new file mode 100644
index 0000000..7c77196
--- /dev/null
+++ b/chatgpt_bot/static/description/index.html
@@ -0,0 +1,449 @@
+
+
+
+
+
+
+README.rst
+
+
+
+
+
+
+
+
OpenAI ChatGPT Odoo Module
+

+
+- This Odoo module allows for seamless integration with the OpenAI ChatGPT API,
+- providing advanced natural language processing capabilities within the Odoo platform.
+With this module, users can leverage the power of ChatGPT to generate human-like text,
+perform language translation, and more.
+It utilizes API calls to communicate with the OpenAI service,
+making it easy to set up and use.
+
+
Table of contents
+
+
+
+
Bugfix
+
+- fix error when no api key is set
+
+
+
+
Usage
+
To use this module, you need to:
+
+- require queque_job from queue_job.
+- After the installation to this module, you must change the configuration and add this on the configuration file:
+- server_wide_modules = base,web,queue_job add queue_job
+- Then restart the server and see a logs file in server console.
+
+

+
This module is required for not blocking the server when the API is called.
+
+
+
Configuration users
+
inside the preferences of the user you can set the chatGPT bot as default bot.
+

+
You can activate or deactivate the chatGPT bot for each user.
+You can activate or deactivate the chatGPT directly in the chat window.
+
You can type: #enable or #disable
+

+
+
+
Example
+

+

+
+
+
Bug Tracker
+
Bugs are tracked on GitHub Issues.
+In case of trouble, please check there if your issue has already been reported.
+If you spotted it first, help us smashing it by providing a detailed and welcomed
+
Do not contact contributors directly about support or help with technical issues.
+
+
+
Credits
+
+
+
+
Maintainers
+
This module is maintained by the FL1.
+

+
+
+
+
+
diff --git a/chatgpt_bot/views/res_config_settings.xml b/chatgpt_bot/views/res_config_settings.xml
new file mode 100644
index 0000000..375cbb6
--- /dev/null
+++ b/chatgpt_bot/views/res_config_settings.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+ res.config.settings.view.form.inherit.chatgpt
+ res.config.settings
+
+
+
+
+
+
+
+
+
+
+
+
+ ChatGPT Settings
+ res.config.settings
+ form
+ current
+ {'module': 'chatgpt_blog'}
+
+
+
+
diff --git a/queue b/queue
new file mode 160000
index 0000000..edc21e4
--- /dev/null
+++ b/queue
@@ -0,0 +1 @@
+Subproject commit edc21e4c4ef11a1ef746ca5ac641e9227602a35d