autoamtiona nd other pages udpates,
This commit is contained in:
@@ -152,10 +152,12 @@ class AutomationService:
|
||||
start_time = time.time()
|
||||
|
||||
# Query pending keywords
|
||||
# FIXED: Match pipeline_overview query - use status='new' only
|
||||
# Keywords with status='new' are ready for clustering, regardless of cluster FK
|
||||
# (If cluster FK is set but status='new', it means the old cluster was deleted)
|
||||
pending_keywords = Keywords.objects.filter(
|
||||
site=self.site,
|
||||
status='new',
|
||||
cluster__isnull=True,
|
||||
disabled=False
|
||||
)
|
||||
|
||||
@@ -411,10 +413,10 @@ class AutomationService:
|
||||
start_time = time.time()
|
||||
|
||||
# ADDED: Pre-stage validation - verify Stage 1 completion
|
||||
# FIXED: Match pipeline_overview query - use status='new' only
|
||||
pending_keywords = Keywords.objects.filter(
|
||||
site=self.site,
|
||||
status='new',
|
||||
cluster__isnull=True,
|
||||
disabled=False
|
||||
).count()
|
||||
|
||||
@@ -1138,6 +1140,26 @@ class AutomationService:
|
||||
self.run.run_id, self.account.id, self.site.id,
|
||||
stage_number, f"Content '{content.title}' complete ({content_processed}/{total_content})"
|
||||
)
|
||||
|
||||
# ADDED: Incremental save after each content piece for real-time frontend progress
|
||||
# This allows the frontend to show accurate progress during Stage 5
|
||||
current_prompts_created = Images.objects.filter(
|
||||
site=self.site,
|
||||
status='pending',
|
||||
created_at__gte=self.run.started_at
|
||||
).count()
|
||||
current_credits_used = self._get_credits_used() - credits_before
|
||||
current_time_elapsed = self._format_time_elapsed(start_time)
|
||||
self.run.stage_5_result = {
|
||||
'content_processed': content_processed,
|
||||
'content_total': total_content,
|
||||
'prompts_created': current_prompts_created,
|
||||
'credits_used': current_credits_used,
|
||||
'time_elapsed': current_time_elapsed,
|
||||
'in_progress': True
|
||||
}
|
||||
self.run.save(update_fields=['stage_5_result'])
|
||||
|
||||
except Exception as e:
|
||||
# FIXED: Log error but continue processing remaining content
|
||||
error_msg = f"Failed to extract prompts for content '{content.title}': {str(e)}"
|
||||
@@ -1441,9 +1463,14 @@ class AutomationService:
|
||||
time.sleep(delay)
|
||||
|
||||
def run_stage_7(self):
|
||||
"""Stage 7: Manual Review Gate (Count Only)"""
|
||||
"""Stage 7: Auto-Approve and Publish Review Content
|
||||
|
||||
This stage automatically approves content in 'review' status and
|
||||
marks it as 'published' (or queues for WordPress sync).
|
||||
"""
|
||||
stage_number = 7
|
||||
stage_name = "Manual Review Gate"
|
||||
stage_name = "Review → Published"
|
||||
start_time = time.time()
|
||||
|
||||
# Query content ready for review
|
||||
ready_for_review = Content.objects.filter(
|
||||
@@ -1452,7 +1479,6 @@ class AutomationService:
|
||||
)
|
||||
|
||||
total_count = ready_for_review.count()
|
||||
content_ids = list(ready_for_review.values_list('id', flat=True))
|
||||
|
||||
# Log stage start
|
||||
self.logger.log_stage_start(
|
||||
@@ -1460,22 +1486,129 @@ class AutomationService:
|
||||
stage_number, stage_name, total_count
|
||||
)
|
||||
|
||||
self.logger.log_stage_progress(
|
||||
self.run.run_id, self.account.id, self.site.id,
|
||||
stage_number, f"Automation complete. {total_count} content pieces ready for review"
|
||||
)
|
||||
|
||||
if content_ids:
|
||||
if total_count == 0:
|
||||
self.logger.log_stage_progress(
|
||||
self.run.run_id, self.account.id, self.site.id,
|
||||
stage_number, f"Content IDs ready: {content_ids[:10]}..." if len(content_ids) > 10 else f"Content IDs ready: {content_ids}"
|
||||
stage_number, "No content in review to approve - completing automation"
|
||||
)
|
||||
self.run.stage_7_result = {
|
||||
'ready_for_review': 0,
|
||||
'approved_count': 0,
|
||||
'content_ids': []
|
||||
}
|
||||
self.run.status = 'completed'
|
||||
self.run.completed_at = datetime.now()
|
||||
self.run.save()
|
||||
cache.delete(f'automation_lock_{self.site.id}')
|
||||
return
|
||||
|
||||
# Save results
|
||||
content_list = list(ready_for_review)
|
||||
approved_count = 0
|
||||
|
||||
# INITIAL SAVE: Set totals immediately
|
||||
self.run.stage_7_result = {
|
||||
'ready_for_review': total_count,
|
||||
'content_ids': content_ids
|
||||
'review_total': total_count,
|
||||
'approved_count': 0,
|
||||
'content_ids': [],
|
||||
'in_progress': True
|
||||
}
|
||||
self.run.save(update_fields=['stage_7_result'])
|
||||
|
||||
for idx, content in enumerate(content_list, 1):
|
||||
# Check if automation should stop (paused or cancelled)
|
||||
should_stop, reason = self._check_should_stop()
|
||||
if should_stop:
|
||||
self.logger.log_stage_progress(
|
||||
self.run.run_id, self.account.id, self.site.id,
|
||||
stage_number, f"Stage {reason} - saving progress ({approved_count} content approved)"
|
||||
)
|
||||
time_elapsed = self._format_time_elapsed(start_time)
|
||||
self.run.stage_7_result = {
|
||||
'ready_for_review': total_count,
|
||||
'review_total': total_count,
|
||||
'approved_count': approved_count,
|
||||
'content_ids': list(Content.objects.filter(
|
||||
site=self.site, status='published', updated_at__gte=self.run.started_at
|
||||
).values_list('id', flat=True)),
|
||||
'partial': True,
|
||||
'stopped_reason': reason,
|
||||
'time_elapsed': time_elapsed
|
||||
}
|
||||
self.run.save()
|
||||
return
|
||||
|
||||
try:
|
||||
self.logger.log_stage_progress(
|
||||
self.run.run_id, self.account.id, self.site.id,
|
||||
stage_number, f"Approving content {idx}/{total_count}: {content.title}"
|
||||
)
|
||||
|
||||
# Approve content by changing status to 'published'
|
||||
content.status = 'published'
|
||||
content.save(update_fields=['status', 'updated_at'])
|
||||
|
||||
approved_count += 1
|
||||
|
||||
self.logger.log_stage_progress(
|
||||
self.run.run_id, self.account.id, self.site.id,
|
||||
stage_number, f"Content '{content.title}' approved ({approved_count}/{total_count})"
|
||||
)
|
||||
|
||||
# Incremental save for real-time frontend progress
|
||||
current_time_elapsed = self._format_time_elapsed(start_time)
|
||||
self.run.stage_7_result = {
|
||||
'ready_for_review': total_count,
|
||||
'review_total': total_count,
|
||||
'approved_count': approved_count,
|
||||
'content_ids': [], # Don't store full list during processing
|
||||
'time_elapsed': current_time_elapsed,
|
||||
'in_progress': True
|
||||
}
|
||||
self.run.save(update_fields=['stage_7_result'])
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"Failed to approve content '{content.title}': {str(e)}"
|
||||
logger.error(f"[AutomationService] {error_msg}", exc_info=True)
|
||||
self.logger.log_stage_error(
|
||||
self.run.run_id, self.account.id, self.site.id,
|
||||
stage_number, error_msg
|
||||
)
|
||||
continue
|
||||
|
||||
# Small delay between approvals to prevent overwhelming the system
|
||||
if idx < total_count:
|
||||
time.sleep(0.5)
|
||||
|
||||
# Final results
|
||||
time_elapsed = self._format_time_elapsed(start_time)
|
||||
content_ids = list(Content.objects.filter(
|
||||
site=self.site,
|
||||
status='published',
|
||||
updated_at__gte=self.run.started_at
|
||||
).values_list('id', flat=True))
|
||||
|
||||
self.logger.log_stage_complete(
|
||||
self.run.run_id, self.account.id, self.site.id,
|
||||
stage_number, approved_count, time_elapsed, 0
|
||||
)
|
||||
|
||||
self.run.stage_7_result = {
|
||||
'ready_for_review': total_count,
|
||||
'review_total': total_count,
|
||||
'approved_count': approved_count,
|
||||
'content_ids': content_ids,
|
||||
'time_elapsed': time_elapsed,
|
||||
'in_progress': False
|
||||
}
|
||||
self.run.status = 'completed'
|
||||
self.run.completed_at = datetime.now()
|
||||
self.run.save()
|
||||
|
||||
# Release lock
|
||||
cache.delete(f'automation_lock_{self.site.id}')
|
||||
|
||||
logger.info(f"[AutomationService] Stage 7 complete: {approved_count} content pieces approved and published")
|
||||
self.run.status = 'completed'
|
||||
self.run.completed_at = datetime.now()
|
||||
self.run.save()
|
||||
@@ -1501,8 +1634,8 @@ class AutomationService:
|
||||
|
||||
def estimate_credits(self) -> int:
|
||||
"""Estimate total credits needed for automation"""
|
||||
# Count items
|
||||
keywords_count = Keywords.objects.filter(site=self.site, status='new', cluster__isnull=True, disabled=False).count()
|
||||
# Count items - FIXED: Match pipeline_overview query
|
||||
keywords_count = Keywords.objects.filter(site=self.site, status='new', disabled=False).count()
|
||||
clusters_count = Clusters.objects.filter(site=self.site, status='new').exclude(ideas__isnull=False).count()
|
||||
ideas_count = ContentIdeas.objects.filter(site=self.site, status='new').count()
|
||||
tasks_count = Tasks.objects.filter(site=self.site, status='queued').count()
|
||||
@@ -1526,8 +1659,9 @@ class AutomationService:
|
||||
This snapshot is used to calculate global progress percentage correctly.
|
||||
"""
|
||||
# Stage 1: Keywords pending clustering
|
||||
# FIXED: Match pipeline_overview query - use status='new' only
|
||||
stage_1_initial = Keywords.objects.filter(
|
||||
site=self.site, status='new', cluster__isnull=True, disabled=False
|
||||
site=self.site, status='new', disabled=False
|
||||
).count()
|
||||
|
||||
# Stage 2: Clusters needing ideas
|
||||
|
||||
Reference in New Issue
Block a user