Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions ai_chatgpt_oauth/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

================
AI ChatGPT OAuth
================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:69a4694add2c51f0db97b7175cdea04fd24e717eda5af03caf14adc35867e5c3
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github
:target: https://github.com/OCA/server-tools/tree/19.0/ai_chatgpt_oauth
:alt: OCA/server-tools
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/server-tools-19-0/server-tools-19-0-ai_chatgpt_oauth
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/server-tools&target_branch=19.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module separates **AI chat and AI Agent authentication** from the
credentials used by supporting OpenAI API services in Odoo Enterprise
AI.

It allows organizations to route AI conversational queries, chat bots,
and AI fields through an eligible **ChatGPT subscription** (Plus, Pro,
Team, Enterprise) via an OAuth 2.0 Device Code grant flow, eliminating
per-token generation costs for interactive chat while preserving the
standard OpenAI developer API key for knowledge embeddings, Whisper
voice transcription, and realtime sessions.

Supported configurations:

- **OpenAI API key only**: Standard Odoo setup (pay-per-token API for
chat, embeddings, and voice).
- **ChatGPT subscription only**: ChatGPT subscription for chat and
agents. Knowledge embeddings and voice remain unconfigured.
- **Mixed / Hybrid**: ChatGPT subscription for chat and agents; OpenAI
developer API key for embeddings and voice.

**Table of contents**

.. contents::
:local:

Configuration
=============

To configure this module:

1. Navigate to **AI > Configuration > Settings** (or **General Settings
> AI Providers**) as a Settings Administrator
(``base.group_system``).
2. Under **Use your own ChatGPT / OpenAI account**, choose **ChatGPT
Subscription (OAuth)** under Connection Type.
3. Click **Connect ChatGPT Subscription** to launch the device
authentication wizard.
4. Follow the prompt to visit ``https://auth.openai.com/codex/device``
and input the provided one-time code to authorize the Odoo instance.
5. Return to Odoo and click **Verify & Connect**.
6. (Optional) In the same section, expand the optional API key section
to provide a developer API key if knowledge base embeddings (RAG) or
voice transcription are also needed.
7. Use the **Sync Models** and **Test Connection** buttons to verify
credentials and synchronize available models.

Usage
=====

Once configured:

1. Open any **AI Agent** record under **AI > Agents**.
2. Select any active ChatGPT model directly from the **LLM Model**
dropdown (e.g. ``GPT-5.6 Luna``, ``GPT-5.6 Terra``, ``GPT-5.5``,
``GPT-5.4``, etc.).
3. Conversations initiated with the AI agent or chat bots will
automatically stream responses through the authorized ChatGPT
subscription without per-token charges.
4. Tokens are automatically refreshed every 2 hours via a background
cron job (``ir.cron``), with concurrency protection across
multi-worker environments.

Managing & Adding New Models
----------------------------

When OpenAI releases new models or deprecates older versions:

1. Navigate to **AI > Configuration > Settings**.
2. Under the connected ChatGPT section, click **Manage Models**.
3. To add a newly released OpenAI model (e.g., ``GPT-5.7 Pro`` with
technical code ``gpt-5.7-pro``), click **New** and enter the display
name and technical model ID.
4. To deactivate an old or deprecated model, simply toggle its
**Active** switch off.
5. The model selection on all AI Agents will update immediately across
Odoo.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/server-tools/issues/new?body=module:%20ai_chatgpt_oauth%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Mayur Bechara

Contributors
------------

- Mayur Bechara becharamayur49@gmail.com
- Odoo Community Association (OCA) https://odoo-community.org

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

.. |maintainer-becharamayur| image:: https://github.com/becharamayur.png?size=40px
:target: https://github.com/becharamayur
:alt: becharamayur

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-becharamayur|

This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/19.0/ai_chatgpt_oauth>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
5 changes: 5 additions & 0 deletions ai_chatgpt_oauth/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2026 Mayur Bechara <becharamayur49@gmail.com>
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).

from . import models
from . import wizard
25 changes: 25 additions & 0 deletions ai_chatgpt_oauth/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright 2026 Mayur Bechara <becharamayur49@gmail.com>
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).

{
"name": "AI ChatGPT OAuth",
"summary": "Use ChatGPT subscription authentication for Odoo AI chat with OpenAI API fallback for supporting services",
"version": "19.0.1.0.0",
"category": "Productivity/Artificial Intelligence",
"author": "Mayur Bechara, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/server-tools",
"license": "LGPL-3",
"maintainers": ["becharamayur"],
"depends": ["base", "ai"],
"data": [
"security/ir.model.access.csv",
"data/ir_cron.xml",
"data/ai_chatgpt_model_data.xml",
"views/ai_chatgpt_model_views.xml",
"wizard/chatgpt_oauth_wizard_views.xml",
"views/res_config_settings_views.xml",
],
"installable": True,
"application": False,
"auto_install": False,
}
46 changes: 46 additions & 0 deletions ai_chatgpt_oauth/data/ai_chatgpt_model_data.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="chatgpt_model_gpt56_sol" model="ai.chatgpt.model">
<field name="name">GPT-5.6 Sol</field>
<field name="code">gpt-5.6-sol</field>
<field name="sequence">10</field>
<field name="description">Flagship frontier reasoning model. Designed for complex multi-step reasoning, deep logic, advanced agentic orchestration, and long-horizon tasks (supports 1M+ token context window).</field>
</record>

<record id="chatgpt_model_gpt56_terra" model="ai.chatgpt.model">
<field name="name">GPT-5.6 Terra</field>
<field name="code">gpt-5.6-terra</field>
<field name="sequence">20</field>
<field name="description">Balanced workhorse model for interactive workflows, business operations, coding, and day-to-day AI agent tasks with optimized speed and cost efficiency.</field>
</record>

<record id="chatgpt_model_gpt56_luna" model="ai.chatgpt.model">
<field name="name">GPT-5.6 Luna</field>
<field name="code">gpt-5.6-luna</field>
<field name="sequence">30</field>
<field name="description">High-speed, low-latency model optimized for real-time conversational chat, quick summaries, document classification, and high-frequency tasks.</field>
</record>

<record id="chatgpt_model_gpt55" model="ai.chatgpt.model">
<field name="name">GPT-5.5</field>
<field name="code">gpt-5.5</field>
<field name="sequence">40</field>
<field name="description">High-capability general reasoning model with strong agentic tool calling and deep contextual comprehension.</field>
</record>

<record id="chatgpt_model_gpt54" model="ai.chatgpt.model">
<field name="name">GPT-5.4</field>
<field name="code">gpt-5.4</field>
<field name="sequence">50</field>
<field name="description">Versatile foundation model for structured business logic, text analysis, and multi-turn dialogues.</field>
</record>

<record id="chatgpt_model_gpt54_mini" model="ai.chatgpt.model">
<field name="name">GPT-5.4 Mini</field>
<field name="code">gpt-5.4-mini</field>
<field name="sequence">60</field>
<field name="description">Compact high-throughput model designed for lightweight queries, rapid responses, and lower resource consumption.</field>
</record>
</data>
</odoo>
15 changes: 15 additions & 0 deletions ai_chatgpt_oauth/data/ir_cron.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="ir_cron_refresh_chatgpt_oauth_tokens" model="ir.cron">
<field name="name">AI: Refresh ChatGPT OAuth Tokens</field>
<field name="model_id" ref="model_ai_chatgpt_oauth"/>
<field name="state">code</field>
<field name="code">model.get_valid_access_token()</field>
<field name="user_id" ref="base.user_root"/>
<field name="interval_number">2</field>
<field name="interval_type">hours</field>
<field name="active">True</field>
</record>
</data>
</odoo>
9 changes: 9 additions & 0 deletions ai_chatgpt_oauth/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright 2026 Mayur Bechara <becharamayur49@gmail.com>
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).

from . import chatgpt_model
from . import chatgpt_models
from . import chatgpt_oauth
from . import res_config_settings
from . import ai_agent
from . import llm_patch
22 changes: 22 additions & 0 deletions ai_chatgpt_oauth/models/ai_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2026 Mayur Bechara <becharamayur49@gmail.com>
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).

from odoo import api, models

from .chatgpt_models import get_chatgpt_models


class AIAgent(models.Model):
_inherit = "ai.agent"

@api.model
def _get_llm_model_selection(self):
selection = super()._get_llm_model_selection()
existing_keys = {item[0] for item in selection}

available_chatgpt_models = get_chatgpt_models(self.env)
for model_key, model_label in available_chatgpt_models:
if model_key not in existing_keys:
selection.append((model_key, model_label))

return selection
65 changes: 65 additions & 0 deletions ai_chatgpt_oauth/models/chatgpt_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Copyright 2026 Mayur Bechara <becharamayur49@gmail.com>
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).

from odoo import api, fields, models


class AIChatGPTModel(models.Model):
_name = "ai.chatgpt.model"
_description = "ChatGPT Subscription Supported Model"
_order = "sequence, id"

name = fields.Char(
string="Model Display Name",
required=True,
help="User-friendly name displayed in AI Agent dropdown (e.g., 'GPT-5.6 Luna').",
)
code = fields.Char(
string="Technical Model ID",
required=True,
index=True,
help="Technical model slug sent to OpenAI Codex endpoint (e.g., 'gpt-5.6-luna').",
)
sequence = fields.Integer(string="Sequence", default=10)
active = fields.Boolean(
string="Active",
default=True,
help="Uncheck to hide this model from AI Agent selection when deprecated by OpenAI.",
)
description = fields.Text(
string="Notes",
help="Optional notes regarding model capabilities, tiers, or context window.",
)

_code_unique = models.Constraint("UNIQUE (code)", "The technical model ID must be unique!")

@api.model_create_multi
def create(self, vals_list):
records = super().create(vals_list)
self._refresh_provider_cache()
return records

def write(self, vals):
res = super().write(vals)
self._refresh_provider_cache()
return res

def unlink(self):
res = super().unlink()
self._refresh_provider_cache()
return res

@api.model
def _refresh_provider_cache(self):
"""Update Odoo's in-memory LLM providers registry when models change."""
from odoo.addons.ai.utils import llm_providers
active_models = self.search([("active", "=", True)], order="sequence, id")
for p_idx, provider in enumerate(llm_providers.PROVIDERS):
if provider.name == "openai":
existing_keys = {m[0] for m in provider.llms}
new_llms = list(provider.llms)
for m in active_models:
if m.code not in existing_keys:
new_llms.append((m.code, m.name))
existing_keys.add(m.code)
llm_providers.PROVIDERS[p_idx] = provider._replace(llms=new_llms)
22 changes: 22 additions & 0 deletions ai_chatgpt_oauth/models/chatgpt_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2026 Mayur Bechara <becharamayur49@gmail.com>
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0).


def get_chatgpt_models(env):
"""Retrieve active ChatGPT models dynamically from the database."""
try:
model_records = env["ai.chatgpt.model"].sudo().search(
[("active", "=", True)],
order="sequence, id",
)
if model_records:
return [(m.code, m.name) for m in model_records]
except Exception:
pass
return []


def get_chatgpt_model_ids(env):
"""Return a set of valid active ChatGPT model identifiers."""
models = get_chatgpt_models(env)
return {model_id for model_id, _label in models}
Loading
Loading