Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
b56630f
[ADD] ai_oca_bridge
etobella Jun 7, 2025
717af48
[UPD] Update ai_oca_bridge.pot
Jun 9, 2025
989a795
[BOT] post-merge updates
OCA-git-bot Jun 9, 2025
fc847de
Added translation using Weblate (Italian)
mymage Jun 10, 2025
63fac15
Translated using Weblate (Italian)
mymage Jun 10, 2025
1897e13
Translated using Weblate (Italian)
mymage Jun 11, 2025
33bbe69
[IMP] ai_oca_bridge
etobella Jun 10, 2025
f582157
[IMP] ai_oca_bridge: Add action option
etobella Jun 12, 2025
d917fbd
[UPD] Update ai_oca_bridge.pot
Jun 17, 2025
286fa3b
[BOT] post-merge updates
OCA-git-bot Jun 17, 2025
06c4bd0
Update translation files
weblate Jun 17, 2025
e7fdd03
Translated using Weblate (Italian)
mymage Jun 18, 2025
8e4f772
[FIX] ai_oca_bridge: Enforce saving before executing it
etobella Jun 19, 2025
b04c102
[BOT] post-merge updates
OCA-git-bot Jun 19, 2025
f7d8c5e
[IMP] ai_oca_bridge: Allow to send files on Creation
etobella Jun 23, 2025
9e8bbb6
[UPD] Update ai_oca_bridge.pot
Jul 15, 2025
38671e7
Update translation files
weblate Jul 15, 2025
4f1c791
Translated using Weblate (Italian)
mymage Jul 15, 2025
4df195f
Translated using Weblate (Italian)
mymage Jul 22, 2025
6515aa8
[UPD] Update ai_oca_bridge.pot
Jul 29, 2025
61fef7c
Update translation files
weblate Jul 29, 2025
5a70331
[UPD] Update ai_oca_bridge.pot
Jul 31, 2025
71a5451
Update translation files
weblate Jul 31, 2025
7dbf4e4
[FIX] ai_oca_bridge token authentication
arielbarreiros96 Jul 31, 2025
8c7df9b
Translated using Weblate (Italian)
mymage Jul 31, 2025
2dc9b8e
Added translation using Weblate (Spanish)
macagua Aug 14, 2025
0bd5810
Added translation using Weblate (Spanish (Venezuela))
macagua Aug 14, 2025
06b8d3b
Translated using Weblate (Spanish)
macagua Aug 15, 2025
4b1f8bb
Translated using Weblate (Spanish (Venezuela))
macagua Aug 15, 2025
9f473a6
Added translation using Weblate (Portuguese (Brazil))
marcelsavegnago Aug 21, 2025
e4aa55e
[BOT] post-merge updates
OCA-git-bot Aug 25, 2025
7e27c06
[IMP] ai_oca_bridge: pre-commit auto fixes
yoadria Aug 25, 2025
5178663
[MIG] ai_oca_bridge: Migration to 17.0
yoadria Aug 13, 2025
d936cc5
[UPD] Update ai_oca_bridge.pot
Aug 26, 2025
9277195
[BOT] post-merge updates
OCA-git-bot Aug 26, 2025
6ebf409
[MIG] ai_oca_bridge: Migration to 18.0
luisDIXMIT Sep 3, 2025
17be27c
[UPD] Update ai_oca_bridge.pot
Sep 10, 2025
6f8dfd3
[BOT] post-merge updates
OCA-git-bot Sep 10, 2025
2b3a179
[UPD] Update ai_oca_bridge.pot
Sep 18, 2025
222c312
Update translation files
weblate Sep 18, 2025
ca902b9
Translated using Weblate (Italian)
mymage Sep 26, 2025
7528974
[IMP] ai_oca_bridge thread models selection
arielbarreiros96 Sep 25, 2025
4a833af
[IMP] ai_oca_bridge: Allow access to portal users
etobella Nov 18, 2025
adfb876
[UPD] Update ai_oca_bridge.pot
Dec 9, 2025
142b502
[BOT] post-merge updates
OCA-git-bot Dec 9, 2025
f95f33b
Update translation files
weblate Dec 9, 2025
48f415e
Translated using Weblate (Italian)
mymage Dec 11, 2025
aaee0bf
[IMP] ai_oca_bridge: support server_action result_type
thienvh332 Dec 16, 2025
fcc9c24
[IMP] ai_oca_bridge: support field-based trigger for ai_thread_update
thienvh332 Dec 16, 2025
b4f3aa2
[IMP] ai_oca_bridge: add examples data for AI bridge configuration wi…
thienvh332 Dec 17, 2025
a622199
[MIG] ai_oca_bridge: Migration to 19.0
hailangvn Jan 7, 2026
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
205 changes: 205 additions & 0 deletions ai_oca_bridge/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=============
AI OCA Bridge
=============

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

.. |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-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fai-lightgray.png?logo=github
:target: https://github.com/OCA/ai/tree/19.0/ai_oca_bridge
:alt: OCA/ai
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/ai-19-0/ai-19-0-ai_oca_bridge
: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/ai&target_branch=19.0
:alt: Try me on Runboat

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

This module is used to create a bridge between Odoo and other AI systems
like n8n.

**Table of contents**

.. contents::
:local:

Use Cases / Context
===================

Right now, there are 2 different approaches for AI integration with
Odoo:

1. Make everything inside Odoo.
2. Make it using other tools and integrate Odoo with these tools.

IMO, it would be better to make use of option 2 for different reasons:

- Odoo server is intended as a transactional system. AI systems requires
other kind of characteristics
- Everything changes too fast. I am not confident that Odoo can keep the
pace in this topic
- There are OSS tools that fills the gap perfectly and are created just
for this topic.

Anyway, OCA is open to everyone and we don't intend to force an
opinionated way of doing. For this reason, we have this module, that can
be used as Bridge with AI systems.

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

As an administrator access ``AI Bridge\AI Bridge``.

Create a new bridge. Define the name, model, url and configuration.

In order to improve the view of the AI configuration, use groups and
domain to set better filters.

Payload Configuration
---------------------

On the external system, you will receive a POST payload. The data
included will be the following:

General
~~~~~~~

- \_odoo: Standard data to identify the Odoo Database
- \_model: Model of the related object
- \_id: Id of the related object
- \_response_url: Url to call with the response in case of async calls

Record Payload
~~~~~~~~~~~~~~

Adds a new item called record with all the fields.

Asynchronous and synchronous calls
----------------------------------

The new system allows asynchronous and synchronous calls. Asynchronous
calls makes sense when the task to be processed don't need to be
immediate. For example, reviewing an invoice and leave a comment with
the result. The same would happen with a chat message. We expect that
the system will leave time to the AI to answer and Odoo's user can do
other things.

Meanwhile, Synchronous calls will froze odoo system and wait for an
answer. This makes sense when we expect some feedback from odoo user. It
makes sense, when we open an action for example.

In the synchronous call, the result is processed when the AI system
answers on the webhook. On the other hand, it will be processed
automatically on the synchronous call.

Result processing
-----------------

With the answers of the system we expect to do something about it. We
have the following options:

No processing
~~~~~~~~~~~~~

In this case, the result will do nothing

Post a Message
~~~~~~~~~~~~~~

We will post a message on the original thread of the system. The thread
is computed by a function, so it can be overriden in future modules. It
expects the keyword arguments of the ``message_post`` function.

Action
~~~~~~

It expects to launch an action on the user interface. It only makes
sense on synchronous calls.

It expects an action item with the following parameters:

- action: xmlid of the action
- context: Context to pass to the action (not required)
- res_id: Id of the resource (not required)

Usage
=====

Use the bolt widget in the chatter to execute the different AI options.

The options will be filtered according to the configuration.

Known issues / Roadmap
======================

- Define examples to use and import
- Allow child fields. Right now, only first level fields are accepted.
- Information popover is not working properly when there is large data.

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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/ai/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/ai/issues/new?body=module:%20ai_oca_bridge%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
-------

* Dixmit

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

- `Dixmit <https://www.dixmit.com>`__

- Enric Tobella

- `Sygel Technology <https://www.sygel.es>`__

- Valentín Vinagre

- `Binhex <https://www.binhex.cloud/>`__

- Ariel Barreiros
- Adria Hortoneda

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.

This module is part of the `OCA/ai <https://github.com/OCA/ai/tree/19.0/ai_oca_bridge>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
2 changes: 2 additions & 0 deletions ai_oca_bridge/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import controllers
from . import models
39 changes: 39 additions & 0 deletions ai_oca_bridge/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Copyright 2025 Dixmit
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "AI OCA Bridge",
"summary": """
Makes a basic configuration to be used as bridge with external AI systems
""",
"version": "19.0.1.0.0",
"license": "AGPL-3",
"author": "Dixmit,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/ai",
"category": "AI",
"development_status": "Beta",
"depends": [
"base",
"mail",
"web",
],
"data": [
"data/ir_module_category.xml",
"security/ir.model.access.csv",
"security/security.xml",
"views/menu.xml",
"views/ai_bridge_execution.xml",
"views/ai_bridge.xml",
],
"assets": {
"web.assets_backend": [
"ai_oca_bridge/static/src/chatter_ai_registry.esm.js",
"ai_oca_bridge/static/src/**/*.xml",
"ai_oca_bridge/static/src/**/*.esm.js",
],
"web.assets_unit_tests": [
"ai_oca_bridge/static/tests/**/*",
],
},
"application": True,
}
1 change: 1 addition & 0 deletions ai_oca_bridge/controllers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import ai
50 changes: 50 additions & 0 deletions ai_oca_bridge/controllers/ai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright 2025 Dixmit
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

import json

from odoo import fields, http
from odoo.http import request
from odoo.tools import consteq


class AIController(http.Controller):
@http.route(
[
"/ai/response/<int:execution_id>/<string:token>",
],
type="http",
auth="public",
cors="*",
csrf=False,
)
def ai_process_response(self, execution_id, token):
execution = request.env["ai.bridge.execution"].sudo().browse(execution_id)
if not execution.exists():
return request.make_response(self.env._("Execution not found."), status=404)
if not consteq(execution._generate_token(), token):
return request.make_response(
self.env._("Token is not allowed for this execution."),
status=404,
)
if (
not execution.expiration_date
or execution.expiration_date < fields.Datetime.now()
):
return request.make_response(
self.env._("Execution is expired."), status=404
)
try:
charset = request.httprequest.charset
except AttributeError:
charset = "utf-8"
return request.make_response(
json.dumps(
execution._process_response(
json.loads(request.httprequest.get_data().decode(charset))
)
),
headers=[
("Content-Type", "application/json"),
],
)
7 changes: 7 additions & 0 deletions ai_oca_bridge/data/ir_module_category.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.module.category" id="module_category_ai">
<field name="name">AI</field>
<field name="sequence">99</field>
</record>
</odoo>
42 changes: 42 additions & 0 deletions ai_oca_bridge/examples/filter_spam_tickets.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="tag_helpdesk_spam" model="helpdesk.ticket.tag">
<field name="name">Spam</field>
<field name="color">1</field>
</record>

<record id="action_mark_ticket_as_spam" model="ir.actions.server">
<field name="name">AI Action: Mark Ticket as Spam</field>
<field name="model_id" ref="helpdesk_mgmt.model_helpdesk_ticket" />
<field name="state">code</field>
<field name="code">
ai_data = env.context.get('ai_response', {})

reason = ai_data.get('reason', 'AI System Flagged')
confidence = ai_data.get('confidence', 'N/A')

spam_tag = env.ref('ai_oca_bridge.tag_helpdesk_spam', raise_if_not_found=False)

if spam_tag:
for ticket in records:
if spam_tag.id not in ticket.tag_ids.ids:
ticket.write({'tag_ids': [(4, spam_tag.id)]})

msg_body = f"🤖 &lt;b&gt;SPAM DETECTED&lt;/b&gt;&lt;br/&gt;Reason: {reason} (Confidence: {confidence})"
ticket.message_post(body=msg_body)
</field>
</record>

<record id="ai_bridge_helpdesk_ticket_spam_identify" model="ai.bridge">
<field name="name">Helpdesk Ticket Spam Identification</field>
<field name="model_id" ref="helpdesk_mgmt.model_helpdesk_ticket" />
<field name="usage">ai_thread_create</field>
<field name="result_kind">async</field>
<field name="result_type">server_action</field>
<field name="server_action_id" ref="ai_oca_bridge.action_mark_ticket_as_spam" />
<field
name="field_ids"
eval="[(6, 0, [ref('helpdesk_mgmt.field_helpdesk_ticket__id'), ref('helpdesk_mgmt.field_helpdesk_ticket__display_name'), ref('helpdesk_mgmt.field_helpdesk_ticket__description')])]"
/>
</record>
</odoo>
Loading