Node.js NSFWJS图像分类API同步问题求助:多图片预测结果异常
Fixing Async Sync & Image Overwriting Issues in Your NSFWJS API
Hey there! Let's tackle the two main issues you're facing—async flow synchronization problems and image overwriting—with some targeted fixes and code refactoring.
Root Causes of Your Problems
- Async Flow Chaos: Your
whileloop doesn't wait for asynchronous operations (like downloading images or running model predictions) to finish before moving to the next code. This leads to out-of-order execution, incorrectiincrements, and incomplete/overwritten results in your final JSON. - Image Overwriting: All images are saved to the same
ans1.pngfile, so each new download replaces the previous one. This means your model ends up predicting on the last downloaded image every time, not the current one.
Refactored Code
const express = require('express') const multer = require('multer') const jpeg = require('jpeg-js') const tf = require('@tensorflow/tfjs-node') const nsfw = require('nsfwjs') const bodyParser = require("body-parser") const axios = require('axios'); const fs = require('fs').promises; // Use promise-based fs for better async handling const request = require('request'); const { promisify } = require('util'); const app = express() const upload = multer() app.use(bodyParser.json()); let _model; // Promisify request.head for async/await const requestHead = promisify(request.head); // Promisify request stream for async download const downloadImage = async (uri, filename) => { await requestHead(uri); return new Promise((resolve, reject) => { request(uri) .pipe(fs.createWriteStream(filename)) .on('close', resolve) .on('error', reject); }); }; // Process image and get NSFW predictions const processImagePrediction = async (imagePath) => { const fileContent = await fs.readFile(imagePath); const image = jpeg.decode(fileContent, true); const numChannels = 3; const numPixels = image.width * image.height; const values = new Int32Array(numPixels * numChannels); for (let i = 0; i < numPixels; i++) { for (let c = 0; c < numChannels; ++c) { values[i * numChannels + c] = image.data[i * 4 + c]; } } const tensor = tf.tensor3d(values, [image.height, image.width, numChannels], 'int32'); const predictions = await _model.classify(tensor); // Clean up tensor to free memory tensor.dispose(); return predictions; }; app.post('/nsfw', async (req, res) => { const arrayCodes = req.body.Codes; const jsonObj = {}; if (!arrayCodes || !Array.isArray(arrayCodes)) { return res.status(400).json({ error: 'Invalid input: Codes must be an array' }); } for (const code of arrayCodes) { try { const imgUrl = `http://url/to/image${code}`; const response = await axios.get(imgUrl); const imageUrl = response.data.facets.Media.productImage.url; const tempFilename = `temp-${code}.png`; // Download the image to a unique temp file await downloadImage(imageUrl, tempFilename); // Get predictions const predictions = await processImagePrediction(tempFilename); // Store results jsonObj[code] = predictions; // Clean up temp file await fs.unlink(tempFilename); console.log(`Processed code: ${code}`); } catch (error) { console.error(`Failed to process code ${code}:`, error.message); jsonObj[code] = { error: `Failed to process: ${error.message}` }; } } res.json(jsonObj); }); const load_model = async () => { _model = await nsfw.load(); console.log('NSFW model loaded successfully'); }; load_model().then(() => app.listen(8080, () => { console.log('Server running on port 8080'); }));
Key Improvements Explained
- Sequential Async Execution: Using
for...ofwithawaitensures we fully process one image before moving to the next. No more messy loop logic or out-of-sync state. - Unique Temp Files: Each image is saved to a unique file (e.g.,
temp-Code1.png) so downloads don't overwrite each other. We also delete these files after processing to keep your filesystem clean. - Modular Functions:
downloadImageandprocessImagePredictionseparate concerns, making the code easier to read, test, and modify. - Promise-Based Filesystem: Using
fs.promisesand promisifyingrequestfunctions lets us useawaitfor all async operations, avoiding callback hell. - Memory Cleanup: We dispose of the TensorFlow tensor after prediction to prevent memory leaks.
- Better Error Handling: Each code's processing is wrapped in
try/catch, so a single failure doesn't break the entire request. We also return error details for failed codes in the final JSON. - Input Validation: We check if
Codesis a valid array to return a clear error for bad requests.
内容的提问来源于stack exchange,提问作者Madhur Dheer
相关产品推荐
相关产品推荐

