section2-3

This commit is contained in:
IGNY8 VPS (Salman)
2025-11-14 17:27:58 +00:00
parent d14d6093e0
commit 5cc4d07373
2 changed files with 414 additions and 296 deletions

View File

@@ -10,6 +10,7 @@ import json
import time import time
from igny8_core.api.base import SiteSectorModelViewSet from igny8_core.api.base import SiteSectorModelViewSet
from igny8_core.api.pagination import CustomPageNumberPagination from igny8_core.api.pagination import CustomPageNumberPagination
from igny8_core.api.response import success_response, error_response
from .models import Keywords, Clusters, ContentIdeas from .models import Keywords, Clusters, ContentIdeas
from .serializers import KeywordSerializer, ContentIdeasSerializer from .serializers import KeywordSerializer, ContentIdeasSerializer
from .cluster_serializers import ClusterSerializer from .cluster_serializers import ClusterSerializer
@@ -124,10 +125,10 @@ class KeywordViewSet(SiteSectorModelViewSet):
return Response(serializer.data) return Response(serializer.data)
except Exception as e: except Exception as e:
logger.error(f"Error in KeywordViewSet.list(): {type(e).__name__}: {str(e)}", exc_info=True) logger.error(f"Error in KeywordViewSet.list(): {type(e).__name__}: {str(e)}", exc_info=True)
return Response({ return error_response(
'error': f'Error loading keywords: {str(e)}', error=f'Error loading keywords: {str(e)}',
'type': type(e).__name__ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
def perform_create(self, serializer): def perform_create(self, serializer):
"""Require explicit site_id and sector_id - no defaults.""" """Require explicit site_id and sector_id - no defaults."""
@@ -190,12 +191,18 @@ class KeywordViewSet(SiteSectorModelViewSet):
"""Bulk delete keywords""" """Bulk delete keywords"""
ids = request.data.get('ids', []) ids = request.data.get('ids', [])
if not ids: if not ids:
return Response({'error': 'No IDs provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No IDs provided',
status_code=status.HTTP_400_BAD_REQUEST
)
queryset = self.get_queryset() queryset = self.get_queryset()
deleted_count, _ = queryset.filter(id__in=ids).delete() deleted_count, _ = queryset.filter(id__in=ids).delete()
return Response({'deleted_count': deleted_count}, status=status.HTTP_200_OK) return success_response(
data={'deleted_count': deleted_count},
message=f'Successfully deleted {deleted_count} keyword(s)'
)
@action(detail=False, methods=['post'], url_path='bulk_update', url_name='bulk_update') @action(detail=False, methods=['post'], url_path='bulk_update', url_name='bulk_update')
def bulk_update(self, request): def bulk_update(self, request):
@@ -204,14 +211,23 @@ class KeywordViewSet(SiteSectorModelViewSet):
status_value = request.data.get('status') status_value = request.data.get('status')
if not ids: if not ids:
return Response({'error': 'No IDs provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No IDs provided',
status_code=status.HTTP_400_BAD_REQUEST
)
if not status_value: if not status_value:
return Response({'error': 'No status provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No status provided',
status_code=status.HTTP_400_BAD_REQUEST
)
queryset = self.get_queryset() queryset = self.get_queryset()
updated_count = queryset.filter(id__in=ids).update(status=status_value) updated_count = queryset.filter(id__in=ids).update(status=status_value)
return Response({'updated_count': updated_count}, status=status.HTTP_200_OK) return success_response(
data={'updated_count': updated_count},
message=f'Successfully updated {updated_count} keyword(s)'
)
@action(detail=False, methods=['post'], url_path='bulk_add_from_seed', url_name='bulk_add_from_seed') @action(detail=False, methods=['post'], url_path='bulk_add_from_seed', url_name='bulk_add_from_seed')
def bulk_add_from_seed(self, request): def bulk_add_from_seed(self, request):
@@ -223,32 +239,53 @@ class KeywordViewSet(SiteSectorModelViewSet):
sector_id = request.data.get('sector_id') sector_id = request.data.get('sector_id')
if not seed_keyword_ids: if not seed_keyword_ids:
return Response({'error': 'No seed keyword IDs provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No seed keyword IDs provided',
status_code=status.HTTP_400_BAD_REQUEST
)
if not site_id: if not site_id:
return Response({'error': 'site_id is required'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='site_id is required',
status_code=status.HTTP_400_BAD_REQUEST
)
if not sector_id: if not sector_id:
return Response({'error': 'sector_id is required'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='sector_id is required',
status_code=status.HTTP_400_BAD_REQUEST
)
try: try:
site = Site.objects.get(id=site_id) site = Site.objects.get(id=site_id)
sector = Sector.objects.get(id=sector_id) sector = Sector.objects.get(id=sector_id)
except (Site.DoesNotExist, Sector.DoesNotExist) as e: except (Site.DoesNotExist, Sector.DoesNotExist) as e:
return Response({'error': f'Invalid site or sector: {str(e)}'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error=f'Invalid site or sector: {str(e)}',
status_code=status.HTTP_400_BAD_REQUEST
)
# Validate sector belongs to site # Validate sector belongs to site
if sector.site != site: if sector.site != site:
return Response({'error': 'Sector does not belong to the specified site'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='Sector does not belong to the specified site',
status_code=status.HTTP_400_BAD_REQUEST
)
# Get account from site # Get account from site
account = site.account account = site.account
if not account: if not account:
return Response({'error': 'Site has no account assigned'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='Site has no account assigned',
status_code=status.HTTP_400_BAD_REQUEST
)
# Get SeedKeywords # Get SeedKeywords
seed_keywords = SeedKeyword.objects.filter(id__in=seed_keyword_ids, is_active=True) seed_keywords = SeedKeyword.objects.filter(id__in=seed_keyword_ids, is_active=True)
if not seed_keywords.exists(): if not seed_keywords.exists():
return Response({'error': 'No valid seed keywords found'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No valid seed keywords found',
status_code=status.HTTP_400_BAD_REQUEST
)
created_count = 0 created_count = 0
skipped_count = 0 skipped_count = 0
@@ -288,12 +325,14 @@ class KeywordViewSet(SiteSectorModelViewSet):
errors.append(f"Error adding '{seed_keyword.keyword}': {str(e)}") errors.append(f"Error adding '{seed_keyword.keyword}': {str(e)}")
skipped_count += 1 skipped_count += 1
return Response({ return success_response(
'success': True, data={
'created': created_count, 'created': created_count,
'skipped': skipped_count, 'skipped': skipped_count,
'errors': errors[:10] if errors else [] # Limit errors to first 10 'errors': errors[:10] if errors else [] # Limit errors to first 10
}, status=status.HTTP_200_OK) },
message=f'Successfully added {created_count} keyword(s) to workflow'
)
@action(detail=False, methods=['get'], url_path='export', url_name='export') @action(detail=False, methods=['get'], url_path='export', url_name='export')
def export(self, request): def export(self, request):
@@ -366,11 +405,17 @@ class KeywordViewSet(SiteSectorModelViewSet):
Automatically links keywords to current active site/sector. Automatically links keywords to current active site/sector.
""" """
if 'file' not in request.FILES: if 'file' not in request.FILES:
return Response({'error': 'No file provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No file provided',
status_code=status.HTTP_400_BAD_REQUEST
)
file = request.FILES['file'] file = request.FILES['file']
if not file.name.endswith('.csv'): if not file.name.endswith('.csv'):
return Response({'error': 'File must be a CSV'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='File must be a CSV',
status_code=status.HTTP_400_BAD_REQUEST
)
user = getattr(request, 'user', None) user = getattr(request, 'user', None)
@@ -391,23 +436,38 @@ class KeywordViewSet(SiteSectorModelViewSet):
# Site ID is REQUIRED # Site ID is REQUIRED
if not site_id: if not site_id:
return Response({'error': 'site_id is required'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='site_id is required',
status_code=status.HTTP_400_BAD_REQUEST
)
try: try:
site = Site.objects.get(id=site_id) site = Site.objects.get(id=site_id)
except Site.DoesNotExist: except Site.DoesNotExist:
return Response({'error': f'Site with id {site_id} does not exist'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error=f'Site with id {site_id} does not exist',
status_code=status.HTTP_400_BAD_REQUEST
)
# Sector ID is REQUIRED # Sector ID is REQUIRED
if not sector_id: if not sector_id:
return Response({'error': 'sector_id is required'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='sector_id is required',
status_code=status.HTTP_400_BAD_REQUEST
)
try: try:
sector = Sector.objects.get(id=sector_id) sector = Sector.objects.get(id=sector_id)
if sector.site_id != site_id: if sector.site_id != site_id:
return Response({'error': 'Sector does not belong to the selected site'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='Sector does not belong to the selected site',
status_code=status.HTTP_400_BAD_REQUEST
)
except Sector.DoesNotExist: except Sector.DoesNotExist:
return Response({'error': f'Sector with id {sector_id} does not exist'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error=f'Sector with id {sector_id} does not exist',
status_code=status.HTTP_400_BAD_REQUEST
)
# Get account # Get account
account = getattr(request, 'account', None) account = getattr(request, 'account', None)
@@ -461,17 +521,20 @@ class KeywordViewSet(SiteSectorModelViewSet):
errors.append(f"Row {row_num}: {str(e)}") errors.append(f"Row {row_num}: {str(e)}")
continue continue
return Response({ return success_response(
'success': True, data={
'imported': imported_count, 'imported': imported_count,
'skipped': skipped_count, 'skipped': skipped_count,
'errors': errors[:10] if errors else [] # Limit errors to first 10 'errors': errors[:10] if errors else [] # Limit errors to first 10
}, status=status.HTTP_200_OK) },
message=f'Successfully imported {imported_count} keyword(s)'
)
except Exception as e: except Exception as e:
return Response({ return error_response(
'error': f'Failed to parse CSV: {str(e)}' error=f'Failed to parse CSV: {str(e)}',
}, status=status.HTTP_400_BAD_REQUEST) status_code=status.HTTP_400_BAD_REQUEST
)
@action(detail=False, methods=['post'], url_path='auto_cluster', url_name='auto_cluster') @action(detail=False, methods=['post'], url_path='auto_cluster', url_name='auto_cluster')
def auto_cluster(self, request): def auto_cluster(self, request):
@@ -497,16 +560,16 @@ class KeywordViewSet(SiteSectorModelViewSet):
# Validate basic input # Validate basic input
if not payload['ids']: if not payload['ids']:
return Response({ return error_response(
'success': False, error='No IDs provided',
'error': 'No IDs provided' status_code=status.HTTP_400_BAD_REQUEST
}, status=status.HTTP_400_BAD_REQUEST) )
if len(payload['ids']) > 20: if len(payload['ids']) > 20:
return Response({ return error_response(
'success': False, error='Maximum 20 keywords allowed for clustering',
'error': 'Maximum 20 keywords allowed for clustering' status_code=status.HTTP_400_BAD_REQUEST
}, status=status.HTTP_400_BAD_REQUEST) )
# Try to queue Celery task # Try to queue Celery task
try: try:
@@ -517,11 +580,12 @@ class KeywordViewSet(SiteSectorModelViewSet):
account_id=account_id account_id=account_id
) )
logger.info(f"Task queued: {task.id}") logger.info(f"Task queued: {task.id}")
return Response({ return success_response(
'success': True, data={
'task_id': str(task.id), 'task_id': str(task.id)
'message': 'Clustering started' },
}, status=status.HTTP_200_OK) message='Clustering started'
)
else: else:
# Celery not available - execute synchronously # Celery not available - execute synchronously
logger.warning("Celery not available, executing synchronously") logger.warning("Celery not available, executing synchronously")
@@ -531,15 +595,15 @@ class KeywordViewSet(SiteSectorModelViewSet):
account_id=account_id account_id=account_id
) )
if result.get('success'): if result.get('success'):
return Response({ return success_response(
'success': True, data=result,
**result message='Clustering completed successfully'
}, status=status.HTTP_200_OK) )
else: else:
return Response({ return error_response(
'success': False, error=result.get('error', 'Clustering failed'),
'error': result.get('error', 'Clustering failed') status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
except (KombuOperationalError, ConnectionError) as e: except (KombuOperationalError, ConnectionError) as e:
# Broker connection failed - fall back to synchronous execution # Broker connection failed - fall back to synchronous execution
logger.warning(f"Celery broker unavailable, falling back to synchronous execution: {str(e)}") logger.warning(f"Celery broker unavailable, falling back to synchronous execution: {str(e)}")
@@ -549,27 +613,27 @@ class KeywordViewSet(SiteSectorModelViewSet):
account_id=account_id account_id=account_id
) )
if result.get('success'): if result.get('success'):
return Response({ return success_response(
'success': True, data=result,
**result message='Clustering completed successfully'
}, status=status.HTTP_200_OK) )
else: else:
return Response({ return error_response(
'success': False, error=result.get('error', 'Clustering failed'),
'error': result.get('error', 'Clustering failed') status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
except Exception as e: except Exception as e:
logger.error(f"Error in auto_cluster: {str(e)}", exc_info=True) logger.error(f"Error in auto_cluster: {str(e)}", exc_info=True)
return Response({ return error_response(
'success': False, error=str(e),
'error': str(e) status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
except Exception as e: except Exception as e:
logger.error(f"Unexpected error in auto_cluster: {str(e)}", exc_info=True) logger.error(f"Unexpected error in auto_cluster: {str(e)}", exc_info=True)
return Response({ return error_response(
'success': False, error=f'Unexpected error: {str(e)}',
'error': f'Unexpected error: {str(e)}' status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
class ClusterViewSet(SiteSectorModelViewSet): class ClusterViewSet(SiteSectorModelViewSet):
@@ -719,12 +783,18 @@ class ClusterViewSet(SiteSectorModelViewSet):
"""Bulk delete clusters""" """Bulk delete clusters"""
ids = request.data.get('ids', []) ids = request.data.get('ids', [])
if not ids: if not ids:
return Response({'error': 'No IDs provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No IDs provided',
status_code=status.HTTP_400_BAD_REQUEST
)
queryset = self.get_queryset() queryset = self.get_queryset()
deleted_count, _ = queryset.filter(id__in=ids).delete() deleted_count, _ = queryset.filter(id__in=ids).delete()
return Response({'deleted_count': deleted_count}, status=status.HTTP_200_OK) return success_response(
data={'deleted_count': deleted_count},
message=f'Successfully deleted {deleted_count} cluster(s)'
)
@action(detail=False, methods=['post'], url_path='auto_generate_ideas', url_name='auto_generate_ideas') @action(detail=False, methods=['post'], url_path='auto_generate_ideas', url_name='auto_generate_ideas')
def auto_generate_ideas(self, request): def auto_generate_ideas(self, request):
@@ -749,16 +819,16 @@ class ClusterViewSet(SiteSectorModelViewSet):
# Validate basic input # Validate basic input
if not payload['ids']: if not payload['ids']:
return Response({ return error_response(
'success': False, error='No IDs provided',
'error': 'No IDs provided' status_code=status.HTTP_400_BAD_REQUEST
}, status=status.HTTP_400_BAD_REQUEST) )
if len(payload['ids']) > 10: if len(payload['ids']) > 10:
return Response({ return error_response(
'success': False, error='Maximum 10 clusters allowed for idea generation',
'error': 'Maximum 10 clusters allowed for idea generation' status_code=status.HTTP_400_BAD_REQUEST
}, status=status.HTTP_400_BAD_REQUEST) )
# Try to queue Celery task # Try to queue Celery task
try: try:
@@ -769,11 +839,12 @@ class ClusterViewSet(SiteSectorModelViewSet):
account_id=account_id account_id=account_id
) )
logger.info(f"Task queued: {task.id}") logger.info(f"Task queued: {task.id}")
return Response({ return success_response(
'success': True, data={
'task_id': str(task.id), 'task_id': str(task.id)
'message': 'Idea generation started' },
}, status=status.HTTP_200_OK) message='Idea generation started'
)
else: else:
# Celery not available - execute synchronously # Celery not available - execute synchronously
logger.warning("Celery not available, executing synchronously") logger.warning("Celery not available, executing synchronously")
@@ -783,15 +854,15 @@ class ClusterViewSet(SiteSectorModelViewSet):
account_id=account_id account_id=account_id
) )
if result.get('success'): if result.get('success'):
return Response({ return success_response(
'success': True, data=result,
**result message='Idea generation completed successfully'
}, status=status.HTTP_200_OK) )
else: else:
return Response({ return error_response(
'success': False, error=result.get('error', 'Idea generation failed'),
'error': result.get('error', 'Idea generation failed') status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
except (KombuOperationalError, ConnectionError) as e: except (KombuOperationalError, ConnectionError) as e:
# Broker connection failed - fall back to synchronous execution # Broker connection failed - fall back to synchronous execution
logger.warning(f"Celery broker unavailable, falling back to synchronous execution: {str(e)}") logger.warning(f"Celery broker unavailable, falling back to synchronous execution: {str(e)}")
@@ -801,27 +872,27 @@ class ClusterViewSet(SiteSectorModelViewSet):
account_id=account_id account_id=account_id
) )
if result.get('success'): if result.get('success'):
return Response({ return success_response(
'success': True, data=result,
**result message='Idea generation completed successfully'
}, status=status.HTTP_200_OK) )
else: else:
return Response({ return error_response(
'success': False, error=result.get('error', 'Idea generation failed'),
'error': result.get('error', 'Idea generation failed') status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
except Exception as e: except Exception as e:
logger.error(f"Error in auto_generate_ideas: {str(e)}", exc_info=True) logger.error(f"Error in auto_generate_ideas: {str(e)}", exc_info=True)
return Response({ return error_response(
'success': False, error=str(e),
'error': str(e) status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
except Exception as e: except Exception as e:
logger.error(f"Unexpected error in auto_generate_ideas: {str(e)}", exc_info=True) logger.error(f"Unexpected error in auto_generate_ideas: {str(e)}", exc_info=True)
return Response({ return error_response(
'success': False, error=f'Unexpected error: {str(e)}',
'error': f'Unexpected error: {str(e)}' status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
def list(self, request, *args, **kwargs): def list(self, request, *args, **kwargs):
""" """
@@ -919,19 +990,28 @@ class ContentIdeasViewSet(SiteSectorModelViewSet):
"""Bulk delete content ideas""" """Bulk delete content ideas"""
ids = request.data.get('ids', []) ids = request.data.get('ids', [])
if not ids: if not ids:
return Response({'error': 'No IDs provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No IDs provided',
status_code=status.HTTP_400_BAD_REQUEST
)
queryset = self.get_queryset() queryset = self.get_queryset()
deleted_count, _ = queryset.filter(id__in=ids).delete() deleted_count, _ = queryset.filter(id__in=ids).delete()
return Response({'deleted_count': deleted_count}, status=status.HTTP_200_OK) return success_response(
data={'deleted_count': deleted_count},
message=f'Successfully deleted {deleted_count} content idea(s)'
)
@action(detail=False, methods=['post'], url_path='bulk_queue_to_writer', url_name='bulk_queue_to_writer') @action(detail=False, methods=['post'], url_path='bulk_queue_to_writer', url_name='bulk_queue_to_writer')
def bulk_queue_to_writer(self, request): def bulk_queue_to_writer(self, request):
"""Queue ideas to writer by creating Tasks""" """Queue ideas to writer by creating Tasks"""
ids = request.data.get('ids', []) ids = request.data.get('ids', [])
if not ids: if not ids:
return Response({'error': 'No IDs provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No IDs provided',
status_code=status.HTTP_400_BAD_REQUEST
)
queryset = self.get_queryset() queryset = self.get_queryset()
ideas = queryset.filter(id__in=ids, status='new') # Only queue 'new' ideas ideas = queryset.filter(id__in=ids, status='new') # Only queue 'new' ideas
@@ -958,11 +1038,12 @@ class ContentIdeasViewSet(SiteSectorModelViewSet):
idea.status = 'scheduled' idea.status = 'scheduled'
idea.save() idea.save()
return Response({ return success_response(
'success': True, data={
'created_count': len(created_tasks), 'created_count': len(created_tasks),
'task_ids': created_tasks, 'task_ids': created_tasks
'message': f'Successfully queued {len(created_tasks)} ideas to writer' },
}, status=status.HTTP_200_OK) message=f'Successfully queued {len(created_tasks)} ideas to writer'
)
# REMOVED: generate_idea action - idea generation function removed # REMOVED: generate_idea action - idea generation function removed

View File

@@ -6,6 +6,7 @@ from django.db import transaction, models
from django.db.models import Q from django.db.models import Q
from igny8_core.api.base import SiteSectorModelViewSet from igny8_core.api.base import SiteSectorModelViewSet
from igny8_core.api.pagination import CustomPageNumberPagination from igny8_core.api.pagination import CustomPageNumberPagination
from igny8_core.api.response import success_response, error_response
from .models import Tasks, Images, Content from .models import Tasks, Images, Content
from .serializers import TasksSerializer, ImagesSerializer, ContentSerializer from .serializers import TasksSerializer, ImagesSerializer, ContentSerializer
@@ -84,12 +85,18 @@ class TasksViewSet(SiteSectorModelViewSet):
"""Bulk delete tasks""" """Bulk delete tasks"""
ids = request.data.get('ids', []) ids = request.data.get('ids', [])
if not ids: if not ids:
return Response({'error': 'No IDs provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No IDs provided',
status_code=status.HTTP_400_BAD_REQUEST
)
queryset = self.get_queryset() queryset = self.get_queryset()
deleted_count, _ = queryset.filter(id__in=ids).delete() deleted_count, _ = queryset.filter(id__in=ids).delete()
return Response({'deleted_count': deleted_count}, status=status.HTTP_200_OK) return success_response(
data={'deleted_count': deleted_count},
message=f'Successfully deleted {deleted_count} task(s)'
)
@action(detail=False, methods=['post'], url_path='bulk_update', url_name='bulk_update') @action(detail=False, methods=['post'], url_path='bulk_update', url_name='bulk_update')
def bulk_update(self, request): def bulk_update(self, request):
@@ -98,14 +105,23 @@ class TasksViewSet(SiteSectorModelViewSet):
status_value = request.data.get('status') status_value = request.data.get('status')
if not ids: if not ids:
return Response({'error': 'No IDs provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No IDs provided',
status_code=status.HTTP_400_BAD_REQUEST
)
if not status_value: if not status_value:
return Response({'error': 'No status provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No status provided',
status_code=status.HTTP_400_BAD_REQUEST
)
queryset = self.get_queryset() queryset = self.get_queryset()
updated_count = queryset.filter(id__in=ids).update(status=status_value) updated_count = queryset.filter(id__in=ids).update(status=status_value)
return Response({'updated_count': updated_count}, status=status.HTTP_200_OK) return success_response(
data={'updated_count': updated_count},
message=f'Successfully updated {updated_count} task(s)'
)
@action(detail=False, methods=['post'], url_path='auto_generate_content', url_name='auto_generate_content') @action(detail=False, methods=['post'], url_path='auto_generate_content', url_name='auto_generate_content')
def auto_generate_content(self, request): def auto_generate_content(self, request):
@@ -120,17 +136,17 @@ class TasksViewSet(SiteSectorModelViewSet):
ids = request.data.get('ids', []) ids = request.data.get('ids', [])
if not ids: if not ids:
logger.warning("auto_generate_content: No IDs provided") logger.warning("auto_generate_content: No IDs provided")
return Response({ return error_response(
'error': 'No IDs provided', error='No IDs provided',
'type': 'ValidationError' status_code=status.HTTP_400_BAD_REQUEST
}, status=status.HTTP_400_BAD_REQUEST) )
if len(ids) > 10: if len(ids) > 10:
logger.warning(f"auto_generate_content: Too many IDs provided: {len(ids)}") logger.warning(f"auto_generate_content: Too many IDs provided: {len(ids)}")
return Response({ return error_response(
'error': 'Maximum 10 tasks allowed for content generation', error='Maximum 10 tasks allowed for content generation',
'type': 'ValidationError' status_code=status.HTTP_400_BAD_REQUEST
}, status=status.HTTP_400_BAD_REQUEST) )
logger.info(f"auto_generate_content: Processing {len(ids)} task IDs: {ids}") logger.info(f"auto_generate_content: Processing {len(ids)} task IDs: {ids}")
@@ -151,11 +167,10 @@ class TasksViewSet(SiteSectorModelViewSet):
if existing_count == 0: if existing_count == 0:
logger.error(f"auto_generate_content: No tasks found for IDs: {ids}") logger.error(f"auto_generate_content: No tasks found for IDs: {ids}")
return Response({ return error_response(
'error': f'No tasks found for the provided IDs: {ids}', error=f'No tasks found for the provided IDs: {ids}',
'type': 'NotFound', status_code=status.HTTP_404_NOT_FOUND
'requested_ids': ids )
}, status=status.HTTP_404_NOT_FOUND)
if existing_count < len(ids): if existing_count < len(ids):
missing_ids = set(ids) - set(existing_ids) missing_ids = set(ids) - set(existing_ids)
@@ -171,11 +186,10 @@ class TasksViewSet(SiteSectorModelViewSet):
logger.error(f" - Account ID: {account_id}") logger.error(f" - Account ID: {account_id}")
logger.error("=" * 80, exc_info=True) logger.error("=" * 80, exc_info=True)
return Response({ return error_response(
'error': f'Database error while querying tasks: {str(db_error)}', error=f'Database error while querying tasks: {str(db_error)}',
'type': 'OperationalError', status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
'details': 'Failed to retrieve tasks from database. Please check database connection and try again.' )
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
# Try to queue Celery task, fall back to synchronous if Celery not available # Try to queue Celery task, fall back to synchronous if Celery not available
try: try:
@@ -192,11 +206,10 @@ class TasksViewSet(SiteSectorModelViewSet):
account_id=account_id account_id=account_id
) )
logger.info(f"auto_generate_content: Celery task queued successfully: {task.id}") logger.info(f"auto_generate_content: Celery task queued successfully: {task.id}")
return Response({ return success_response(
'success': True, data={'task_id': str(task.id)},
'task_id': str(task.id), message='Content generation started'
'message': 'Content generation started' )
}, status=status.HTTP_200_OK)
except KombuOperationalError as celery_error: except KombuOperationalError as celery_error:
logger.error("=" * 80) logger.error("=" * 80)
logger.error("CELERY ERROR: Failed to queue task") logger.error("CELERY ERROR: Failed to queue task")
@@ -206,10 +219,10 @@ class TasksViewSet(SiteSectorModelViewSet):
logger.error(f" - Account ID: {account_id}") logger.error(f" - Account ID: {account_id}")
logger.error("=" * 80, exc_info=True) logger.error("=" * 80, exc_info=True)
return Response({ return error_response(
'error': 'Task queue unavailable. Please try again.', error='Task queue unavailable. Please try again.',
'type': 'QueueError' status_code=status.HTTP_503_SERVICE_UNAVAILABLE
}, status=status.HTTP_503_SERVICE_UNAVAILABLE) )
except Exception as celery_error: except Exception as celery_error:
logger.error("=" * 80) logger.error("=" * 80)
logger.error("CELERY ERROR: Failed to queue task") logger.error("CELERY ERROR: Failed to queue task")
@@ -227,16 +240,15 @@ class TasksViewSet(SiteSectorModelViewSet):
account_id=account_id account_id=account_id
) )
if result.get('success'): if result.get('success'):
return Response({ return success_response(
'success': True, data={'tasks_updated': result.get('count', 0)},
'tasks_updated': result.get('count', 0), message='Content generated successfully (synchronous)'
'message': 'Content generated successfully (synchronous)' )
}, status=status.HTTP_200_OK)
else: else:
return Response({ return error_response(
'error': result.get('error', 'Content generation failed'), error=result.get('error', 'Content generation failed'),
'type': 'TaskExecutionError' status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
else: else:
# Celery not available - execute synchronously # Celery not available - execute synchronously
logger.info(f"auto_generate_content: Executing synchronously (Celery not available)") logger.info(f"auto_generate_content: Executing synchronously (Celery not available)")
@@ -247,17 +259,16 @@ class TasksViewSet(SiteSectorModelViewSet):
) )
if result.get('success'): if result.get('success'):
logger.info(f"auto_generate_content: Synchronous execution successful: {result.get('count', 0)} tasks updated") logger.info(f"auto_generate_content: Synchronous execution successful: {result.get('count', 0)} tasks updated")
return Response({ return success_response(
'success': True, data={'tasks_updated': result.get('count', 0)},
'tasks_updated': result.get('count', 0), message='Content generated successfully'
'message': 'Content generated successfully' )
}, status=status.HTTP_200_OK)
else: else:
logger.error(f"auto_generate_content: Synchronous execution failed: {result.get('error', 'Unknown error')}") logger.error(f"auto_generate_content: Synchronous execution failed: {result.get('error', 'Unknown error')}")
return Response({ return error_response(
'error': result.get('error', 'Content generation failed'), error=result.get('error', 'Content generation failed'),
'type': 'TaskExecutionError' status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
except ImportError as import_error: except ImportError as import_error:
logger.error(f"auto_generate_content: ImportError - tasks module not available: {str(import_error)}") logger.error(f"auto_generate_content: ImportError - tasks module not available: {str(import_error)}")
@@ -268,21 +279,20 @@ class TasksViewSet(SiteSectorModelViewSet):
updated_count = tasks.update(status='completed', content='[AI content generation not available]') updated_count = tasks.update(status='completed', content='[AI content generation not available]')
logger.info(f"auto_generate_content: Updated {updated_count} tasks (AI generation not available)") logger.info(f"auto_generate_content: Updated {updated_count} tasks (AI generation not available)")
return Response({ return success_response(
'updated_count': updated_count, data={'updated_count': updated_count},
'message': 'Tasks updated (AI generation not available)' message='Tasks updated (AI generation not available)'
}, status=status.HTTP_200_OK) )
except (OperationalError, DatabaseError) as db_error: except (OperationalError, DatabaseError) as db_error:
logger.error("=" * 80) logger.error("=" * 80)
logger.error("DATABASE ERROR: Failed to update tasks") logger.error("DATABASE ERROR: Failed to update tasks")
logger.error(f" - Error type: {type(db_error).__name__}") logger.error(f" - Error type: {type(db_error).__name__}")
logger.error(f" - Error message: {str(db_error)}") logger.error(f" - Error message: {str(db_error)}")
logger.error("=" * 80, exc_info=True) logger.error("=" * 80, exc_info=True)
return Response({ return error_response(
'error': f'Database error while updating tasks: {str(db_error)}', error=f'Database error while updating tasks: {str(db_error)}',
'type': 'OperationalError', status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
'details': 'Failed to update tasks in database. Please check database connection.' )
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
except (OperationalError, DatabaseError) as db_error: except (OperationalError, DatabaseError) as db_error:
logger.error("=" * 80) logger.error("=" * 80)
@@ -293,11 +303,10 @@ class TasksViewSet(SiteSectorModelViewSet):
logger.error(f" - Account ID: {account_id}") logger.error(f" - Account ID: {account_id}")
logger.error("=" * 80, exc_info=True) logger.error("=" * 80, exc_info=True)
return Response({ return error_response(
'error': f'Database error during content generation: {str(db_error)}', error=f'Database error during content generation: {str(db_error)}',
'type': 'OperationalError', status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
'details': 'A database operation failed. This may be due to connection issues, constraint violations, or data integrity problems. Check the logs for more details.' )
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
except IntegrityError as integrity_error: except IntegrityError as integrity_error:
logger.error("=" * 80) logger.error("=" * 80)
@@ -306,18 +315,17 @@ class TasksViewSet(SiteSectorModelViewSet):
logger.error(f" - Task IDs: {ids}") logger.error(f" - Task IDs: {ids}")
logger.error("=" * 80, exc_info=True) logger.error("=" * 80, exc_info=True)
return Response({ return error_response(
'error': f'Data integrity error: {str(integrity_error)}', error=f'Data integrity error: {str(integrity_error)}',
'type': 'IntegrityError', status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
'details': 'The operation violated database constraints. This may indicate missing required relationships or invalid data.' )
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
except ValidationError as validation_error: except ValidationError as validation_error:
logger.error(f"auto_generate_content: ValidationError: {str(validation_error)}") logger.error(f"auto_generate_content: ValidationError: {str(validation_error)}")
return Response({ return error_response(
'error': f'Validation error: {str(validation_error)}', error=f'Validation error: {str(validation_error)}',
'type': 'ValidationError' status_code=status.HTTP_400_BAD_REQUEST
}, status=status.HTTP_400_BAD_REQUEST) )
except Exception as e: except Exception as e:
logger.error("=" * 80) logger.error("=" * 80)
@@ -328,11 +336,10 @@ class TasksViewSet(SiteSectorModelViewSet):
logger.error(f" - Account ID: {account_id}") logger.error(f" - Account ID: {account_id}")
logger.error("=" * 80, exc_info=True) logger.error("=" * 80, exc_info=True)
return Response({ return error_response(
'error': f'Unexpected error: {str(e)}', error=f'Unexpected error: {str(e)}',
'type': type(e).__name__, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
'details': 'An unexpected error occurred. Please check the logs for more details.' )
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
except Exception as outer_error: except Exception as outer_error:
logger.error("=" * 80) logger.error("=" * 80)
@@ -341,10 +348,10 @@ class TasksViewSet(SiteSectorModelViewSet):
logger.error(f" - Error message: {str(outer_error)}") logger.error(f" - Error message: {str(outer_error)}")
logger.error("=" * 80, exc_info=True) logger.error("=" * 80, exc_info=True)
return Response({ return error_response(
'error': f'Critical error: {str(outer_error)}', error=f'Critical error: {str(outer_error)}',
'type': type(outer_error).__name__ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
class ImagesViewSet(SiteSectorModelViewSet): class ImagesViewSet(SiteSectorModelViewSet):
@@ -383,30 +390,34 @@ class ImagesViewSet(SiteSectorModelViewSet):
try: try:
image = Images.objects.get(pk=pk) image = Images.objects.get(pk=pk)
except Images.DoesNotExist: except Images.DoesNotExist:
return Response({ return error_response(
'error': 'Image not found' error='Image not found',
}, status=status.HTTP_404_NOT_FOUND) status_code=status.HTTP_404_NOT_FOUND
)
# Check if image has a local path # Check if image has a local path
if not image.image_path: if not image.image_path:
return Response({ return error_response(
'error': 'No local file path available for this image' error='No local file path available for this image',
}, status=status.HTTP_404_NOT_FOUND) status_code=status.HTTP_404_NOT_FOUND
)
file_path = image.image_path file_path = image.image_path
# Verify file exists at the saved path # Verify file exists at the saved path
if not os.path.exists(file_path): if not os.path.exists(file_path):
logger.error(f"[serve_image_file] Image {pk} - File not found at saved path: {file_path}") logger.error(f"[serve_image_file] Image {pk} - File not found at saved path: {file_path}")
return Response({ return error_response(
'error': f'Image file not found at: {file_path}' error=f'Image file not found at: {file_path}',
}, status=status.HTTP_404_NOT_FOUND) status_code=status.HTTP_404_NOT_FOUND
)
# Check if file is readable # Check if file is readable
if not os.access(file_path, os.R_OK): if not os.access(file_path, os.R_OK):
return Response({ return error_response(
'error': 'Image file is not readable' error='Image file is not readable',
}, status=status.HTTP_403_FORBIDDEN) status_code=status.HTTP_403_FORBIDDEN
)
# Determine content type from file extension # Determine content type from file extension
import mimetypes import mimetypes
@@ -422,31 +433,40 @@ class ImagesViewSet(SiteSectorModelViewSet):
filename=os.path.basename(file_path) filename=os.path.basename(file_path)
) )
except Exception as e: except Exception as e:
return Response({ return error_response(
'error': f'Failed to serve file: {str(e)}' error=f'Failed to serve file: {str(e)}',
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
)
except Images.DoesNotExist: except Images.DoesNotExist:
return Response({ return error_response(
'error': 'Image not found' error='Image not found',
}, status=status.HTTP_404_NOT_FOUND) status_code=status.HTTP_404_NOT_FOUND
)
except Exception as e: except Exception as e:
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.error(f"Error serving image file: {str(e)}", exc_info=True) logger.error(f"Error serving image file: {str(e)}", exc_info=True)
return Response({ return error_response(
'error': f'Failed to serve image: {str(e)}' error=f'Failed to serve image: {str(e)}',
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
)
@action(detail=False, methods=['post'], url_path='auto_generate', url_name='auto_generate_images') @action(detail=False, methods=['post'], url_path='auto_generate', url_name='auto_generate_images')
def auto_generate_images(self, request): def auto_generate_images(self, request):
"""Auto-generate images for tasks using AI""" """Auto-generate images for tasks using AI"""
task_ids = request.data.get('task_ids', []) task_ids = request.data.get('task_ids', [])
if not task_ids: if not task_ids:
return Response({'error': 'No task IDs provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No task IDs provided',
status_code=status.HTTP_400_BAD_REQUEST
)
if len(task_ids) > 10: if len(task_ids) > 10:
return Response({'error': 'Maximum 10 tasks allowed for image generation'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='Maximum 10 tasks allowed for image generation',
status_code=status.HTTP_400_BAD_REQUEST
)
# Get account # Get account
account = getattr(request, 'account', None) account = getattr(request, 'account', None)
@@ -464,11 +484,10 @@ class ImagesViewSet(SiteSectorModelViewSet):
payload={'ids': task_ids}, payload={'ids': task_ids},
account_id=account_id account_id=account_id
) )
return Response({ return success_response(
'success': True, data={'task_id': str(task.id)},
'task_id': str(task.id), message='Image generation started'
'message': 'Image generation started' )
}, status=status.HTTP_200_OK)
else: else:
# Celery not available - execute synchronously # Celery not available - execute synchronously
result = run_ai_task( result = run_ai_task(
@@ -477,33 +496,34 @@ class ImagesViewSet(SiteSectorModelViewSet):
account_id=account_id account_id=account_id
) )
if result.get('success'): if result.get('success'):
return Response({ return success_response(
'success': True, data={'images_created': result.get('count', 0)},
'images_created': result.get('count', 0), message=result.get('message', 'Image generation completed')
'message': result.get('message', 'Image generation completed') )
}, status=status.HTTP_200_OK)
else: else:
return Response({ return error_response(
'error': result.get('error', 'Image generation failed') error=result.get('error', 'Image generation failed'),
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
)
except KombuOperationalError as e: except KombuOperationalError as e:
return Response({ return error_response(
'error': 'Task queue unavailable. Please try again.', error='Task queue unavailable. Please try again.',
'type': 'QueueError' status_code=status.HTTP_503_SERVICE_UNAVAILABLE
}, status=status.HTTP_503_SERVICE_UNAVAILABLE) )
except ImportError: except ImportError:
# Tasks module not available # Tasks module not available
return Response({ return error_response(
'error': 'Image generation task not available' error='Image generation task not available',
}, status=status.HTTP_503_SERVICE_UNAVAILABLE) status_code=status.HTTP_503_SERVICE_UNAVAILABLE
)
except Exception as e: except Exception as e:
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.error(f"Error queuing image generation task: {str(e)}", exc_info=True) logger.error(f"Error queuing image generation task: {str(e)}", exc_info=True)
return Response({ return error_response(
'error': f'Failed to start image generation: {str(e)}', error=f'Failed to start image generation: {str(e)}',
'type': 'TaskError' status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
@action(detail=False, methods=['post'], url_path='bulk_update', url_name='bulk_update') @action(detail=False, methods=['post'], url_path='bulk_update', url_name='bulk_update')
def bulk_update(self, request): def bulk_update(self, request):
@@ -518,7 +538,10 @@ class ImagesViewSet(SiteSectorModelViewSet):
status_value = request.data.get('status') status_value = request.data.get('status')
if not status_value: if not status_value:
return Response({'error': 'No status provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='No status provided',
status_code=status.HTTP_400_BAD_REQUEST
)
queryset = self.get_queryset() queryset = self.get_queryset()
@@ -534,13 +557,22 @@ class ImagesViewSet(SiteSectorModelViewSet):
Q(content=content) | Q(task=content.task) Q(content=content) | Q(task=content.task)
).update(status=status_value) ).update(status=status_value)
except Content.DoesNotExist: except Content.DoesNotExist:
return Response({'error': 'Content not found'}, status=status.HTTP_404_NOT_FOUND) return error_response(
error='Content not found',
status_code=status.HTTP_404_NOT_FOUND
)
elif image_ids: elif image_ids:
updated_count = queryset.filter(id__in=image_ids).update(status=status_value) updated_count = queryset.filter(id__in=image_ids).update(status=status_value)
else: else:
return Response({'error': 'Either content_id or ids must be provided'}, status=status.HTTP_400_BAD_REQUEST) return error_response(
error='Either content_id or ids must be provided',
status_code=status.HTTP_400_BAD_REQUEST
)
return Response({'updated_count': updated_count}, status=status.HTTP_200_OK) return success_response(
data={'updated_count': updated_count},
message=f'Successfully updated {updated_count} image(s)'
)
@action(detail=False, methods=['get'], url_path='content_images', url_name='content_images') @action(detail=False, methods=['get'], url_path='content_images', url_name='content_images')
def content_images(self, request): def content_images(self, request):
@@ -621,10 +653,12 @@ class ImagesViewSet(SiteSectorModelViewSet):
# Sort by content title # Sort by content title
grouped_data.sort(key=lambda x: x['content_title']) grouped_data.sort(key=lambda x: x['content_title'])
return Response({ return success_response(
'count': len(grouped_data), data={
'results': grouped_data 'count': len(grouped_data),
}, status=status.HTTP_200_OK) 'results': grouped_data
}
)
@action(detail=False, methods=['post'], url_path='generate_images', url_name='generate_images') @action(detail=False, methods=['post'], url_path='generate_images', url_name='generate_images')
def generate_images(self, request): def generate_images(self, request):
@@ -636,10 +670,10 @@ class ImagesViewSet(SiteSectorModelViewSet):
content_id = request.data.get('content_id') content_id = request.data.get('content_id')
if not image_ids: if not image_ids:
return Response({ return error_response(
'error': 'No image IDs provided', error='No image IDs provided',
'type': 'ValidationError' status_code=status.HTTP_400_BAD_REQUEST
}, status=status.HTTP_400_BAD_REQUEST) )
account_id = account.id if account else None account_id = account.id if account else None
@@ -651,11 +685,10 @@ class ImagesViewSet(SiteSectorModelViewSet):
account_id=account_id, account_id=account_id,
content_id=content_id content_id=content_id
) )
return Response({ return success_response(
'success': True, data={'task_id': str(task.id)},
'task_id': str(task.id), message='Image generation started'
'message': 'Image generation started' )
}, status=status.HTTP_200_OK)
else: else:
# Fallback to synchronous execution (for testing) # Fallback to synchronous execution (for testing)
result = process_image_generation_queue( result = process_image_generation_queue(
@@ -663,13 +696,19 @@ class ImagesViewSet(SiteSectorModelViewSet):
account_id=account_id, account_id=account_id,
content_id=content_id content_id=content_id
) )
return Response(result, status=status.HTTP_200_OK) if result.get('success'):
return success_response(data=result)
else:
return error_response(
error=result.get('error', 'Image generation failed'),
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
)
except Exception as e: except Exception as e:
logger.error(f"[generate_images] Error: {str(e)}", exc_info=True) logger.error(f"[generate_images] Error: {str(e)}", exc_info=True)
return Response({ return error_response(
'error': str(e), error=str(e),
'type': 'ExecutionError' status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
class ContentViewSet(SiteSectorModelViewSet): class ContentViewSet(SiteSectorModelViewSet):
""" """
@@ -702,10 +741,10 @@ class ContentViewSet(SiteSectorModelViewSet):
ids = request.data.get('ids', []) ids = request.data.get('ids', [])
if not ids: if not ids:
return Response({ return error_response(
'error': 'No IDs provided', error='No IDs provided',
'type': 'ValidationError' status_code=status.HTTP_400_BAD_REQUEST
}, status=status.HTTP_400_BAD_REQUEST) )
account_id = account.id if account else None account_id = account.id if account else None
@@ -717,11 +756,10 @@ class ContentViewSet(SiteSectorModelViewSet):
payload={'ids': ids}, payload={'ids': ids},
account_id=account_id account_id=account_id
) )
return Response({ return success_response(
'success': True, data={'task_id': str(task.id)},
'task_id': str(task.id), message='Image prompt generation started'
'message': 'Image prompt generation started' )
}, status=status.HTTP_200_OK)
else: else:
# Fallback to synchronous execution # Fallback to synchronous execution
result = run_ai_task( result = run_ai_task(
@@ -730,19 +768,18 @@ class ContentViewSet(SiteSectorModelViewSet):
account_id=account_id account_id=account_id
) )
if result.get('success'): if result.get('success'):
return Response({ return success_response(
'success': True, data={'prompts_created': result.get('count', 0)},
'prompts_created': result.get('count', 0), message='Image prompts generated successfully'
'message': 'Image prompts generated successfully' )
}, status=status.HTTP_200_OK)
else: else:
return Response({ return error_response(
'error': result.get('error', 'Image prompt generation failed'), error=result.get('error', 'Image prompt generation failed'),
'type': 'TaskExecutionError' status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )
except Exception as e: except Exception as e:
return Response({ return error_response(
'error': str(e), error=str(e),
'type': 'ExecutionError' status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) )