MogensR's picture
Create examples/javascript/node/basic_usage.js
e6e3409
raw
history blame
15.5 kB
#!/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 };