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
114 lines
4.3 KiB
Python
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
|