autoamtiona nd other pages udpates,

This commit is contained in:
IGNY8 VPS (Salman)
2026-01-01 01:40:34 +00:00
parent a02e485f7d
commit 0d3e25e50f
11 changed files with 701 additions and 434 deletions

View File

@@ -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