import type { ProcessingResult } from '../../types/index.js';
import { contentGenerator } from '../../generators/content/content.generator.js';
import { lateService } from '../../services/late/late.service.js';
import { appConfig } from '../../core/config/config.js';
import { schedulerUtil } from '../../utils/scheduler/scheduler.util.js';
import { logger } from '../../core/logger.js';
import { cdnUrlBuilder } from '../../utils/cdn/cdn-url-builder.js';
import { imagePipeline } from './image-pipeline.js';
import path from 'path';
/**
* Image Processor Service
*/
export class ImageProcessor {
/**
* Process a single image
* @param imagePath - Path to image file
* @param userContext - Context for content generation
* @param publishDate - Publish date (null = auto-calculate)
* @param instagramType - Instagram content type ('post' or 'story')
* @param isDraft - Create as draft
* @param publishToInstagram - Publish to Instagram (default: true)
* @param publishToPinterest - Publish to Pinterest (default: true)
*/
async processImage(
imagePath: string,
userContext: string = '',
publishDate: Date | null = null,
instagramType: 'post' | 'story' = 'post',
isDraft: boolean = false,
publishToInstagram: boolean = true,
publishToPinterest: boolean = true
): Promise<ProcessingResult> {
try {
const fileName = path.basename(imagePath);
const platforms = [];
if (publishToInstagram) platforms.push('Instagram');
if (publishToPinterest) platforms.push('Pinterest');
logger.info('Processing image', { fileName, platforms: platforms.join(' + ') || 'none' });
// Determine needed content types for image pipeline
const neededTypes: Array<'post' | 'story' | 'pin'> = [];
if (publishToInstagram) neededTypes.push(instagramType);
if (publishToPinterest) neededTypes.push('pin');
// Run image pipeline (process local images or pass through URLs)
const pipeline = await imagePipeline.process({
imageInput: imagePath,
contentTypes: neededTypes,
});
// For content generation, use CDN URL if available, otherwise the original path
const contentGenerationSource = pipeline.cdnUrls.story
|| pipeline.cdnUrls.post
|| pipeline.cdnUrls.pin
|| (cdnUrlBuilder.isConfigured()
? cdnUrlBuilder.buildURLForContentGeneration(fileName)
: imagePath);
// Generate content
const content = await contentGenerator.generateContent(contentGenerationSource, userContext);
// Set publish date if not provided
const publishDateToUse = publishDate || schedulerUtil.getNextPublishDate();
// Validate platform configuration
if (publishToInstagram && !appConfig.isInstagramLateConfigured()) {
throw new Error('Late API must be configured for Instagram. Please set LATE_API_KEY, LATE_PROFILE_ID, and LATE_INSTAGRAM_ACCOUNT_ID');
}
if (publishToPinterest && !appConfig.isPinterestLateConfigured()) {
throw new Error('Late API must be configured for Pinterest. Please set LATE_API_KEY, LATE_PROFILE_ID, and LATE_PINTEREST_ACCOUNT_ID');
}
let instagramResult: { id: string } | null = null;
let pinterestResult: { id: string } | null = null;
// Schedule Instagram if needed
if (publishToInstagram) {
const instagramImageURL = pipeline.cdnUrls[instagramType]
|| cdnUrlBuilder.buildURLForPublishing(fileName, instagramType);
logger.debug('Using CDN URL', { instagram: instagramImageURL });
logger.info('Scheduling to Instagram via Late API');
instagramResult = await lateService.scheduleToMultiplePlatforms({
imagePathOrUrl: instagramImageURL,
pinterestContent: null,
instagramContent: content.instagram,
publishDate: publishDateToUse,
platforms: ['instagram'],
instagramMediaType: instagramType,
isPublicURL: true,
isDraft,
});
logger.info(`Instagram ${instagramType} scheduled via Late API`, { postId: instagramResult.id });
}
// Schedule Pinterest if needed (via Late API)
if (publishToPinterest) {
const pinterestImageURL = pipeline.cdnUrls.pin
|| cdnUrlBuilder.buildURLForPublishing(fileName, 'pin');
logger.debug('Using CDN URL', { pinterest: pinterestImageURL });
logger.info('Scheduling to Pinterest via Late API');
const pinterestLateResult = await lateService.scheduleToMultiplePlatforms({
imagePathOrUrl: pinterestImageURL,
pinterestContent: content.pinterest,
instagramContent: content.instagram,
publishDate: publishDateToUse,
platforms: ['pinterest'],
instagramMediaType: instagramType,
isPublicURL: true,
isDraft,
});
pinterestResult = { id: pinterestLateResult.id };
logger.info('Pinterest pin scheduled via Late API', { postId: pinterestResult.id });
}
return {
imagePath,
pinterest: pinterestResult
? { id: pinterestResult.id, service: 'late' }
: { id: '', service: 'none' },
instagram: instagramResult
? { id: instagramResult.id, service: 'late', mediaType: instagramType }
: { id: '', service: 'none' },
instagramType,
publishDate: publishDateToUse.toISOString()
};
} catch (error) {
logger.error(`Error processing image`, error instanceof Error ? error : new Error(String(error)), { imagePath });
throw error;
}
}
}
// Export singleton instance
export const imageProcessor = new ImageProcessor();