115 lines
3.7 KiB
Python
115 lines
3.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
from odoo import models, fields, api, _
|
|
from odoo.addons.mail.models.mail_thread import MailThread
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class AIProviderInstance(models.Model):
|
|
_name = 'ai.provider.instance'
|
|
_description = 'AI Provider Instance'
|
|
_order = 'name'
|
|
_check_company = False # Disable automatic company checks
|
|
_inherit = ['mail.thread', 'ai.base.mixin']
|
|
|
|
@api.model
|
|
def _has_provider_modules(self):
|
|
"""Check if any AI provider modules are installed."""
|
|
modules = ['ollama_ai_integration', 'chatgpt_ai_integration']
|
|
return any(self.env['ir.module.module'].search([('name', 'in', modules), ('state', '=', 'installed')]))
|
|
|
|
@api.model
|
|
def default_get(self, fields_list):
|
|
"""Override default_get to prevent creation if no provider modules are installed."""
|
|
if not self._has_provider_modules():
|
|
raise UserError(_('No AI provider modules are installed. Please install at least one provider module (e.g., Ollama or ChatGPT) before creating a provider instance.'))
|
|
return super().default_get(fields_list)
|
|
|
|
active = fields.Boolean(
|
|
string='Active',
|
|
default=True,
|
|
help='Whether this provider instance is active and available for use')
|
|
|
|
name = fields.Char(
|
|
string='Name',
|
|
required=True,
|
|
help='Name of this provider instance (e.g., "OpenWebUI Production", "Ollama Local")'
|
|
)
|
|
|
|
provider_id = fields.Many2one(
|
|
'ai.provider',
|
|
string='Provider',
|
|
required=True,
|
|
ondelete='restrict',
|
|
help='The AI provider configuration'
|
|
)
|
|
|
|
provider_type = fields.Selection(
|
|
selection=[
|
|
('none', 'None') # Base selection, will be extended by provider modules
|
|
],
|
|
string='Provider Type',
|
|
required=True,
|
|
ondelete={'none': 'set default'},
|
|
default='none',
|
|
help='Type of AI provider'
|
|
)
|
|
|
|
host = fields.Char(
|
|
string='Host',
|
|
required=True,
|
|
help='Host address (e.g., "http://localhost:8080" or "https://api.example.com")'
|
|
)
|
|
|
|
api_key = fields.Char(
|
|
string='API Key',
|
|
help='API key if required by the provider'
|
|
)
|
|
|
|
|
|
@api.onchange('provider_id')
|
|
def _onchange_provider_id(self):
|
|
if self.provider_id:
|
|
self.provider_type = self.provider_id.code
|
|
|
|
model_ids = fields.One2many(
|
|
'ai.model',
|
|
'provider_instance_id',
|
|
copy=True,
|
|
string='Available Models'
|
|
)
|
|
|
|
timeout = fields.Integer(
|
|
string='Timeout',
|
|
default=60,
|
|
help='Maximum wait time for API calls (in seconds)'
|
|
)
|
|
|
|
max_retries = fields.Integer(
|
|
string='Max Retries',
|
|
default=3,
|
|
help='Maximum number of retry attempts for failed API calls'
|
|
)
|
|
|
|
_sql_constraints = [
|
|
('name_uniq',
|
|
'unique(name)',
|
|
'Provider instance name must be unique!')
|
|
]
|
|
|
|
def test_connection(self):
|
|
"""Test the connection to this provider instance."""
|
|
self.ensure_one()
|
|
provider_model = f'ai.provider.{self.provider_type}'
|
|
if provider_model not in self.env:
|
|
raise UserError(_("Provider type %s is not installed", self.provider_type))
|
|
|
|
return self.env[provider_model].test_connection(self)
|
|
|
|
def sync_models(self):
|
|
"""Synchronize models from this provider instance."""
|
|
self.ensure_one()
|
|
provider_model = f'ai.provider.{self.provider_type}'
|
|
if provider_model not in self.env:
|
|
raise UserError(_("Provider type %s is not installed", self.provider_type))
|
|
|
|
return self.env[provider_model].sync_models(self)
|