bemade-addons/helpdesk_sale_order_ai/models/ai_openwebui_client.py
mathis c5904a51d7 [REF] Replace openwebui_connector with centralized openwebui_base module
This commit represents a significant architectural improvement:

- Completely replaced openwebui_connector with a more robust openwebui_base module
- Centralized OpenWebUI API integration for better maintainability
- Redesigned helpdesk_sale_order_ai to use the new openwebui_base module
- Added support for multiple OpenWebUI providers and models
- Improved error handling and response parsing
- Added proper template management with openwebui_prompt_template
- Fixed KeyError issues with safe template substitution
- Streamlined API client initialization and usage
2025-07-28 13:27:29 -04:00

114 lines
4.3 KiB
Python

# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
import logging
import requests
import json
_logger = logging.getLogger(__name__)
class AIOpenWebUIClient(models.AbstractModel):
"""
Abstract model to provide a bridge between the helpdesk_sale_order_ai module
and the openwebui_base module.
This ensures proper integration with the OpenWebUI API using configuration
from the settings.
"""
_name = "helpdesk_sale_order_ai.openwebui.client"
_description = "OpenWebUI Client"
@api.model
def chat_completion(self, messages, model=None, **kwargs):
"""
Send a chat completion request to the OpenWebUI API
Args:
messages: List of message dictionaries with 'role' and 'content'
model: The model to use for the completion (default: anthropic.claude-3-7-sonnet-latest)
**kwargs: Additional parameters to pass to the OpenWebUI client
Returns:
The response from the OpenWebUI API
"""
# Check if openwebui_base module is installed
module_obj = self.env['ir.module.module']
openwebui_base_module = module_obj.search([('name', '=', 'openwebui_base'), ('state', '=', 'installed')])
if not openwebui_base_module:
_logger.error("The openwebui_base module is not installed. Cannot use AI features.")
return False
try:
# Get configuration from settings
config = self.env['ir.config_parameter'].sudo()
company = self.env.company
# Get provider configuration
provider = company.openwebui_provider_id
if not provider:
_logger.error("No OpenWebUI provider configured for this company")
return False
# Get API key and base URL from provider
api_key = provider.api_key
base_url = provider.base_url
if not api_key or not base_url:
_logger.error("Missing API key or base URL in OpenWebUI provider configuration")
return False
# Get model from company settings or use provided model or default
if not model and company.openwebui_default_model_id:
model = company.openwebui_default_model_id.technical_name
_logger.info(f"Using OpenWebUI API with model={model} and {len(messages)} messages")
# Log first few characters of the prompt for debugging
if messages and len(messages) > 0:
first_content = messages[0].get('content', '')[:100]
_logger.info(f"First message content (truncated): {first_content}...")
# Prepare the request
headers = {
'Content-Type': 'application/json',
'Authorization': f'Bearer {api_key}'
}
data = {
'model': model,
'messages': messages,
**kwargs
}
# Make the API call
endpoint = f"{base_url.rstrip('/')}/chat/completions"
_logger.info(f"Sending request to {endpoint}")
response = requests.post(
endpoint,
headers=headers,
json=data,
timeout=60 # Reasonable timeout for AI responses
)
# Check for successful response
response.raise_for_status()
result = response.json()
# Log response summary
if result:
_logger.info(f"Received response from OpenWebUI API: {str(result)[:200]}...")
else:
_logger.warning("Received empty response from OpenWebUI API")
return result
except requests.exceptions.RequestException as e:
_logger.error(f"API request error in chat_completion: {str(e)}")
return False
except json.JSONDecodeError as e:
_logger.error(f"JSON decode error in chat_completion: {str(e)}")
return False
except Exception as e:
_logger.error(f"Unexpected error in chat_completion: {str(e)}")
return False