/** * Automation API Service */ import { fetchAPI } from './api'; export interface AutomationConfig { is_enabled: boolean; frequency: 'daily' | 'weekly' | 'monthly'; scheduled_time: string; stage_1_enabled: boolean; stage_2_enabled: boolean; stage_3_enabled: boolean; stage_4_enabled: boolean; stage_5_enabled: boolean; stage_6_enabled: boolean; stage_7_enabled: boolean; stage_1_batch_size: number; stage_2_batch_size: number; stage_3_batch_size: number; stage_4_batch_size: number; stage_5_batch_size: number; stage_6_batch_size: number; within_stage_delay: number; between_stage_delay: number; last_run_at: string | null; next_run_at: string | null; } export interface StageResult { [key: string]: any; } export interface AutomationRun { run_id: string; status: 'running' | 'paused' | 'cancelled' | 'completed' | 'failed'; current_stage: number; trigger_type: 'manual' | 'scheduled'; started_at: string; completed_at?: string | null; paused_at?: string | null; resumed_at?: string | null; cancelled_at?: string | null; total_credits_used: number; stage_1_result: StageResult | null; stage_2_result: StageResult | null; stage_3_result: StageResult | null; stage_4_result: StageResult | null; stage_5_result: StageResult | null; stage_6_result: StageResult | null; stage_7_result: StageResult | null; } export interface RunHistoryItem { run_id: string; status: string; trigger_type: string; started_at: string; completed_at: string | null; total_credits_used: number; current_stage: number; } export interface PipelineStage { number: number; name: string; pending: number; type: 'AI' | 'Local' | 'Manual'; } export interface ProcessingItem { id: number; title: string; type: string; } export interface ProcessingState { stage_number: number; stage_name: string; stage_type: 'AI' | 'Local' | 'Manual'; total_items: number; processed_items: number; percentage: number; currently_processing: ProcessingItem[]; up_next: ProcessingItem[]; remaining_count: number; } export interface CurrentProcessingResponse { state: ProcessingState | null; total_credits_used: number; current_stage: number; } // NEW: Types for unified run_progress endpoint export interface StageProgress { number: number; name: string; type: 'AI' | 'Local' | 'Manual'; status: 'pending' | 'active' | 'completed' | 'skipped'; input_count: number; output_count: number; processed_count: number; progress_percentage: number; credits_used: number; time_elapsed: string; currently_processing?: ProcessingItem[]; up_next?: ProcessingItem[]; remaining_count?: number; } export interface GlobalProgress { total_items: number; completed_items: number; percentage: number; current_stage: number; total_stages: number; } export interface InitialSnapshot { stage_1_initial: number; stage_2_initial: number; stage_3_initial: number; stage_4_initial: number; stage_5_initial: number; stage_6_initial: number; stage_7_initial: number; total_initial_items: number; } export interface RunProgressResponse { run: { run_id: string; status: 'running' | 'paused' | 'cancelled' | 'completed' | 'failed'; current_stage: number; trigger_type: 'manual' | 'scheduled'; started_at: string; completed_at: string | null; paused_at: string | null; } | null; global_progress: GlobalProgress | null; stages: StageProgress[]; metrics: { credits_used: number; duration_seconds: number; errors: string[]; } | null; initial_snapshot: InitialSnapshot | null; } function buildUrl(endpoint: string, params?: Record): string { let url = `/v1/automation${endpoint}`; if (params) { const query = new URLSearchParams( Object.entries(params) .filter(([, v]) => v != null) .map(([k, v]) => [k, String(v)]) ); const queryStr = query.toString(); if (queryStr) { url += `?${queryStr}`; } } return url; } export const automationService = { /** * Get automation configuration for site */ getConfig: async (siteId: number): Promise => { return fetchAPI(buildUrl('/config/', { site_id: siteId })); }, /** * Update automation configuration */ updateConfig: async (siteId: number, config: Partial): Promise => { await fetchAPI(buildUrl('/update_config/', { site_id: siteId }), { method: 'PUT', body: JSON.stringify(config), }); }, /** * Trigger automation run now */ runNow: async (siteId: number): Promise<{ run_id: string; message: string }> => { return fetchAPI(buildUrl('/run_now/', { site_id: siteId }), { method: 'POST', }); }, /** * Get current automation run status */ getCurrentRun: async (siteId: number): Promise<{ run: AutomationRun | null }> => { return fetchAPI(buildUrl('/current_run/', { site_id: siteId })); }, /** * Pause automation run */ pause: async (siteId: number, runId: string): Promise => { await fetchAPI(buildUrl('/pause/', { site_id: siteId, run_id: runId }), { method: 'POST', }); }, /** * Resume paused automation run */ resume: async (siteId: number, runId: string): Promise => { await fetchAPI(buildUrl('/resume/', { site_id: siteId, run_id: runId }), { method: 'POST', }); }, /** * Cancel automation run */ cancel: async (siteId: number, runId: string): Promise => { await fetchAPI(buildUrl('/cancel/', { site_id: siteId, run_id: runId }), { method: 'POST', }); }, /** * Get automation run history */ getHistory: async (siteId: number): Promise => { const response = await fetchAPI(buildUrl('/history/', { site_id: siteId })); return response.runs; }, /** * Get enhanced automation run history with pagination */ getEnhancedHistory: async ( siteId: number, page: number = 1, pageSize: number = 20 ): Promise => { return fetchAPI(buildUrl('/history/', { site_id: siteId, page, page_size: pageSize })); }, /** * Get overview statistics with predictive analysis */ getOverviewStats: async (siteId: number): Promise => { return fetchAPI(buildUrl('/overview_stats/', { site_id: siteId })); }, /** * Get detailed information about a specific run */ getRunDetail: async ( siteId: number, runId: string ): Promise => { return fetchAPI(buildUrl('/run_detail/', { site_id: siteId, run_id: runId })); }, /** * Get automation run logs */ getLogs: async (runId: string, lines: number = 100): Promise => { const response = await fetchAPI(buildUrl('/logs/', { run_id: runId, lines })); return response.log; }, /** * Estimate credits needed */ estimate: async (siteId: number): Promise<{ estimated_credits: number; current_balance: number; sufficient: boolean; }> => { return fetchAPI(buildUrl('/estimate/', { site_id: siteId })); }, /** * Get pipeline overview with pending counts for all stages */ getPipelineOverview: async (siteId: number): Promise<{ stages: PipelineStage[] }> => { return fetchAPI(buildUrl('/pipeline_overview/', { site_id: siteId })); }, /** * Publish all content without review (bulk action) * Note: backend must implement this endpoint for it to succeed. */ publishWithoutReview: async (siteId: number): Promise => { await fetchAPI(buildUrl('/publish_without_review/', { site_id: siteId }), { method: 'POST', }); }, /** * Get current processing state for active automation run * Returns state with total_credits_used for real-time credits tracking */ getCurrentProcessing: async ( siteId: number, runId: string ): Promise => { const response = await fetchAPI( buildUrl('/current_processing/', { site_id: siteId, run_id: runId }) ); return response.data; }, /** * Get unified run progress data - global + per-stage. * This is the recommended endpoint for getting all automation progress data in a single call. */ getRunProgress: async ( siteId: number, runId?: string ): Promise => { const params: Record = { site_id: siteId }; if (runId) { params.run_id = runId; } return fetchAPI(buildUrl('/run_progress/', params)); }, /** * Check if site is eligible for automation * A site is eligible if it has any data in the pipeline (keywords, clusters, ideas, etc.) */ checkEligibility: async (siteId: number): Promise<{ is_eligible: boolean; totals: { keywords: number; clusters: number; ideas: number; tasks: number; content: number; images: number; }; total_items: number; message: string | null; }> => { return fetchAPI(buildUrl('/eligibility/', { site_id: siteId })); }, };