#!/usr/bin/env node /** * BackgroundFX Pro - Node.js Usage Examples * * This script demonstrates how to use the BackgroundFX Pro API with Node.js * including file uploads, async processing, and WebSocket connections. */ const axios = require('axios'); const FormData = require('form-data'); const fs = require('fs'); const path = require('path'); const WebSocket = require('ws'); // Configuration const API_BASE_URL = process.env.BACKGROUNDFX_API_URL || 'https://api.backgroundfx.pro/v1'; const API_KEY = process.env.BACKGROUNDFX_API_KEY || 'your-api-key-here'; const WS_URL = process.env.BACKGROUNDFX_WS_URL || 'wss://ws.backgroundfx.pro'; /** * BackgroundFX API Client */ class BackgroundFXClient { constructor(apiKey, baseUrl = API_BASE_URL) { this.apiKey = apiKey; this.baseUrl = baseUrl.replace(/\/$/, ''); // Configure axios instance this.client = axios.create({ baseURL: this.baseUrl, headers: { 'Authorization': `Bearer ${apiKey}`, 'User-Agent': 'BackgroundFX-Node-Client/1.0' } }); } /** * Remove background from an image */ async removeBackground(imagePath, options = {}) { const { quality = 'high', model = 'auto', returnMask = false, edgeRefinement = 50 } = options; // Check if file exists if (!fs.existsSync(imagePath)) { throw new Error(`File not found: ${imagePath}`); } // Create form data const formData = new FormData(); formData.append('file', fs.createReadStream(imagePath)); formData.append('quality', quality); formData.append('model', model); formData.append('return_mask', returnMask.toString()); formData.append('edge_refinement', edgeRefinement.toString()); try { console.log(`šŸ”„ Processing image: ${path.basename(imagePath)}`); const response = await this.client.post('/process/remove-background', formData, { headers: formData.getHeaders(), maxContentLength: Infinity, maxBodyLength: Infinity }); console.log('āœ… Background removed successfully!'); return response.data; } catch (error) { console.error('āŒ Error processing image:', error.response?.data || error.message); throw error; } } /** * Process multiple images in batch */ async processBatch(imagePaths, options = {}) { const formData = new FormData(); // Add all files for (const imagePath of imagePaths) { if (!fs.existsSync(imagePath)) { console.warn(`āš ļø Skipping missing file: ${imagePath}`); continue; } formData.append('files', fs.createReadStream(imagePath)); } // Add options formData.append('options', JSON.stringify(options)); try { console.log(`šŸ”„ Processing batch of ${imagePaths.length} images...`); const response = await this.client.post('/process/batch', formData, { headers: formData.getHeaders() }); const jobId = response.data.id; console.log(`āœ… Batch job created: ${jobId}`); // Monitor job progress return await this.monitorJob(jobId); } catch (error) { console.error('āŒ Batch processing failed:', error.message); throw error; } } /** * Monitor batch job progress */ async monitorJob(jobId, pollInterval = 2000) { console.log(`šŸ“Š Monitoring job: ${jobId}`); while (true) { try { const response = await this.client.get(`/process/jobs/${jobId}`); const job = response.data; console.log(` Status: ${job.status} | Progress: ${job.progress}%`); if (job.status === 'completed') { console.log('āœ… Job completed!'); return job; } else if (job.status === 'failed') { throw new Error(`Job failed: ${job.error}`); } // Wait before next poll await new Promise(resolve => setTimeout(resolve, pollInterval)); } catch (error) { console.error('āŒ Error monitoring job:', error.message); throw error; } } } /** * Replace background with color or image */ async replaceBackground(imageId, background, blendMode = 'normal') { try { const response = await this.client.post('/process/replace-background', { image_id: imageId, background: background, blend_mode: blendMode }); console.log('āœ… Background replaced!'); return response.data; } catch (error) { console.error('āŒ Error replacing background:', error.message); throw error; } } /** * Download result to file */ async downloadResult(url, outputPath) { const writer = fs.createWriteStream(outputPath); const response = await axios({ url, method: 'GET', responseType: 'stream' }); response.data.pipe(writer); return new Promise((resolve, reject) => { writer.on('finish', () => { console.log(`šŸ’¾ Saved to: ${outputPath}`); resolve(outputPath); }); writer.on('error', reject); }); } /** * Connect to WebSocket for real-time updates */ connectWebSocket(jobId) { return new Promise((resolve, reject) => { const ws = new WebSocket(`${WS_URL}?job_id=${jobId}`, { headers: { 'Authorization': `Bearer ${this.apiKey}` } }); ws.on('open', () => { console.log('šŸ”Œ WebSocket connected'); ws.send(JSON.stringify({ action: 'subscribe', job_id: jobId })); }); ws.on('message', (data) => { const message = JSON.parse(data); console.log('šŸ“Ø WebSocket message:', message); if (message.type === 'job:complete') { ws.close(); resolve(message.data); } else if (message.type === 'job:error') { ws.close(); reject(new Error(message.error)); } else if (message.type === 'job:progress') { console.log(` Progress: ${message.progress}%`); } }); ws.on('error', (error) => { console.error('āŒ WebSocket error:', error); reject(error); }); ws.on('close', () => { console.log('šŸ”Œ WebSocket disconnected'); }); }); } } // ============================================================================ // EXAMPLES // ============================================================================ /** * Example 1: Basic background removal */ async function exampleBasicUsage() { console.log('\n' + '='.repeat(60)); console.log('EXAMPLE 1: Basic Background Removal'); console.log('='.repeat(60)); const client = new BackgroundFXClient(API_KEY); try { // Process image const result = await client.removeBackground('sample_images/portrait.jpg', { quality: 'high' }); // Download result await client.downloadResult( result.image, 'output/portrait_no_bg.png' ); console.log('✨ Basic processing complete!'); } catch (error) { console.error('Failed:', error.message); } } /** * Example 2: Batch processing with progress monitoring */ async function exampleBatchProcessing() { console.log('\n' + '='.repeat(60)); console.log('EXAMPLE 2: Batch Processing'); console.log('='.repeat(60)); const client = new BackgroundFXClient(API_KEY); const images = [ 'sample_images/product1.jpg', 'sample_images/product2.jpg', 'sample_images/product3.jpg' ]; try { const job = await client.processBatch(images, { quality: 'medium', model: 'rembg' }); // Download all results for (const [index, result] of job.results.entries()) { await client.downloadResult( result.image, `output/batch/product${index + 1}_no_bg.png` ); } console.log('✨ Batch processing complete!'); } catch (error) { console.error('Failed:', error.message); } } /** * Example 3: WebSocket real-time monitoring */ async function exampleWebSocketMonitoring() { console.log('\n' + '='.repeat(60)); console.log('EXAMPLE 3: WebSocket Real-time Monitoring'); console.log('='.repeat(60)); const client = new BackgroundFXClient(API_KEY); try { // Start batch job const formData = new FormData(); formData.append('files', fs.createReadStream('sample_images/large1.jpg')); formData.append('files', fs.createReadStream('sample_images/large2.jpg')); const response = await client.client.post('/process/batch', formData, { headers: formData.getHeaders() }); const jobId = response.data.id; console.log(`šŸ“‹ Job ID: ${jobId}`); // Monitor via WebSocket const result = await client.connectWebSocket(jobId); console.log('✨ Processing complete via WebSocket!'); } catch (error) { console.error('Failed:', error.message); } } /** * Example 4: Background replacement variations */ async function exampleBackgroundReplacement() { console.log('\n' + '='.repeat(60)); console.log('EXAMPLE 4: Background Replacement'); console.log('='.repeat(60)); const client = new BackgroundFXClient(API_KEY); try { // First remove background const result = await client.removeBackground('sample_images/person.jpg'); const imageId = result.id; // Try different backgrounds const backgrounds = [ { type: 'color', value: '#3498db', name: 'blue' }, { type: 'gradient', value: 'linear-gradient(45deg, #ff6b6b, #4ecdc4)', name: 'gradient' }, { type: 'blur', value: 'blur:20', name: 'blurred' } ]; for (const bg of backgrounds) { console.log(`šŸŽØ Applying ${bg.name} background...`); const replaced = await client.replaceBackground(imageId, bg.value); await client.downloadResult( replaced.image, `output/person_${bg.name}_bg.png` ); } console.log('✨ Background replacement complete!'); } catch (error) { console.error('Failed:', error.message); } } /** * Example 5: Error handling and retries */ async function exampleErrorHandling() { console.log('\n' + '='.repeat(60)); console.log('EXAMPLE 5: Error Handling'); console.log('='.repeat(60)); const client = new BackgroundFXClient(API_KEY); // Retry logic async function withRetry(fn, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (error) { console.log(`āš ļø Attempt ${i + 1} failed: ${error.message}`); if (i === maxRetries - 1) throw error; // Exponential backoff const delay = Math.pow(2, i) * 1000; console.log(`ā³ Waiting ${delay}ms before retry...`); await new Promise(resolve => setTimeout(resolve, delay)); } } } try { const result = await withRetry(() => client.removeBackground('sample_images/test.jpg') ); console.log('āœ… Success after retries'); } catch (error) { console.error('āŒ Failed after all retries:', error.message); } } /** * Example 6: Parallel processing */ async function exampleParallelProcessing() { console.log('\n' + '='.repeat(60)); console.log('EXAMPLE 6: Parallel Processing'); console.log('='.repeat(60)); const client = new BackgroundFXClient(API_KEY); const images = [ 'sample_images/img1.jpg', 'sample_images/img2.jpg', 'sample_images/img3.jpg', 'sample_images/img4.jpg' ]; try { console.log(`šŸš€ Processing ${images.length} images in parallel...`); const startTime = Date.now(); // Process all images in parallel const promises = images.map(imagePath => client.removeBackground(imagePath, { quality: 'medium' }) .catch(err => ({ error: err.message, path: imagePath })) ); const results = await Promise.all(promises); const elapsed = (Date.now() - startTime) / 1000; console.log(`āœ… Processed ${results.length} images in ${elapsed.toFixed(2)}s`); // Count successes and failures const successes = results.filter(r => !r.error).length; const failures = results.filter(r => r.error).length; console.log(` Successes: ${successes}`); console.log(` Failures: ${failures}`); } catch (error) { console.error('Failed:', error.message); } } // ============================================================================ // MAIN // ============================================================================ async function main() { console.log('\n' + '#'.repeat(60)); console.log('# BackgroundFX Pro - Node.js Examples'); console.log('#'.repeat(60)); // Check API key if (API_KEY === 'your-api-key-here') { console.error('\nāš ļø Please set your API key in BACKGROUNDFX_API_KEY environment variable'); process.exit(1); } // Create output directories const dirs = ['output', 'output/batch', 'sample_images']; dirs.forEach(dir => { if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } }); // Run examples const examples = [ exampleBasicUsage, exampleBatchProcessing, exampleWebSocketMonitoring, exampleBackgroundReplacement, exampleErrorHandling, exampleParallelProcessing ]; for (const example of examples) { try { await example(); } catch (error) { console.error(`\nāŒ Example failed: ${error.message}`); } } console.log('\n' + '#'.repeat(60)); console.log('# All examples complete!'); console.log('#'.repeat(60)); } // Run if called directly if (require.main === module) { main().catch(console.error); } module.exports = { BackgroundFXClient };