我不明白为什么我不能在上面的代码中使用express和multer。当我上传文件时,我在日志中得到的只是一个空数组。我花了几个小时修改它,我就是不明白!
我看到有几个人报告了 Express 和 multer 之间的错误或错误,但我仍然无法解决我的问题。如果您有任何想法,我将不胜感激!
如果您有任何想法,这是我的代码,谢谢!
const functions = require('firebase-functions');
const express = require('express');
const multer = require('multer');
const Replicate = require('replicate');
const cors = require('cors');
const app = express();
// Configuration de Multer avec gestion d'erreurs
const upload = multer({
storage: multer.memoryStorage(),
limits: { fileSize: 10 * 1024 * 1024 }, // Limite à 10MB
}).single('image');
app.use(cors({ origin: true }));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const replicate = new Replicate({
auth: functions.config().replicate.api_token,
});
const styleDescriptions = {
'Gamer': `Upgrade this setup to create a gaming setup, with aesthetic rgb lights...`,
'Aesthetic': `Transform this setup into a minimalist and visually pleasing design...`,
'RGB Free': `Enhance this setup to create a professional and sophisticated environment...`
};
app.post('/generate', (req, res) => {
console.log('Received generate request');
upload(req, res, async function(err) {
console.log('On arrive ici');
if (err) {
console.error('Upload error:', err);
return res.status(400).json({ error: 'File upload error', details: err.message });
}
try {
const { file } = req;
const { style } = req.body;
console.log('File uploaded successfully');
console.log('File details:', file ? { originalname: file.originalname, size: file.size } : 'No file');
console.log('Selected style:', style);
console.log('File details:', file ? { originalname: file.originalname, size: file.size } : 'No file');
console.log('Selected style:', style);
if (!file) {
return res.status(400).json({ error: 'No image file provided' });
}
const styleDescription = styleDescriptions[style] || '';
console.log('Preparing input for Replicate API');
const input = {
image: `data:${file.mimetype};base64,${file.buffer.toString('base64')}`,
prompt: styleDescription,
guidance: 3.5,
num_outputs: 1,
aspect_ratio: "1:1",
output_format: "webp",
output_quality: 80,
prompt_strength: 0.80,
num_inference_steps: 28
};
console.log('Sending request to Replicate API...');
const output = await replicate.run(
"black-forest-labs/flux-dev",
{ input }
);
console.log('Replicate API response received');
res.json({ output: output[0] });
} catch (error) {
console.error('Error in generate function:', error);
res.status(500).json({ error: 'An error occurred while generating the image', details: error.message });
}
});
});
// Export the Express app as a Firebase Cloud Function
exports.api = functions.https.onRequest(app);
这是客户端代码,用户可以在其中上传图像,然后单击生成:
export const GenerateNew = () => {
const [image, setImage] = useState(null);
const [style, setStyle] = useState('Gamer');
const [loading, setLoading] = useState(false);
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [credits, setCredits] = useState(0);
const [showCreditAlert, setShowCreditAlert] = useState(false);
const dropdownRef = useRef(null);
const { currentUser } = useAuth();
useEffect(() => {
if (currentUser) {
const userDocRef = doc(db, 'users', currentUser.uid);
const unsubscribe = onSnapshot(userDocRef, (docSnapshot) => {
if (docSnapshot.exists()) {
const userData = docSnapshot.data();
setCredits(userData.credits || 0);
}
});
return () => unsubscribe();
}
}, [currentUser]);
useEffect(() => {
const handleClickOutside = (event) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setIsDropdownOpen(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => document.removeEventListener('mousedown', handleClickOutside);
}, []);
const onDrop = useCallback((acceptedFiles) => {
setImage(acceptedFiles[0]);
}, []);
const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept: { 'image/*': ['.jpeg', '.jpg', '.png', '.gif', '.webp'] },
maxFiles: 1,
disabled: !!image
});
const handleSubmit = async (e) => {
e.preventDefault();
if (!image) {
alert('Please select an image first.');
return;
}
if (credits === 0) {
setShowCreditAlert(true);
return;
}
setLoading(true);
try {
const formData = new FormData();
formData.append('image', image);
formData.append('style', style);
console.log('FormData content:');
for (let [key, value] of formData.entries()) {
console.log(key, value);
}
const response = await axios.post(`${API_URL}/generate`, formData,);
const generatedImageUrl = response.data.output;
// Sauvegarder les images dans Firebase Storage
console.log('start save dans FBS');
const originalImageRef = ref(storage, `original/${currentUser.uid}/${Date.now()}_${image.name}`);
console.log('Saved dans FBS');
await uploadBytes(originalImageRef, image);
const originalImageUrl = await getDownloadURL(originalImageRef);
const generatedImageResponse = await fetch(generatedImageUrl);
const generatedImageBlob = await generatedImageResponse.blob();
const generatedImageRef = ref(storage, `generated/${currentUser.uid}/${Date.now()}_generated.png`);
await uploadBytes(generatedImageRef, generatedImageBlob);
const firebaseGeneratedImageUrl = await getDownloadURL(generatedImageRef);
// Sauvegarder les informations dans Firestore
console.log('Save dans FBS');
const setupsRef = collection(db, 'generatedImages');
const setupsSnapshot = await getDocs(query(setupsRef, where('userId', '==', currentUser.uid)));
const setupNumber = setupsSnapshot.size + 1;
console.log('Saved dans FBS');
await addDoc(setupsRef, {
userId: currentUser.uid,
originalImage: originalImageUrl,
generatedImage: firebaseGeneratedImageUrl,
style: style,
title: `Setup #${setupNumber}`,
createdAt: new Date()
});
// Mettre à jour les crédits de l'utilisateur
const userRef = doc(db, 'users', currentUser.uid);
await updateDoc(userRef, { credits: increment(-1) });
setLoading(false);
alert('Image generated and saved successfully!');
setImage(null);
setStyle('Gamer');
} catch (error) {
console.error('Error:', error.response ? error.response.data : error.message);
setLoading(false);
alert('An error occurred. Please try again.');
}
};
const styles = ['Gamer', 'Aesthetic', 'RGB Free'];
看来您的问题在于如何在 Express 应用程序中调用中间件。在您的代码中,您的 req 对象是从 multer 之前的中间件定义的,因此只有原始数据(因为 multer 中间件尚未运行)。
不要尝试在 post 函数中调用 multer 中间件,而是先将其用作中间件。然后传递给 post 回调函数的请求对象将包含您期望的文件。
...
const multer = require('multer');
...
// Configuration de Multer avec gestion d'erreurs
const upload = multer({
storage: multer.memoryStorage(),
limits: { fileSize: 10 * 1024 * 1024 }, // Limite à 10MB
}).single('image');
...
//post request using multer middleware
app.post('/generate', upload, (req, res) => {
try {
const { file } = req;
const { style } = req.body;
...