| | #!/usr/bin/env node |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | const axios = require('axios'); |
| | const FormData = require('form-data'); |
| | const fs = require('fs'); |
| | const path = require('path'); |
| | const WebSocket = require('ws'); |
| |
|
| | |
| | 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'; |
| |
|
| | |
| | |
| | |
| | class BackgroundFXClient { |
| | constructor(apiKey, baseUrl = API_BASE_URL) { |
| | this.apiKey = apiKey; |
| | this.baseUrl = baseUrl.replace(/\/$/, ''); |
| | |
| | |
| | this.client = axios.create({ |
| | baseURL: this.baseUrl, |
| | headers: { |
| | 'Authorization': `Bearer ${apiKey}`, |
| | 'User-Agent': 'BackgroundFX-Node-Client/1.0' |
| | } |
| | }); |
| | } |
| |
|
| | |
| | |
| | |
| | async removeBackground(imagePath, options = {}) { |
| | const { |
| | quality = 'high', |
| | model = 'auto', |
| | returnMask = false, |
| | edgeRefinement = 50 |
| | } = options; |
| |
|
| | |
| | if (!fs.existsSync(imagePath)) { |
| | throw new Error(`File not found: ${imagePath}`); |
| | } |
| |
|
| | |
| | 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; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | async processBatch(imagePaths, options = {}) { |
| | const formData = new FormData(); |
| | |
| | |
| | for (const imagePath of imagePaths) { |
| | if (!fs.existsSync(imagePath)) { |
| | console.warn(`⚠️ Skipping missing file: ${imagePath}`); |
| | continue; |
| | } |
| | formData.append('files', fs.createReadStream(imagePath)); |
| | } |
| | |
| | |
| | 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}`); |
| | |
| | |
| | return await this.monitorJob(jobId); |
| | } catch (error) { |
| | console.error('❌ Batch processing failed:', error.message); |
| | throw error; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | 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}`); |
| | } |
| | |
| | |
| | await new Promise(resolve => setTimeout(resolve, pollInterval)); |
| | } catch (error) { |
| | console.error('❌ Error monitoring job:', error.message); |
| | throw error; |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | 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; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | 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); |
| | }); |
| | } |
| |
|
| | |
| | |
| | |
| | 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'); |
| | }); |
| | }); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | 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 { |
| | |
| | const result = await client.removeBackground('sample_images/portrait.jpg', { |
| | quality: 'high' |
| | }); |
| | |
| | |
| | await client.downloadResult( |
| | result.image, |
| | 'output/portrait_no_bg.png' |
| | ); |
| | |
| | console.log('✨ Basic processing complete!'); |
| | } catch (error) { |
| | console.error('Failed:', error.message); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | 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' |
| | }); |
| | |
| | |
| | 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); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | 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 { |
| | |
| | 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}`); |
| | |
| | |
| | const result = await client.connectWebSocket(jobId); |
| | console.log('✨ Processing complete via WebSocket!'); |
| | |
| | } catch (error) { |
| | console.error('Failed:', error.message); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | 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 { |
| | |
| | const result = await client.removeBackground('sample_images/person.jpg'); |
| | const imageId = result.id; |
| | |
| | |
| | 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); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | async function exampleErrorHandling() { |
| | console.log('\n' + '='.repeat(60)); |
| | console.log('EXAMPLE 5: Error Handling'); |
| | console.log('='.repeat(60)); |
| |
|
| | const client = new BackgroundFXClient(API_KEY); |
| | |
| | |
| | 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; |
| | |
| | |
| | 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); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | 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(); |
| | |
| | |
| | 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`); |
| | |
| | |
| | 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); |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| |
|
| | async function main() { |
| | console.log('\n' + '#'.repeat(60)); |
| | console.log('# BackgroundFX Pro - Node.js Examples'); |
| | console.log('#'.repeat(60)); |
| | |
| | |
| | if (API_KEY === 'your-api-key-here') { |
| | console.error('\n⚠️ Please set your API key in BACKGROUNDFX_API_KEY environment variable'); |
| | process.exit(1); |
| | } |
| | |
| | |
| | const dirs = ['output', 'output/batch', 'sample_images']; |
| | dirs.forEach(dir => { |
| | if (!fs.existsSync(dir)) { |
| | fs.mkdirSync(dir, { recursive: true }); |
| | } |
| | }); |
| | |
| | |
| | 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)); |
| | } |
| |
|
| | |
| | if (require.main === module) { |
| | main().catch(console.error); |
| | } |
| |
|
| | module.exports = { BackgroundFXClient }; |