I receive the error in AutoDetailing.js when I submit a photo for capture.
Error uploading photo or analyzing image: Response is missing data field. AutoDetailing.js:37:20
Error details: FirebaseError: Response is missing data field.
But I receive the following in Firebase logs.
Received labels from OpenAI API: The image shows a young man in an indoor setting, holding up a green can towards the camera which has the text “Recycle Me” on it. He is smiling and wearing a light-colored t-shirt. The background appears to be a home interior with a neutral color tone. The focus is on promoting recycling based on the text visible on the can.
Here is my code below.
AutoDetailing.js
import React, { useState } from "react";
import Camera, { FACING_MODES } from 'react-html5-camera-photo';
import 'react-html5-camera-photo/build/css/index.css';
import PropTypes from 'prop-types';
import { useForm } from "react-hook-form";
import { storage, functions } from './firebase'; // Ensure the correct path
import { ref, uploadBytes, getDownloadURL } from 'firebase/storage';
import { httpsCallable } from 'firebase/functions';
function AutoCameraApp({ onClose, onPhotoCapture, formData }) {
const handlePhotoCapture = async (dataUri) => {
console.log('Photo captured:', dataUri);
const blob = await fetch(dataUri).then(res => res.blob());
const storageRef = ref(storage, `vehicle-photos/${Date.now()}-vehicle-photo.png`);
try {
const snapshot = await uploadBytes(storageRef, blob);
console.log('Uploaded the file!', snapshot);
const downloadUrl = await getDownloadURL(snapshot.ref);
console.log('File available at', downloadUrl);
const analyzeImage = httpsCallable(functions, 'analyzeImage');
const payload = { imageUrl: downloadUrl };
console.log('Calling analyzeImage with payload:', payload);
const result = await analyzeImage(payload);
console.log('Result from analyzeImage:', result);
if (result.data && result.data.labels) {
onPhotoCapture(downloadUrl, result.data.labels);
} else {
console.error('Response is missing labels field:', result.data);
}
} catch (error) {
console.error('Error uploading photo or analyzing image:', error.message);
console.error('Error details:', error);
}
console.log('Form Data:', formData);
};
return (
<div className="camera-fullscreen">
<div className="camera-header">
Take a picture of your vehicle
</div>
<Camera
onTakePhoto={(dataUri) => { handlePhotoCapture(dataUri); }}
isFullscreen={true}
idealFacingMode={FACING_MODES.ENVIRONMENT}
isMaxResolution={true}
/>
<button onClick={onClose}>Close</button>
</div>
);
AutoCameraApp.propTypes = {
onClose: PropTypes.func.isRequired,
onPhotoCapture: PropTypes.func.isRequired,
formData: PropTypes.object
};
const AutoDetailing = ({ vehicleTypes, pricingMatrix, setCurrentVehicle }) => {
const { register, handleSubmit, watch, formState: { errors }, getValues } = useForm();
const [selectedVehicle, setSelectedVehicle] = useState(null);
const [showCamera, setShowCamera] = useState(false);
const [photoData, setPhotoData] = useState(null);
const [analysisResult, setAnalysisResult] = useState(null);
const [isFormVisible, setIsFormVisible] = useState(false);
const onSubmit = data => {
console.log('Form submitted:', data);
// Handle form submission here
};
const handleVehicleSelect = (vehicleType) => {
setSelectedVehicle(vehicleType);
console.log('Vehicle selected:', vehicleType);
};
const handlePackageSelect = (packageType) => {
setCurrentVehicle(selectedVehicle);
setShowCamera(false);
setIsFormVisible(true);
console.log('Package selected:', packageType);
};
const handleCloseCamera = () => {
setShowCamera(false);
setIsFormVisible(false);
console.log('Camera closed');
};
const handlePhotoCapture = (downloadUrl, analysis) => {
setPhotoData(downloadUrl);
setAnalysisResult(analysis);
setShowCamera(false);
setIsFormVisible(false);
console.log('Photo captured and analyzed:', { downloadUrl, analysis });
};
const watchFields = watch(["firstName", "lastName", "threeAvailDatesTimes", "address"]);
const isFormComplete = watchFields.every(field => field && field.trim() !== "");
const formData = getValues();
return (
<div className="service-detail-wrapper">
<p className="service-description">
We're deeply committed to the art of automotive detailing, ensuring no detail is overlooked in our meticulous process. Our approach combines safe solutions with expert care to maintain the highest quality standards, preserving your vehicle's finish impeccably. Did you know that most swirls on vehicles stem from improper hand washing or automatic car washes? We offer various detailing packages tailored to your needs, with our standard package recommended biannually and the full package annually. You can also customize your package to suit your preferences. Rest assured, our dedication to customer satisfaction means we'll promptly address any concerns to ensure your experience with us is exceptional.
</p>
{isFormVisible ? (
<div className="booking-overlay">
<form className="fullscreen-form" onSubmit={handleSubmit(onSubmit)}>
<h3>Fill out the following form</h3>
<div className="input-fields">
<input type="text" placeholder="First Name" {...register("firstName", { required: true })} />
{errors.firstName && <span>This field is required</span>}
<input type="text" placeholder="Last Name" {...register("lastName", { required: true })} />
{errors.lastName && <span>This field is required</span>}
<input type="tel" placeholder="Phone" {...register("phone", { required: true })} />
{errors.phone && <span>This field is required</span>}
<input type="email" placeholder="Email" {...register("email", { required: true })} />
{errors.email && <span>This field is required</span>}
<input type="text" placeholder="3 Available Dates / Times" {...register("threeAvailDatesTimes", { required: true })} />
{errors.threeAvailDatesTimes && <span>This field is required</span>}
<input type="text" placeholder="Address" {...register("address", { required: true })} />
{errors.address && <span>This field is required</span>}
<button type="button" onClick={() => setShowCamera(true)} className="view-packages" disabled={!isFormComplete}>Proceed to vehicle capture</button>
</div>
</form>
</div>
) : (
<div>
<h3>Select a Vehicle</h3>
<div className="vehicle-buttons">
{vehicleTypes.map((vehicleType, index) => (
<button key={index} className="view-packages" onClick={() => handleVehicleSelect(vehicleType)}>
{vehicleType}
</button>
))}
</div>
{selectedVehicle && pricingMatrix[selectedVehicle] && (
<div className="pricing-matrix">
<h3>Select a Package</h3>
<div className="package">
<h4>Basic Package</h4>
<p className="service-description">{pricingMatrix[selectedVehicle].basicDescription}</p>
<p className="service-cost">Price: ${pricingMatrix[selectedVehicle].basic}</p>
<button onClick={() => handlePackageSelect('basic')} className="view-packages">Book Now</button>
</div>
<div className="package">
<h4>Standard Package</h4>
<p className="service-description">{pricingMatrix[selectedVehicle].standardDescription}</p>
<p className="service-cost">Price: ${pricingMatrix[selectedVehicle].standard}</p>
<button onClick={() => handlePackageSelect('standard')} className="view-packages">Book Now</button>
</div>
<div className="package">
<h4>Full Package</h4>
<p className="service-description">{pricingMatrix[selectedVehicle].fullDescription}</p>
<p className="service-cost">Price: ${pricingMatrix[selectedVehicle].full}</p>
<button onClick={() => handlePackageSelect('full')} className="view-packages">Book Now</button>
</div>
</div>
)}
</div>
)}
{showCamera && <AutoCameraApp onClose={handleCloseCamera} onPhotoCapture={handlePhotoCapture} formData={formData} />}
<div className="faqs">
<h3 className="faq-header">Frequently Asked Questions</h3>
<div className="faq">
<h4>How do you ensure safe detailing of exterior surfaces?</h4>
<p>To ensure safe detailing of exterior surfaces, we use a three-bucket method along with new towels for each detail. Our wheel brushes are soft, cleaned after each use, and inspected for damage. The method includes soap, rinse, and wheel buckets, each with a grit guard to catch contaminants. We then go over the vehicle's panels after rinsing them off.</p>
</div>
<div className="faq">
<h4>How can I trust the interior detailing to be immaculate?</h4>
<p>We understand the importance of interior detailing and use specialized tools such as steam cleaners, heated carpet extractors, ozone generators, specialized chemicals, and detailing brushes. Rest assured, we have all the necessary equipment and expertise to deliver exceptional interior detailing.</p>
</div>
<div className="faq">
<h4>How often should I detail my car to keep it looking new?</h4>
<p>The frequency depends on your preferences and budget. For minimal effort and year-round pristine condition, we recommend a ceramic coating package. Otherwise, we suggest a full detail annually, a standard detail biannually, and a basic detail as needed. Note that foregoing ceramic coating may result in higher long-term costs.</p>
</div>
</div>
</div>
);
};
export default AutoDetailing;
index.js
const functions = require("firebase-functions");
const cors = require("cors")({ origin: true });
const admin = require("firebase-admin");
const OpenAI = require("openai");
admin.initializeApp();
const openai = new OpenAI({
apiKey: 'REDACTED', // Replace this with your actual OpenAI API key
});
exports.analyzeImage = functions.https.onRequest((req, res) => {
res.set("Access-Control-Allow-Origin", "*");
res.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
res.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
if (req.method === "OPTIONS") {
res.status(204).send("");
return;
}
cors(req, res, async () => {
console.log("Request received:", req.body);
const imageUrl = req.body.imageUrl || (req.body.data && req.body.data.imageUrl);
console.log("Received imageUrl:", imageUrl);
if (!imageUrl) {
console.error("Missing imageUrl");
return res.status(400).send("Missing imageUrl");
}
try {
const messages = [
{
role: "user",
content: [
{ type: "text", text: "What’s in this image?" },
{ type: "image_url", image_url: { url: imageUrl } },
],
},
];
console.log("Messages payload:", JSON.stringify(messages, null, 2));
const openaiResponse = await openai.chat.completions.create({
model: "gpt-4-turbo", // Adjust the model as needed
messages: messages,
max_tokens: 300,
});
console.log("OpenAI API response:", JSON.stringify(openaiResponse, null, 2));
if (openaiResponse.choices && openaiResponse.choices.length > 0) {
const labels = openaiResponse.choices[0].message.content;
console.log("Received labels from OpenAI API:", labels);
res.status(200).json({ labels }); // Ensure to send a JSON response
} else {
throw new Error("Invalid response structure");
}
} catch (error) {
console.error("Error analyzing image:", error.message);
if (error.response) {
console.error("Error response data:", JSON.stringify(error.response.data, null, 2));
}
res.status(500).send("Internal Server Error");
}
});
});
firebase.js
const firebase = require('firebase/app');
require('firebase/firestore');
require('firebase/storage');
const firebaseConfig = {
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID,
};
firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
const storage = firebase.storage();
module.exports = { db, storage };
I’ve tried using base64 to pass through images and that failed, I’m getting a response with image url in Firebase but not in console.
Johnathon Nguyen is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.