import { apiClient } from './client' import { io, Socket } from 'socket.io-client' export interface ProcessingOptions { model?: 'rembg' | 'u2net' | 'deeplab' | 'custom' quality?: 'low' | 'medium' | 'high' | 'ultra' returnMask?: boolean edgeRefinement?: number feather?: number tolerance?: number preserveDetails?: boolean } export interface ProcessingResult { id: string image: string mask?: string metadata: { width: number height: number format: string processingTime: number } } export interface BatchJob { id: string status: 'pending' | 'processing' | 'completed' | 'failed' progress: number totalFiles: number processedFiles: number results?: ProcessingResult[] error?: string createdAt: string completedAt?: string } class ProcessingAPI { private socket: Socket | null = null private listeners: Map> = new Map() /** * Process a single image */ async processImage( file: File, options: ProcessingOptions = {}, onProgress?: (progress: number) => void ): Promise { const formData = new FormData() formData.append('file', file) formData.append('options', JSON.stringify(options)) return apiClient.upload( '/api/v1/process/remove-background', file, onProgress ) } /** * Process multiple images in batch */ async processBatch( files: File[], options: ProcessingOptions = {} ): Promise { const formData = new FormData() files.forEach((file) => formData.append('files', file)) formData.append('options', JSON.stringify(options)) const response = await apiClient.post('/api/v1/process/batch', formData, { headers: { 'Content-Type': 'multipart/form-data' }, }) // Connect to WebSocket for real-time updates this.connectWebSocket(response.id) return response } /** * Get batch job status */ async getJobStatus(jobId: string): Promise { return apiClient.get(`/api/v1/process/jobs/${jobId}`) } /** * Cancel a batch job */ async cancelJob(jobId: string): Promise { await apiClient.post(`/api/v1/process/jobs/${jobId}/cancel`) } /** * Replace background with a new one */ async replaceBackground( imageId: string, background: string | File ): Promise { const formData = new FormData() formData.append('imageId', imageId) if (background instanceof File) { formData.append('background', background) } else { formData.append('backgroundUrl', background) } return apiClient.post( '/api/v1/process/replace-background', formData, { headers: { 'Content-Type': 'multipart/form-data' } } ) } /** * Apply AI-powered enhancements */ async enhanceImage( imageId: string, enhancements: { sharpness?: number contrast?: number brightness?: number saturation?: number denoise?: boolean upscale?: 2 | 4 } ): Promise { return apiClient.post('/api/v1/process/enhance', { imageId, enhancements, }) } /** * Generate AI background */ async generateBackground( prompt: string, style?: 'realistic' | 'artistic' | 'abstract' | 'gradient' ): Promise<{ id: string; url: string }> { return apiClient.post('/api/v1/backgrounds/generate', { prompt, style, }) } /** * Smart edge detection and refinement */ async refineEdges( imageId: string, maskId: string, options: { mode: 'hair' | 'fur' | 'smooth' | 'detailed' strength: number } ): Promise { return apiClient.post('/api/v1/process/refine-edges', { imageId, maskId, ...options, }) } /** * Connect to WebSocket for real-time updates */ private connectWebSocket(jobId: string) { if (this.socket?.connected) { this.socket.emit('subscribe', { jobId }) return } const wsUrl = process.env.NEXT_PUBLIC_WS_URL || 'ws://localhost:8000' this.socket = io(wsUrl, { transports: ['websocket'], query: { jobId }, }) this.socket.on('connect', () => { console.log('WebSocket connected') this.socket?.emit('subscribe', { jobId }) }) this.socket.on('job:progress', (data) => { this.emit('progress', data) }) this.socket.on('job:complete', (data) => { this.emit('complete', data) this.disconnectWebSocket() }) this.socket.on('job:error', (data) => { this.emit('error', data) this.disconnectWebSocket() }) this.socket.on('disconnect', () => { console.log('WebSocket disconnected') }) } /** * Disconnect WebSocket */ private disconnectWebSocket() { if (this.socket) { this.socket.disconnect() this.socket = null } } /** * Subscribe to events */ on(event: string, callback: Function) { if (!this.listeners.has(event)) { this.listeners.set(event, new Set()) } this.listeners.get(event)?.add(callback) } /** * Unsubscribe from events */ off(event: string, callback: Function) { this.listeners.get(event)?.delete(callback) } /** * Emit events */ private emit(event: string, data: any) { this.listeners.get(event)?.forEach((callback) => callback(data)) } /** * Estimate processing time */ estimateProcessingTime( fileSize: number, options: ProcessingOptions ): number { const basetime = 1000 // 1 second base const sizeMultiplier = fileSize / (1024 * 1024) // MB const qualityMultiplier = { low: 0.5, medium: 1, high: 1.5, ultra: 2, }[options.quality || 'medium'] return Math.round(basetime * sizeMultiplier * qualityMultiplier) } /** * Validate image before processing */ validateImage(file: File): { valid: boolean; error?: string } { const maxSize = 50 * 1024 * 1024 // 50MB const allowedTypes = ['image/png', 'image/jpeg', 'image/webp', 'image/gif'] if (file.size > maxSize) { return { valid: false, error: 'File size exceeds 50MB limit' } } if (!allowedTypes.includes(file.type)) { return { valid: false, error: 'Unsupported file type' } } return { valid: true } } } export const processingAPI = new ProcessingAPI() // Helper functions export async function processImage( file: File, options?: ProcessingOptions, onProgress?: (progress: number) => void ): Promise { return processingAPI.processImage(file, options, onProgress) } export async function processBatch( files: File[], options?: ProcessingOptions ): Promise { return processingAPI.processBatch(files, options) } export default processingAPI