feat(addon): add ActiveBlue AI bot to Odoo Discuss
- Create res.partner for the AI bot (appears in DM contacts) - Override mail.channel.message_post to intercept direct messages to the bot partner and forward them to the agent service - Post the agent reply back into the Discuss channel as the bot - Add discuss to depends; load res_partner_bot.xml data Users can now open Discuss -> New Message -> search 'ActiveBlue AI' to start a conversation with the agent. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,10 +11,11 @@ CRM, sales, project management, eLearning, expenses, and HR.
|
||||
'website': 'https://activeblue.net',
|
||||
'category': 'Productivity',
|
||||
'license': 'LGPL-3',
|
||||
'depends': ['base', 'mail', 'web'],
|
||||
'depends': ['base', 'mail', 'web', 'discuss'],
|
||||
'data': [
|
||||
'security/res_groups.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'data/res_partner_bot.xml',
|
||||
'data/ir_cron.xml',
|
||||
'views/ab_ai_bot_views.xml',
|
||||
'views/ab_ai_directive_views.xml',
|
||||
|
||||
11
addons/activeblue_ai/data/res_partner_bot.xml
Normal file
11
addons/activeblue_ai/data/res_partner_bot.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="partner_activeblue_ai" model="res.partner">
|
||||
<field name="name">ActiveBlue AI</field>
|
||||
<field name="active">True</field>
|
||||
<field name="partner_share">False</field>
|
||||
<field name="comment">AI assistant — send a direct message to chat</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -1 +1 @@
|
||||
from . import ab_ai_bot, ab_ai_directive, ab_ai_log, ab_ai_registry
|
||||
from . import ab_ai_bot, ab_ai_directive, ab_ai_log, ab_ai_registry, ab_ai_mail
|
||||
|
||||
71
addons/activeblue_ai/models/ab_ai_mail.py
Normal file
71
addons/activeblue_ai/models/ab_ai_mail.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
import re
|
||||
|
||||
from odoo import models, api
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
_HTML_TAG = re.compile(r'<[^>]+>')
|
||||
|
||||
|
||||
def _strip_html(html: str) -> str:
|
||||
return _HTML_TAG.sub(' ', html or '').strip()
|
||||
|
||||
|
||||
class MailChannel(models.Model):
|
||||
_inherit = 'mail.channel'
|
||||
|
||||
@api.model
|
||||
def _ai_bot_partner(self):
|
||||
return self.env.ref('activeblue_ai.partner_activeblue_ai', raise_if_not_found=False)
|
||||
|
||||
def message_post(self, *, body='', author_id=None, **kwargs):
|
||||
result = super().message_post(body=body, author_id=author_id, **kwargs)
|
||||
|
||||
# Only intercept direct-message channels
|
||||
if self.channel_type != 'chat':
|
||||
return result
|
||||
|
||||
bot_partner = self._ai_bot_partner()
|
||||
if not bot_partner:
|
||||
return result
|
||||
|
||||
member_partners = self.channel_member_ids.partner_id
|
||||
if bot_partner not in member_partners:
|
||||
return result
|
||||
|
||||
# Don't react to the bot's own messages
|
||||
if author_id == bot_partner.id:
|
||||
return result
|
||||
|
||||
text = _strip_html(body)
|
||||
if not text:
|
||||
return result
|
||||
|
||||
# Identify the human sender
|
||||
human_partner = member_partners.filtered(lambda p: p != bot_partner)[:1]
|
||||
user = self.env['res.users'].search([('partner_id', '=', human_partner.id)], limit=1)
|
||||
uid = user.id if user else self.env.uid
|
||||
|
||||
try:
|
||||
bot = self.env['ab.ai.bot'].sudo().search([('active', '=', True)], limit=1)
|
||||
if not bot:
|
||||
return result
|
||||
response = bot.dispatch_message(
|
||||
user_id=uid,
|
||||
message=text,
|
||||
context={'channel_id': self.id, 'source': 'discuss'},
|
||||
)
|
||||
reply = (response or {}).get('reply') or (response or {}).get('message') or \
|
||||
'I could not process your request right now.'
|
||||
self.sudo().message_post(
|
||||
body=reply,
|
||||
author_id=bot_partner.id,
|
||||
message_type='comment',
|
||||
subtype_xmlid='mail.mt_comment',
|
||||
)
|
||||
except Exception as exc:
|
||||
_logger.error('AI bot Discuss reply failed: %s', exc)
|
||||
|
||||
return result
|
||||
Reference in New Issue
Block a user