212 lines
7.5 KiB
Python
212 lines
7.5 KiB
Python
from odoo import models, fields, api, _
|
|
|
|
class OllamaProviderMixin(models.AbstractModel):
|
|
"""Mixin model that provides Ollama-specific configuration parameters.
|
|
|
|
This mixin is designed to be inherited by models that need to interact with
|
|
the Ollama AI provider. It provides all the necessary fields and methods
|
|
for configuring and interacting with Ollama's API.
|
|
|
|
Key Features:
|
|
- Provider type selection and validation
|
|
- Context window configuration
|
|
- Advanced sampling parameters (temperature, top-k, top-p)
|
|
- Token generation controls
|
|
|
|
Technical Details:
|
|
- Inherits from ai.generation.params for base AI generation parameters
|
|
- Implements Ollama-specific API parameters
|
|
- Provides default values optimized for general use cases
|
|
"""
|
|
_name = 'ollama.provider.mixin'
|
|
_description = 'Ollama Provider Configuration Mixin'
|
|
_inherit = ['ai.generation.params']
|
|
|
|
# Provider Configuration
|
|
provider_type = fields.Selection(
|
|
selection=[('ollama', 'Ollama')],
|
|
string='Provider Type',
|
|
required=True,
|
|
default='ollama',
|
|
help='Type of AI provider - Must be Ollama for this configuration')
|
|
|
|
# Model Parameters
|
|
model_name = fields.Char(
|
|
string='Model Name',
|
|
help='Name of the Ollama model to use (e.g. llama2, mistral, codellama)',
|
|
required=True,
|
|
default='llama2')
|
|
|
|
# Context Window Configuration
|
|
num_ctx = fields.Integer(
|
|
string='Context Length',
|
|
help='Maximum number of tokens to consider for context. A larger context window allows '
|
|
'the model to access more historical information but requires more memory. '
|
|
'Range: [0 - 32768].',
|
|
default=4096)
|
|
|
|
# Generation Parameters
|
|
temperature = fields.Float(
|
|
string='Temperature',
|
|
help='Controls randomness in the output. Higher values make the output more random, '
|
|
'while lower values make it more focused and deterministic. '
|
|
'Range: [0.0 - 2.0]',
|
|
default=0.8)
|
|
|
|
top_p = fields.Float(
|
|
string='Top P',
|
|
help='Nucleus sampling: only consider the tokens whose cumulative probability exceeds '
|
|
'this value. Lower values make the output more focused. '
|
|
'Range: [0.0 - 1.0]',
|
|
default=0.9)
|
|
|
|
top_k = fields.Integer(
|
|
string='Top K',
|
|
help='Only consider the top K tokens for text generation. Lower values make the '
|
|
'output more focused. Set to 0 to disable. '
|
|
'Range: [0 - 100]',
|
|
default=40)
|
|
|
|
repeat_penalty = fields.Float(
|
|
string='Repeat Penalty',
|
|
help='Penalty for repeating tokens. Higher values make the output less repetitive. '
|
|
'Range: [0.0 - 2.0]',
|
|
default=1.1)
|
|
|
|
# Advanced Configuration
|
|
stop_sequences = fields.Char(
|
|
string='Stop Sequences',
|
|
help='Comma-separated list of sequences where the model should stop generating further tokens.')
|
|
|
|
top_k = fields.Integer(
|
|
string='Top K',
|
|
help='Limits the cumulative probability of tokens to sample from. Only the top K '
|
|
'most likely tokens are considered for sampling at each step. '
|
|
'Range: [1 - 100].',
|
|
default=40)
|
|
|
|
top_p = fields.Float(
|
|
string='Top P (Nucleus Sampling)',
|
|
help='Limits the cumulative probability of tokens to sample from. Only the most likely '
|
|
'tokens with total probability mass of top_p are considered. '
|
|
'Range: [0.0 - 1.0].',
|
|
default=0.9)
|
|
|
|
min_p = fields.Float(
|
|
string='Min P',
|
|
help='Sets a minimum probability threshold for token selection. Range: [0.0 - 1.0].',
|
|
default=0.05,
|
|
digits=(3, 2))
|
|
|
|
repeat_penalty = fields.Float(
|
|
string='Repeat Penalty',
|
|
help='Penalty for repeating tokens. Range: [1.0 - 2.0]. Higher values make repetition less likely.',
|
|
default=1.1,
|
|
digits=(3, 2))
|
|
|
|
repeat_last_n = fields.Integer(
|
|
string='Repeat Last N',
|
|
help='Sets the context window for repeat penalty. Range: [0 - 4096]. Default is 64, 0 disables.',
|
|
default=64)
|
|
|
|
# Advanced Generation Parameters
|
|
seed = fields.Integer(
|
|
string='Random Seed',
|
|
help='Sets the random seed for generation. Range: [0 - 2147483647]. Use 0 for random.',
|
|
default=0)
|
|
|
|
num_gpu = fields.Integer(
|
|
string='Number of GPUs',
|
|
help='Number of GPUs to use for generation. Range: [0 - 8]. 0 means CPU only.',
|
|
default=1)
|
|
|
|
num_thread = fields.Integer(
|
|
string='Number of Threads',
|
|
help='Number of CPU threads to use for generation. Range: [1 - 32].',
|
|
default=8)
|
|
|
|
mirostat = fields.Selection([
|
|
('0', 'Disabled'),
|
|
('1', 'Mirostat'),
|
|
('2', 'Mirostat 2.0')],
|
|
string='Mirostat Mode',
|
|
help='Enable Mirostat sampling for controlling perplexity',
|
|
default='0')
|
|
|
|
mirostat_tau = fields.Float(
|
|
string='Mirostat Tau',
|
|
help='Mirostat target entropy. Range: [0.0 - 10.0].',
|
|
default=5.0,
|
|
digits=(3, 2))
|
|
|
|
mirostat_eta = fields.Float(
|
|
string='Mirostat Eta',
|
|
help='Mirostat learning rate. Range: [0.0 - 1.0].',
|
|
default=0.1,
|
|
digits=(3, 2))
|
|
|
|
# Ollama-specific Response Control
|
|
|
|
tfs_z = fields.Float(
|
|
string='Tail Free Sampling Z',
|
|
help='Tail free sampling parameter. Range: [0.0 - 2.0]. Higher value = more focused.',
|
|
default=1.0,
|
|
digits=(3, 2))
|
|
|
|
# System Settings
|
|
num_batch = fields.Integer(
|
|
string='Batch Size',
|
|
help='Number of prompts to batch together',
|
|
default=8)
|
|
|
|
num_keep = fields.Integer(
|
|
string='Keep Last N Tokens',
|
|
help='Number of tokens to keep from initial prompt',
|
|
default=0)
|
|
|
|
skip_special_tokens = fields.Boolean(
|
|
string='Skip Special Tokens',
|
|
help='Skip special tokens in generation',
|
|
default=True)
|
|
|
|
@api.model
|
|
def default_get(self, fields_list):
|
|
defaults = super().default_get(fields_list)
|
|
if 'provider_type' in fields_list:
|
|
defaults['provider_type'] = 'ollama'
|
|
if 'host' in fields_list and not defaults.get('host'):
|
|
defaults['host'] = 'http://localhost:11434'
|
|
return defaults
|
|
|
|
def _get_provider_options(self):
|
|
"""Get Ollama-specific options for API calls."""
|
|
self.ensure_one()
|
|
options = {
|
|
'temperature': self.temperature,
|
|
'num_ctx': self.num_ctx,
|
|
'num_predict': self.num_predict,
|
|
'top_k': self.top_k,
|
|
'top_p': self.top_p,
|
|
'min_p': self.min_p,
|
|
'repeat_penalty': self.repeat_penalty,
|
|
'repeat_last_n': self.repeat_last_n,
|
|
'seed': self.seed,
|
|
'num_gpu': self.num_gpu,
|
|
'num_thread': self.num_thread,
|
|
'mirostat': int(self.mirostat),
|
|
'mirostat_tau': self.mirostat_tau,
|
|
'mirostat_eta': self.mirostat_eta,
|
|
'num_batch': self.num_batch,
|
|
'num_keep': self.num_keep,
|
|
'tfs_z': self.tfs_z,
|
|
'skip_special_tokens': self.skip_special_tokens,
|
|
}
|
|
|
|
if self.stop_sequences:
|
|
options['stop'] = [
|
|
seq.strip()
|
|
for seq in self.stop_sequences.split(',')
|
|
if seq.strip()
|
|
]
|
|
|
|
return options
|