- Remove hardcoded OPENROUTER_MODEL_CHOICES from openrouter.py
- Add API endpoint /integrations/openrouter/models/ to fetch models dynamically
- Models loaded from OpenRouter API with free models (':free') at top
- Update OpenRouterIntegration model_name field (remove choices, blank=True)
- Add async buildForm() with dynamic_choices support
- Show asterisks (********) for saved API keys with helpful placeholder
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
87 lines
3.0 KiB
Python
87 lines
3.0 KiB
Python
from django.db import models
|
||
from integrations.models.base import BaseIntegration, IntegrationType
|
||
from django.core.exceptions import ValidationError
|
||
from integrations.fields import EncryptedCharField
|
||
|
||
|
||
def validate_temperature(value):
|
||
"""Валидатор для температуры, принимает значения от 0 до 2"""
|
||
if value < 0 or value > 2:
|
||
raise ValidationError('Температура должна быть в диапазоне 0.0-2.0')
|
||
|
||
|
||
# Предустановленные значения температуры
|
||
OPENROUTER_TEMPERATURE_CHOICES = [
|
||
(0.1, '0.1 - Очень консервативно'),
|
||
(0.3, '0.3 - Консервативно'),
|
||
(0.5, '0.5 - Умеренно'),
|
||
(0.7, '0.7 - Баланс (по умолчанию)'),
|
||
(1.0, '1.0 - Креативно'),
|
||
(1.5, '1.5 - Очень креативно'),
|
||
(2.0, '2.0 - Максимальная креативность'),
|
||
]
|
||
|
||
|
||
class AIIntegration(BaseIntegration):
|
||
"""
|
||
Базовая модель для интеграций с ИИ-сервисами
|
||
"""
|
||
class Meta:
|
||
abstract = True
|
||
|
||
|
||
class OpenRouterIntegration(AIIntegration):
|
||
"""
|
||
Интеграция с OpenRouter.ai
|
||
"""
|
||
integration_type = IntegrationType.AI_SERVICE
|
||
|
||
api_key = EncryptedCharField(
|
||
max_length=500,
|
||
blank=True,
|
||
verbose_name="API ключ",
|
||
help_text="Ключ для доступа к API OpenRouter (шифруется в БД)"
|
||
)
|
||
|
||
api_url = models.URLField(
|
||
max_length=500,
|
||
default="https://openrouter.ai/api/v1",
|
||
verbose_name="URL API",
|
||
help_text="URL для обращения к API OpenRouter (обычно https://openrouter.ai/api/v1)"
|
||
)
|
||
|
||
model_name = models.CharField(
|
||
max_length=200,
|
||
default="",
|
||
blank=True,
|
||
verbose_name="Название модели",
|
||
help_text="Название используемой модели OpenRouter (загружается автоматически)"
|
||
)
|
||
|
||
temperature = models.FloatField(
|
||
default=0.7,
|
||
choices=OPENROUTER_TEMPERATURE_CHOICES,
|
||
validators=[validate_temperature],
|
||
verbose_name="Температура",
|
||
help_text="Параметр температуры для генерации (0.0-2.0)"
|
||
)
|
||
|
||
max_tokens = models.IntegerField(
|
||
default=1000,
|
||
verbose_name="Макс. токенов",
|
||
help_text="Максимальное количество токенов в ответе"
|
||
)
|
||
|
||
class Meta:
|
||
verbose_name = "Интеграция OpenRouter"
|
||
verbose_name_plural = "Интеграции OpenRouter"
|
||
|
||
@property
|
||
def is_configured(self) -> bool:
|
||
return bool(self.api_key)
|
||
|
||
def clean(self):
|
||
super().clean()
|
||
if self.temperature < 0 or self.temperature > 2:
|
||
raise ValidationError({'temperature': 'Температура должна быть в диапазоне 0.0-2.0'})
|