feat(integrations): add dynamic OpenRouter model loading
- 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>
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import json
|
||||
import logging
|
||||
from django.views.generic import TemplateView
|
||||
from django.http import JsonResponse
|
||||
from django.views.decorators.http import require_POST
|
||||
from django.views.decorators.http import require_POST, require_GET
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from user_roles.mixins import OwnerRequiredMixin
|
||||
from .models import RecommerceIntegration, WooCommerceIntegration, GLMIntegration, OpenRouterIntegration
|
||||
@@ -181,6 +184,44 @@ def get_integration_service(integration_id: str, instance):
|
||||
return None
|
||||
|
||||
|
||||
@require_GET
|
||||
def get_openrouter_models(request):
|
||||
"""
|
||||
GET /settings/integrations/openrouter/models/
|
||||
Возвращает список моделей OpenRouter (бесплатные сверху)
|
||||
"""
|
||||
import requests
|
||||
|
||||
try:
|
||||
response = requests.get('https://openrouter.ai/api/v1/models', timeout=10)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
|
||||
models = data.get('data', [])
|
||||
|
||||
# Разделить на бесплатные и платные
|
||||
free_models = []
|
||||
paid_models = []
|
||||
|
||||
for model in models:
|
||||
model_id = model.get('id', '')
|
||||
model_name = model.get('name', model_id)
|
||||
|
||||
if ':free' in model_id:
|
||||
free_models.append({'id': model_id, 'name': f"{model_name} (Бесплатная)"})
|
||||
else:
|
||||
paid_models.append({'id': model_id, 'name': model_name})
|
||||
|
||||
# Бесплатные сверху
|
||||
all_models = free_models + paid_models
|
||||
|
||||
return JsonResponse({'models': all_models})
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching OpenRouter models: {e}")
|
||||
return JsonResponse({'error': str(e)}, status=500)
|
||||
|
||||
|
||||
class RecommerceBatchSyncView(TemplateView):
|
||||
"""
|
||||
API View для запуска массовой синхронизации с Recommerce.
|
||||
@@ -363,29 +404,33 @@ def get_form_fields_meta(model):
|
||||
'label': getattr(field, 'verbose_name', field_name),
|
||||
'help_text': getattr(field, 'help_text', ''),
|
||||
'required': not getattr(field, 'blank', True),
|
||||
'type': 'text', # default
|
||||
'type': 'password' if field_name == 'api_key' else 'text',
|
||||
}
|
||||
|
||||
# Определить тип поля
|
||||
if 'BooleanField' in field.__class__.__name__:
|
||||
field_info['type'] = 'checkbox'
|
||||
elif 'URLField' in field.__class__.__name__:
|
||||
field_info['type'] = 'url'
|
||||
elif 'secret' in field_name.lower() or 'token' in field_name.lower() or 'key' in field_name.lower():
|
||||
field_info['type'] = 'password'
|
||||
|
||||
fields.append(field_info)
|
||||
elif field_name in ['model_name', 'temperature']:
|
||||
|
||||
elif field_name == 'temperature':
|
||||
field = model._meta.get_field(field_name)
|
||||
field_info = {
|
||||
'name': field_name,
|
||||
'label': getattr(field, 'verbose_name', field_name),
|
||||
'help_text': getattr(field, 'help_text', ''),
|
||||
'required': not getattr(field, 'blank', True),
|
||||
'type': 'select', # dropdown
|
||||
'type': 'select',
|
||||
'choices': getattr(field, 'choices', [])
|
||||
}
|
||||
fields.append(field_info)
|
||||
|
||||
elif field_name == 'model_name':
|
||||
field = model._meta.get_field(field_name)
|
||||
field_info = {
|
||||
'name': field_name,
|
||||
'label': getattr(field, 'verbose_name', field_name),
|
||||
'help_text': getattr(field, 'help_text', ''),
|
||||
'required': not getattr(field, 'blank', True),
|
||||
'type': 'select',
|
||||
'dynamic_choices': True,
|
||||
'choices_url': '/settings/integrations/openrouter/models/'
|
||||
}
|
||||
fields.append(field_info)
|
||||
# Для WooCommerce показываем только базовые поля для подключения
|
||||
elif model.__name__ == 'WooCommerceIntegration':
|
||||
|
||||
Reference in New Issue
Block a user