- Added Linker and Optimizer apps to `INSTALLED_APPS` in `settings.py`. - Configured API endpoints for Linker and Optimizer in `urls.py`. - Implemented `OptimizeContentFunction` for content optimization in the AI module. - Created prompts for content optimization and site structure generation. - Updated `OptimizerService` to utilize the new AI function for content optimization. - Developed frontend components including dashboards and content lists for Linker and Optimizer. - Integrated new routes and sidebar navigation for Linker and Optimizer in the frontend. - Enhanced content management with source and sync status filters in the Writer module. - Comprehensive test coverage added for new features and components.
110 lines
4.3 KiB
Python
110 lines
4.3 KiB
Python
import logging
|
|
from rest_framework import status
|
|
from rest_framework.decorators import action
|
|
from rest_framework.viewsets import ViewSet
|
|
from drf_spectacular.utils import extend_schema, extend_schema_view
|
|
|
|
from igny8_core.api.permissions import IsAuthenticatedAndActive, IsEditorOrAbove
|
|
from igny8_core.api.response import success_response, error_response
|
|
from igny8_core.api.throttles import DebugScopedRateThrottle
|
|
from igny8_core.business.content.models import Content
|
|
from igny8_core.business.linking.services.linker_service import LinkerService
|
|
from igny8_core.business.billing.exceptions import InsufficientCreditsError
|
|
from igny8_core.modules.linker.serializers import (
|
|
LinkContentSerializer,
|
|
BatchLinkContentSerializer,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@extend_schema_view(
|
|
process=extend_schema(tags=['Linker']),
|
|
batch_process=extend_schema(tags=['Linker']),
|
|
)
|
|
class LinkerViewSet(ViewSet):
|
|
"""
|
|
API endpoints for internal linking operations.
|
|
Unified API Standard v1.0 compliant
|
|
"""
|
|
permission_classes = [IsAuthenticatedAndActive, IsEditorOrAbove]
|
|
throttle_scope = 'linker'
|
|
throttle_classes = [DebugScopedRateThrottle]
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.linker_service = LinkerService()
|
|
|
|
@action(detail=False, methods=['post'])
|
|
def process(self, request):
|
|
"""
|
|
Process a single content item for internal linking.
|
|
|
|
POST /api/v1/linker/process/
|
|
{
|
|
"content_id": 123
|
|
}
|
|
"""
|
|
serializer = LinkContentSerializer(data=request.data, context={'request': request})
|
|
if not serializer.is_valid():
|
|
return error_response(serializer.errors, status=status.HTTP_400_BAD_REQUEST, request=request)
|
|
|
|
content_id = serializer.validated_data['content_id']
|
|
|
|
try:
|
|
content = self.linker_service.process(content_id)
|
|
|
|
result = {
|
|
'content_id': content.id,
|
|
'links_added': len(content.internal_links) if content.internal_links else 0,
|
|
'links': content.internal_links or [],
|
|
'linker_version': content.linker_version,
|
|
'success': True,
|
|
}
|
|
|
|
return success_response(result, request=request)
|
|
|
|
except ValueError as e:
|
|
return error_response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST, request=request)
|
|
except InsufficientCreditsError as e:
|
|
return error_response({'error': str(e)}, status=status.HTTP_402_PAYMENT_REQUIRED, request=request)
|
|
except Exception as e:
|
|
logger.error(f"Error processing content {content_id}: {str(e)}", exc_info=True)
|
|
return error_response({'error': 'Internal server error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, request=request)
|
|
|
|
@action(detail=False, methods=['post'])
|
|
def batch_process(self, request):
|
|
"""
|
|
Process multiple content items for internal linking.
|
|
|
|
POST /api/v1/linker/batch_process/
|
|
{
|
|
"content_ids": [123, 456, 789]
|
|
}
|
|
"""
|
|
serializer = BatchLinkContentSerializer(data=request.data, context={'request': request})
|
|
if not serializer.is_valid():
|
|
return error_response(serializer.errors, status=status.HTTP_400_BAD_REQUEST, request=request)
|
|
|
|
content_ids = serializer.validated_data['content_ids']
|
|
|
|
try:
|
|
results = self.linker_service.batch_process(content_ids)
|
|
|
|
response_data = []
|
|
for content in results:
|
|
response_data.append({
|
|
'content_id': content.id,
|
|
'links_added': len(content.internal_links) if content.internal_links else 0,
|
|
'links': content.internal_links or [],
|
|
'linker_version': content.linker_version,
|
|
'success': True,
|
|
})
|
|
|
|
return success_response(response_data, request=request)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error batch processing content: {str(e)}", exc_info=True)
|
|
return error_response({'error': 'Internal server error'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR, request=request)
|
|
|