E-waste Value Calculator

<iframe id="eWasteAppIframe" title="E-Waste Identifier AI App" width="100%" height="800px" frameborder="0" scrolling="auto" style="border: 2px solid #047857; border-radius: 1.5rem; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);" srcdoc=" E-Waste Identifier AI https://cdn.tailwindcss.com body { font-family: ‘Inter’, sans-serif; margin: 0; padding: 0; background: linear-gradient(to bottom right, #10B981, #059669); /* Green gradient */ display: flex; justify-content: center; align-items: flex-start; /* Align to top for better scroll behavior */ min-height: 100vh; padding: 2rem; box-sizing: border-box; overflow-y: auto; /* Ensure body itself is scrollable if content overflows */ } /* Custom styles for button focus and hover effects */ .btn-primary { background-color: #047857; /* Darker emerald for buttons */ color: white; transition: all 0.3s ease; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .btn-primary:hover:not(:disabled) { background-color: #065F46; /* Even darker on hover */ transform: translateY(-2px); box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15); } .btn-primary:focus:not(:disabled) { outline: none; box-shadow: 0 0 0 3px rgba(4, 120, 87, 0.5); } .btn-secondary { background-color: #D1FAE5; /* Lighter emerald for secondary */ color: #047857; transition: all 0.3s ease; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .btn-secondary:hover:not(:disabled) { background-color: #A7F3D0; transform: translateY(-2px); box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15); } .btn-secondary:focus:not(:disabled) { outline: none; box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.5); } .btn-red { background-color: #EF4444; /* Red for sign out */ color: white; transition: all 0.3s ease; } .btn-red:hover:not(:disabled) { background-color: #DC2626; transform: translateY(-2px); } .btn-red:focus:not(:disabled) { outline: none; box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.5); } .input-field { padding: 0.75rem; border-radius: 0.5rem; border: 2px solid #D1D5DB; /* Gray-300 */ transition: border-color 0.2s ease; } .input-field:focus { outline: none; border-color: #10B981; /* Emerald-500 */ } .scrollable-content { max-height: 500px; /* Example max height for the classifications list */ overflow-y: auto; -webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */ } /* Custom scrollbar for better aesthetics (optional) */ .scrollable-content::-webkit-scrollbar { width: 8px; } .scrollable-content::-webkit-scrollbar-track { background: #f1f1f1; border-radius: 10px; } .scrollable-content::-webkit-scrollbar-thumb { background: #888; border-radius: 10px; } .scrollable-content::-webkit-scrollbar-thumb:hover { background: #555; }

🌍 E-Waste Identifier AI ♻️

Welcome! Please Sign In or Sign Up

Sign In Sign Up
import { initializeApp } from ‘https://www.gstatic.com/firebasejs/11.6.1/firebase-app.js&#8217;; import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged, createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut } from ‘https://www.gstatic.com/firebasejs/11.6.1/firebase-auth.js&#8217;; import { getFirestore, doc, getDoc, addDoc, setDoc, updateDoc, deleteDoc, onSnapshot, collection, query, where, getDocs, orderBy, limit } from ‘https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js&#8217;; // !!! IMPORTANT: Replace with your actual Firebase Project Configuration !!! // Get this from your Firebase Project settings -> General -> Your apps -> Web app -> Config const firebaseConfig = { apiKey: ‘YOUR_API_KEY’, authDomain: ‘YOUR_AUTH_DOMAIN’, projectId: ‘YOUR_PROJECT_ID’, storageBucket: ‘YOUR_STORAGE_BUCKET’, messagingSenderId: ‘YOUR_MESSAGING_SENDER_ID’, appId: ‘YOUR_APP_ID’ }; const appId = firebaseConfig.projectId || ‘e-waste-identifier’; // Use Firebase projectId as unique app ID let app; let db; let auth; let currentUserId = null; let currentAuthReady = false; // To track if auth state has been initially checked // DOM Elements const authSection = document.getElementById(‘auth-section’); const mainAppSection = document.getElementById(‘main-app-section’); const emailInput = document.getElementById(’email-input’); const passwordInput = document.getElementById(‘password-input’); const signInButton = document.getElementById(‘signin-button’); const signUpButton = document.getElementById(‘signup-button’); const signOutButton = document.getElementById(‘signout-button’); const userIdDisplay = document.getElementById(‘user-id-display’); const authErrorMessage = document.getElementById(‘auth-error-message’); const imageUploadInput = document.getElementById(‘image-upload’); const imagePreviewContainer = document.getElementById(‘image-preview-container’); const imagePreview = document.getElementById(‘image-preview’); const classifyButton = document.getElementById(‘classify-button’); const aiResponseSection = document.getElementById(‘ai-response-section’); const aiResponseText = document.getElementById(‘ai-response-text’); const accurateButton = document.getElementById(‘accurate-button’); const inaccurateButton = document.getElementById(‘inaccurate-button’); const appErrorMessage = document.getElementById(‘app-error-message’); const appErrorText = document.getElementById(‘app-error-text’); const classificationsList = document.getElementById(‘classifications-list’); let selectedImageFile = null; let lastClassificationDocId = null; // To store the Firestore doc ID of the last classification // Utility function to display auth errors function displayAuthError(message) { authErrorMessage.textContent = message; authErrorMessage.classList.remove(‘hidden’); } // Utility function to display general app errors function displayAppError(message) { appErrorText.textContent = message; appErrorMessage.classList.remove(‘hidden’); } // Utility function to clear all errors function clearErrors() { authErrorMessage.classList.add(‘hidden’); appErrorMessage.classList.add(‘hidden’); authErrorMessage.textContent = ”; appErrorText.textContent = ”; } // — Firebase Initialization and Authentication — async function initFirebase() { try { app = initializeApp(firebaseConfig); db = getFirestore(app); auth = getAuth(app); onAuthStateChanged(auth, async (user) => { clearErrors(); if (user) { currentUserId = user.uid; userIdDisplay.innerHTML = `Your User ID: ${currentUserId}`; showMainApp(); loadClassifications(); // Load classifications only when authenticated } else { currentUserId = null; userIdDisplay.innerHTML = ”; showAuthForms(); // Attempt anonymous sign-in as a fallback if no user is logged in try { await signInAnonymously(auth); } catch (anonError) { console.error(‘Firebase anonymous auth failed:’, anonError); displayAuthError(‘Failed to authenticate anonymously. Please sign in or sign up.’); } } currentAuthReady = true; // Mark auth as ready after initial check }); } catch (e) { console.error(“Firebase Initialization Error:”, e); displayAuthError(“Failed to initialize Firebase. Please check your firebaseConfig.”); } } // — UI Toggling — function showAuthForms() { authSection.classList.remove(‘hidden’); mainAppSection.classList.add(‘hidden’); // Reset app state when logging out imageUploadInput.value = ”; imagePreviewContainer.classList.add(‘hidden’); imagePreview.src = ”; aiResponseSection.classList.add(‘hidden’); aiResponseText.textContent = ”; accurateButton.classList.remove(‘bg-green-600’, ‘bg-red-600’); inaccurateButton.classList.remove(‘bg-green-600’, ‘bg-red-600’); accurateButton.classList.add(‘btn-primary’); inaccurateButton.classList.add(‘btn-red’); classificationsList.innerHTML = ‘

No classifications yet. Be the first to submit one!

‘; } function showMainApp() { authSection.classList.add(‘hidden’); mainAppSection.classList.remove(‘hidden’); } // — Authentication Handlers — signInButton.addEventListener(‘click’, async () => { clearErrors(); const email = emailInput.value; const password = passwordInput.value; if (!email || !password) { displayAuthError(‘Please enter both email and password.’); return; } signInButton.disabled = true; signUpButton.disabled = true; try { await signInWithEmailAndPassword(auth, email, password); emailInput.value = ”; // Clear inputs on success passwordInput.value = ”; } catch (error) { displayAuthError(error.message || ‘Failed to sign in.’); console.error(‘Sign In Error:’, error); } finally { signInButton.disabled = false; signUpButton.disabled = false; } }); signUpButton.addEventListener(‘click’, async () => { clearErrors(); const email = emailInput.value; const password = passwordInput.value; if (!email || !password) { displayAuthError(‘Please enter both email and password.’); return; } signUpButton.disabled = true; signInButton.disabled = true; try { await createUserWithEmailAndPassword(auth, email, password); emailInput.value = ”; // Clear inputs on success passwordInput.value = ”; } catch (error) { displayAuthError(error.message || ‘Failed to sign up.’); console.error(‘Sign Up Error:’, error); } finally { signUpButton.disabled = false; signInButton.disabled = false; } }); signOutButton.addEventListener(‘click’, async () => { clearErrors(); signOutButton.disabled = true; try { await signOut(auth); } catch (error) { displayAuthError(error.message || ‘Failed to sign out.’); console.error(‘Sign Out Error:’, error); } finally { signOutButton.disabled = false; } }); // — Image Handling — imageUploadInput.addEventListener(‘change’, (event) => { clearErrors(); const file = event.target.files[0]; if (file) { selectedImageFile = file; const reader = new FileReader(); reader.onloadend = () => { imagePreview.src = reader.result; imagePreviewContainer.classList.remove(‘hidden’); aiResponseSection.classList.add(‘hidden’); // Clear previous AI response aiResponseText.textContent = ”; accurateButton.classList.remove(‘bg-green-600’, ‘bg-red-600’); inaccurateButton.classList.remove(‘bg-green-600’, ‘bg-red-600’); accurateButton.classList.add(‘btn-primary’); inaccurateButton.classList.add(‘btn-red’); }; reader.readAsDataURL(file); classifyButton.disabled = false; // Enable classify button } else { selectedImageFile = null; imagePreviewContainer.classList.add(‘hidden’); imagePreview.src = ”; classifyButton.disabled = true; } }); function fileToBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result.split(‘,’)[1]); // Get base64 string reader.onerror = error => reject(error); }); } // — AI Classification — classifyButton.addEventListener(‘click’, async () => { clearErrors(); if (!selectedImageFile) { displayAppError(‘Please select an image first.’); return; } if (!currentUserId) { displayAppError(‘You must be logged in to classify images.’); return; } classifyButton.disabled = true; classifyButton.innerHTML = ` Classifying… `; aiResponseSection.classList.add(‘hidden’); aiResponseText.textContent = ”; lastClassificationDocId = null; // Reset for new classification try { const base64ImageData = await fileToBase64(selectedImageFile); const prompt = ‘Identify all e-waste items in this image and describe them. For each identified e-waste item, also list potential major electronic components (e.g., circuit boards, capacitors, CPUs, LCD screens, batteries, wires, power supplies, memory modules, hard drives, optical drives, cooling fans) that might be found inside. If no e-waste is present, state that clearly and briefly. Be concise and provide a list of identified items and their components.’; const payload = { contents: [ { role: ‘user’, parts: [ { text: prompt }, { inlineData: { mimeType: selectedImageFile.type, data: base64ImageData } } ] } ], }; const apiKey = ”; // Leave this empty. Canvas will provide at runtime for its environment. // For your external website, this would typically be a server-side call // or you’d manage API keys securely. const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`; const response = await fetch(apiUrl, { method: ‘POST’, headers: { ‘Content-Type’: ‘application/json’ }, body: JSON.stringify(payload) }); const result = await response.json(); if (result.candidates && result.candidates.length > 0 && result.candidates[0].content && result.candidates[0].content.parts && result.candidates[0].content.parts.length > 0) { const text = result.candidates[0].content.parts[0].text; aiResponseText.textContent = text; aiResponseSection.classList.remove(‘hidden’); // Save initial classification result to Firestore const classificationRef = collection(db, `artifacts/${appId}/public/data/eWasteClassifications`); const docRef = await addDoc(classificationRef, { userId: currentUserId, timestamp: new Date(), imagePrompt: prompt, aiPrediction: text, userRating: ‘Not Rated’ }); lastClassificationDocId = docRef.id; // Store for rating } else { aiResponseText.textContent = ‘Could not identify e-waste. Please try another image.’; displayAppError(‘AI response was empty or malformed.’); } } catch (err) { console.error(‘AI Classification Error:’, err); displayAppError(`Failed to classify image: ${err.message}.`); } finally { classifyButton.disabled = false; classifyButton.textContent = ‘Classify E-Waste’; } }); // — Rating Functionality — accurateButton.addEventListener(‘click’, () => updateRating(‘Accurate’)); inaccurateButton.addEventListener(‘click’, () => updateRating(‘Inaccurate’)); async function updateRating(rating) { clearErrors(); if (!lastClassificationDocId || !currentUserId) { displayAppError(‘No recent classification found for your user to rate or not logged in.’); return; } // Visually update buttons immediately accurateButton.classList.remove(‘bg-green-600’, ‘bg-red-600’, ‘btn-primary’); inaccurateButton.classList.remove(‘bg-green-600’, ‘bg-red-600’, ‘btn-red’); if (rating === ‘Accurate’) { accurateButton.classList.add(‘bg-green-600’); inaccurateButton.classList.add(‘btn-red’); // Keep default style for inactive } else { inaccurateButton.classList.add(‘bg-red-600’); accurateButton.classList.add(‘btn-primary’); // Keep default style for inactive } try { const classificationDocRef = doc(db, `artifacts/${appId}/public/data/eWasteClassifications`, lastClassificationDocId); await updateDoc(classificationDocRef, { userRating: rating }); // Firestore onSnapshot will automatically update the list } catch (err) { console.error(‘Error updating rating:’, err); displayAppError(`Failed to update rating: ${err.message}.`); } } // — Load Classifications (Real-time) — function loadClassifications() { if (!db || !currentUserId) { // Only load if Firebase is initialized and user is logged in console.log(‘Firebase DB not ready or user not logged in, skipping classification load.’); return; } const classificationsCollectionRef = collection(db, `artifacts/${appId}/public/data/eWasteClassifications`); const q = query(classificationsCollectionRef, orderBy(‘timestamp’, ‘desc’), limit(10)); onSnapshot(q, (snapshot) => { let htmlContent = ”; if (snapshot.empty) { htmlContent = ‘

No classifications yet. Be the first to submit one!

‘; } else { snapshot.docs.forEach(doc => { const item = doc.data(); const timestamp = item.timestamp?.toDate ? item.timestamp.toDate().toLocaleString() : ‘N/A’; const userIdShort = item.userId ? `${item.userId.substring(0, 8)}…` : ‘Anonymous’; let ratingColorClass = ‘bg-gray-100 text-gray-800’; if (item.userRating === ‘Accurate’) { ratingColorClass = ‘bg-green-100 text-green-800’; } else if (item.userRating === ‘Inaccurate’) { ratingColorClass = ‘bg-red-100 text-red-800’; } htmlContent += `

User: ${userIdShort}

${timestamp}

AI identified:

${item.aiPrediction || ‘No prediction available.’}

Rating: ${item.userRating}
`; }); } classificationsList.innerHTML = htmlContent; }, (error) => { console.error(‘Error fetching classifications:’, error); displayAppError(‘Failed to load past classifications.’); }); } // Initialize Firebase when the window loads window.onload = initFirebase; ” >

<iframe

    id=”eWasteAppIframe”

    title=”E-Waste Identifier AI App”

    width=”100%”

    height=”800px”

    frameborder=”0″

    scrolling=”auto”

    style=”border: 2px solid #047857; border-radius: 1.5rem; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);”

    srcdoc=”

        <!DOCTYPE html>

        <html lang=’en’>

        <head>

            <meta charset=’UTF-8′>

            <meta name=’viewport’ content=’width=device-width, initial-scale=1.0′>

            <title>E-Waste Identifier AI</title>

            <!– Tailwind CSS CDN –>

            https://cdn.tailwindcss.com

            <style>

                body {

                    font-family: ‘Inter’, sans-serif;

                    margin: 0;

                    padding: 0;

                    background: linear-gradient(to bottom right, #10B981, #059669); /* Green gradient */

                    display: flex;

                    justify-content: center;

                    align-items: flex-start; /* Align to top for better scroll behavior */

                    min-height: 100vh;

                    padding: 2rem;

                    box-sizing: border-box;

                    overflow-y: auto; /* Ensure body itself is scrollable if content overflows */

                }

 

                /* Custom styles for button focus and hover effects */

                .btn-primary {

                    background-color: #047857; /* Darker emerald for buttons */

                    color: white;

                    transition: all 0.3s ease;

                    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);

                }

                .btn-primary:hover:not(:disabled) {

                    background-color: #065F46; /* Even darker on hover */

                    transform: translateY(-2px);

                    box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);

                }

                .btn-primary:focus:not(:disabled) {

                    outline: none;

                    box-shadow: 0 0 0 3px rgba(4, 120, 87, 0.5);

                }

 

                .btn-secondary {

                    background-color: #D1FAE5; /* Lighter emerald for secondary */

                    color: #047857;

                    transition: all 0.3s ease;

                    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);

                }

                .btn-secondary:hover:not(:disabled) {

                    background-color: #A7F3D0;

                    transform: translateY(-2px);

                    box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);

                }

                .btn-secondary:focus:not(:disabled) {

                    outline: none;

                    box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.5);

                }

 

                .btn-red {

                    background-color: #EF4444; /* Red for sign out */

                    color: white;

                    transition: all 0.3s ease;

                }

                .btn-red:hover:not(:disabled) {

                    background-color: #DC2626;

                    transform: translateY(-2px);

                }

                .btn-red:focus:not(:disabled) {

                    outline: none;

                    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.5);

                }

 

                .input-field {

                    padding: 0.75rem;

                    border-radius: 0.5rem;

                    border: 2px solid #D1D5DB; /* Gray-300 */

                    transition: border-color 0.2s ease;

                }

                .input-field:focus {

                    outline: none;

                    border-color: #10B981; /* Emerald-500 */

                }

 

                .scrollable-content {

                    max-height: 500px; /* Example max height for the classifications list */

                    overflow-y: auto;

                    -webkit-overflow-scrolling: touch; /* Smooth scrolling on iOS */

                }

 

                /* Custom scrollbar for better aesthetics (optional) */

                .scrollable-content::-webkit-scrollbar {

                    width: 8px;

                }

 

                .scrollable-content::-webkit-scrollbar-track {

                    background: #f1f1f1;

                    border-radius: 10px;

                }

 

                .scrollable-content::-webkit-scrollbar-thumb {

                    background: #888;

                    border-radius: 10px;

                }

 

                .scrollable-content::-webkit-scrollbar-thumb:hover {

                    background: #555;

                }

            </style>

        </head>

        <body>

            <div id=’app-container’ class=’bg-white rounded-3xl shadow-2xl p-6 sm:p-8 w-full max-w-4xl space-y-8 flex flex-col justify-center items-center my-8′>

                <h1 class=’text-4xl sm:text-5xl font-extrabold text-center text-gray-800 mb-6′>

                    🌍 E-Waste Identifier AI ♻️

                </h1>

 

                <!– Authentication Error Message –>

                <div id=’auth-error-message’ class=’hidden mt-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded-xl text-center w-full’></div>

 

                <!– Authentication Section –>

                <div id=’auth-section’ class=’w-full space-y-6′>

                    <h2 class=’text-3xl font-bold text-center text-emerald-800′>Welcome! Please Sign In or Sign Up</h2>

                    <input type=’email’ id=’email-input’ placeholder=’Email’ class=’input-field w-full’ />

                    <input type=’password’ id=’password-input’ placeholder=’Password’ class=’input-field w-full’ />

                    <div class=’flex flex-col sm:flex-row justify-center space-y-4 sm:space-y-0 sm:space-x-4′>

                        <button id=’signin-button’ class=’flex-1 py-3 px-6 rounded-xl font-bold text-lg btn-primary’>

                            Sign In

                        </button>

                        <button id=’signup-button’ class=’flex-1 py-3 px-6 rounded-xl font-bold text-lg btn-secondary’>

                            Sign Up

                        </button>

                    </div>

                </div>

 

                <!– Main App Section (hidden initially) –>

                <div id=’main-app-section’ class=’hidden w-full’>

                    <!– User ID Display and Sign Out Button –>

                    <div class=’flex flex-col sm:flex-row justify-between items-center mb-4 space-y-2 sm:space-y-0′>

                        <div id=’user-id-display’ class=’text-gray-600 text-sm font-medium’></div>

                        <button id=’signout-button’ class=’py-2 px-4 rounded-xl text-sm font-semibold btn-red’>

                            Sign Out

                        </button>

                    </div>

 

                    <!– Image Upload Section –>

                    <div class=’space-y-4′>

                        <label for=’image-upload’ class=’block text-lg font-semibold text-gray-700′>

                            Upload an image of potential e-waste:

                        </label>

                        <input

                            type=’file’

                            id=’image-upload’

                            accept=’image/*’

                            class=’block w-full text-sm text-gray-700

                                file:mr-4 file:py-2 file:px-4

                                file:rounded-full file:border-0

                                file:text-sm file:font-semibold

                                file:bg-emerald-50 file:text-emerald-700

                                hover:file:bg-emerald-100′

                        />

                        <div id=’image-preview-container’ class=’mt-4 flex justify-center hidden’>

                            <img id=’image-preview’ alt=’Selected Preview’ class=’max-w-xs sm:max-w-md h-auto rounded-xl shadow-lg border-2 border-emerald-300′ />

                        </div>

                        <button id=’classify-button’ class=’w-full py-3 px-6 rounded-xl font-bold text-lg btn-primary’ disabled>

                            Classify E-Waste

                        </button>

                    </div>

 

                    <!– AI Response Section –>

                    <div id=’ai-response-section’ class=’hidden mt-8 bg-emerald-50 border border-emerald-300 rounded-xl p-5 shadow-inner’>

                        <h2 class=’text-2xl font-semibold text-emerald-800 mb-3′>AI’s Identification:</h2>

                        <p id=’ai-response-text’ class=’text-gray-700 leading-relaxed whitespace-pre-wrap’></p>

                        <div class=’mt-4 flex flex-col sm:flex-row items-center justify-center space-y-3 sm:space-y-0 sm:space-x-4′>

                            <span class=’text-lg font-semibold text-gray-700′>Was this accurate?</span>

                            <button id=’accurate-button’ class=’py-2 px-5 rounded-full text-white font-semibold btn-primary’>

                                Accurate 👍

                            </button>

                            <button id=’inaccurate-button’ class=’py-2 px-5 rounded-full text-white font-semibold btn-red’>

                                Inaccurate 👎

                            </button>

                        </div>

                    </div>

 

                    <!– Error Display –>

                    <div id=’app-error-message’ class=’hidden mt-4 p-3 bg-red-100 border border-red-400 text-red-700 rounded-xl w-full’>

                        <p class=’font-semibold’>Error:</p>

                        <p id=’app-error-text’></p>

                    </div>

 

                    <!– Past Classifications (Social Media Aspect) –>

                    <div class=’mt-10 pt-8 border-t-2 border-emerald-200 w-full’>

                        <h2 class=’text-3xl font-bold text-center text-emerald-800 mb-6′>Recent Community Classifications</h2>

                        <div id=’classifications-list’ class=’space-y-6 scrollable-content’>

                            <p class=’text-center text-gray-600′>No classifications yet. Be the first to submit one!</p>

                        </div>

                    </div>

                </div>

            </div>

 

            <!– Firebase SDKs –>

            <script type=’module’>

                import { initializeApp } from ‘https://www.gstatic.com/firebasejs/11.6.1/firebase-app.js&#8217;;

                import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged, createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut } from ‘https://www.gstatic.com/firebasejs/11.6.1/firebase-auth.js&#8217;;

                import { getFirestore, doc, getDoc, addDoc, setDoc, updateDoc, deleteDoc, onSnapshot, collection, query, where, getDocs, orderBy, limit } from ‘https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js&#8217;;

 

                // !!! IMPORTANT: Replace with your actual Firebase Project Configuration !!!

                // Get this from your Firebase Project settings -> General -> Your apps -> Web app -> Config

                const firebaseConfig = {

                    apiKey: ‘YOUR_API_KEY’,

                    authDomain: ‘YOUR_AUTH_DOMAIN’,

                    projectId: ‘YOUR_PROJECT_ID’,

                    storageBucket: ‘YOUR_STORAGE_BUCKET’,

                    messagingSenderId: ‘YOUR_MESSAGING_SENDER_ID’,

                    appId: ‘YOUR_APP_ID’

                };

 

                const appId = firebaseConfig.projectId || ‘e-waste-identifier’; // Use Firebase projectId as unique app ID

 

                let app;

                let db;

                let auth;

                let currentUserId = null;

                let currentAuthReady = false; // To track if auth state has been initially checked

 

                // DOM Elements

                const authSection = document.getElementById(‘auth-section’);

                const mainAppSection = document.getElementById(‘main-app-section’);

                const emailInput = document.getElementById(’email-input’);

                const passwordInput = document.getElementById(‘password-input’);

                const signInButton = document.getElementById(‘signin-button’);

                const signUpButton = document.getElementById(‘signup-button’);

                const signOutButton = document.getElementById(‘signout-button’);

                const userIdDisplay = document.getElementById(‘user-id-display’);

                const authErrorMessage = document.getElementById(‘auth-error-message’);

 

                const imageUploadInput = document.getElementById(‘image-upload’);

                const imagePreviewContainer = document.getElementById(‘image-preview-container’);

                const imagePreview = document.getElementById(‘image-preview’);

                const classifyButton = document.getElementById(‘classify-button’);

                const aiResponseSection = document.getElementById(‘ai-response-section’);

                const aiResponseText = document.getElementById(‘ai-response-text’);

                const accurateButton = document.getElementById(‘accurate-button’);

                const inaccurateButton = document.getElementById(‘inaccurate-button’);

                const appErrorMessage = document.getElementById(‘app-error-message’);

                const appErrorText = document.getElementById(‘app-error-text’);

                const classificationsList = document.getElementById(‘classifications-list’);

 

                let selectedImageFile = null;

                let lastClassificationDocId = null; // To store the Firestore doc ID of the last classification

 

                // Utility function to display auth errors

                function displayAuthError(message) {

                    authErrorMessage.textContent = message;

                    authErrorMessage.classList.remove(‘hidden’);

                }

 

                // Utility function to display general app errors

                function displayAppError(message) {

                    appErrorText.textContent = message;

                    appErrorMessage.classList.remove(‘hidden’);

                }

 

                // Utility function to clear all errors

                function clearErrors() {

                    authErrorMessage.classList.add(‘hidden’);

                    appErrorMessage.classList.add(‘hidden’);

                    authErrorMessage.textContent = ”;

                    appErrorText.textContent = ”;

                }

 

                // — Firebase Initialization and Authentication —

                async function initFirebase() {

                    try {

                        app = initializeApp(firebaseConfig);

                        db = getFirestore(app);

                        auth = getAuth(app);

 

                        onAuthStateChanged(auth, async (user) => {

                            clearErrors();

                            if (user) {

                                currentUserId = user.uid;

                                userIdDisplay.innerHTML = `Your User ID: <span class=’font-semibold text-green-700 break-all’>${currentUserId}</span>`;

                                showMainApp();

                                loadClassifications(); // Load classifications only when authenticated

                            } else {

                                currentUserId = null;

                                userIdDisplay.innerHTML = ”;

                                showAuthForms();

                                // Attempt anonymous sign-in as a fallback if no user is logged in

                                try {

                                    await signInAnonymously(auth);

                                } catch (anonError) {

                                    console.error(‘Firebase anonymous auth failed:’, anonError);

                                    displayAuthError(‘Failed to authenticate anonymously. Please sign in or sign up.’);

                                }

                            }

                            currentAuthReady = true; // Mark auth as ready after initial check

                        });

                    } catch (e) {

                        console.error(“Firebase Initialization Error:”, e);

                        displayAuthError(“Failed to initialize Firebase. Please check your firebaseConfig.”);

                    }

                }

 

                // — UI Toggling —

                function showAuthForms() {

                    authSection.classList.remove(‘hidden’);

                    mainAppSection.classList.add(‘hidden’);

                    // Reset app state when logging out

                    imageUploadInput.value = ”;

                    imagePreviewContainer.classList.add(‘hidden’);

                    imagePreview.src = ”;

                    aiResponseSection.classList.add(‘hidden’);

                    aiResponseText.textContent = ”;

                    accurateButton.classList.remove(‘bg-green-600’, ‘bg-red-600’);

                    inaccurateButton.classList.remove(‘bg-green-600’, ‘bg-red-600’);

                    accurateButton.classList.add(‘btn-primary’);

                    inaccurateButton.classList.add(‘btn-red’);

                    classificationsList.innerHTML = ‘<p class=\’text-center text-gray-600\’>No classifications yet. Be the first to submit one!</p>’;

                }

 

                function showMainApp() {

                    authSection.classList.add(‘hidden’);

                    mainAppSection.classList.remove(‘hidden’);

                }

 

                // — Authentication Handlers —

                signInButton.addEventListener(‘click’, async () => {

                    clearErrors();

                    const email = emailInput.value;

                    const password = passwordInput.value;

                    if (!email || !password) {

                        displayAuthError(‘Please enter both email and password.’);

                        return;

                    }

                    signInButton.disabled = true;

                    signUpButton.disabled = true;

                    try {

                        await signInWithEmailAndPassword(auth, email, password);

                        emailInput.value = ”; // Clear inputs on success

                        passwordInput.value = ”;

                    } catch (error) {

                        displayAuthError(error.message || ‘Failed to sign in.’);

                        console.error(‘Sign In Error:’, error);

                    } finally {

                        signInButton.disabled = false;

                        signUpButton.disabled = false;

                    }

                });

 

                signUpButton.addEventListener(‘click’, async () => {

                    clearErrors();

                    const email = emailInput.value;

                    const password = passwordInput.value;

                    if (!email || !password) {

                        displayAuthError(‘Please enter both email and password.’);

                        return;

                    }

                    signUpButton.disabled = true;

                    signInButton.disabled = true;

                    try {

                        await createUserWithEmailAndPassword(auth, email, password);

                        emailInput.value = ”; // Clear inputs on success

                        passwordInput.value = ”;

                    } catch (error) {

                        displayAuthError(error.message || ‘Failed to sign up.’);

                        console.error(‘Sign Up Error:’, error);

                    } finally {

                        signUpButton.disabled = false;

                        signInButton.disabled = false;

                    }

                });

 

                signOutButton.addEventListener(‘click’, async () => {

                    clearErrors();

                    signOutButton.disabled = true;

                    try {

                        await signOut(auth);

                    } catch (error) {

                        displayAuthError(error.message || ‘Failed to sign out.’);

                        console.error(‘Sign Out Error:’, error);

                    } finally {

                        signOutButton.disabled = false;

                    }

                });

 

                // — Image Handling —

                imageUploadInput.addEventListener(‘change’, (event) => {

                    clearErrors();

                    const file = event.target.files[0];

                    if (file) {

                        selectedImageFile = file;

                        const reader = new FileReader();

                        reader.onloadend = () => {

                            imagePreview.src = reader.result;

                            imagePreviewContainer.classList.remove(‘hidden’);

                            aiResponseSection.classList.add(‘hidden’); // Clear previous AI response

                            aiResponseText.textContent = ”;

                            accurateButton.classList.remove(‘bg-green-600’, ‘bg-red-600’);

                            inaccurateButton.classList.remove(‘bg-green-600’, ‘bg-red-600’);

                            accurateButton.classList.add(‘btn-primary’);

                            inaccurateButton.classList.add(‘btn-red’);

                        };

                        reader.readAsDataURL(file);

                        classifyButton.disabled = false; // Enable classify button

                    } else {

                        selectedImageFile = null;

                        imagePreviewContainer.classList.add(‘hidden’);

                        imagePreview.src = ”;

                        classifyButton.disabled = true;

                    }

                });

 

                function fileToBase64(file) {

                    return new Promise((resolve, reject) => {

                        const reader = new FileReader();

                        reader.readAsDataURL(file);

                        reader.onload = () => resolve(reader.result.split(‘,’)[1]); // Get base64 string

                        reader.onerror = error => reject(error);

                    });

                }

 

                // — AI Classification —

                classifyButton.addEventListener(‘click’, async () => {

                    clearErrors();

                    if (!selectedImageFile) {

                        displayAppError(‘Please select an image first.’);

                        return;

                    }

                    if (!currentUserId) {

                        displayAppError(‘You must be logged in to classify images.’);

                        return;

                    }

 

                    classifyButton.disabled = true;

                    classifyButton.innerHTML = `

                        <span class=’flex items-center justify-center’>

                            <svg class=’animate-spin -ml-1 mr-3 h-5 w-5 text-white’ xmlns=’http://www.w3.org/2000/svg&#8217; fill=’none’ viewBox=’0 0 24 24′>

                                <circle class=’opacity-25′ cx=’12’ cy=’12’ r=’10’ stroke=’currentColor’ stroke-width=’4′></circle>

                                <path class=’opacity-75′ fill=’currentColor’ d=’M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z’></path>

                            </svg>

                            Classifying…

                        </span>

                    `;

                    aiResponseSection.classList.add(‘hidden’);

                    aiResponseText.textContent = ”;

                    lastClassificationDocId = null; // Reset for new classification

 

                    try {

                        const base64ImageData = await fileToBase64(selectedImageFile);

                        const prompt = ‘Identify all e-waste items in this image and describe them. For each identified e-waste item, also list potential major electronic components (e.g., circuit boards, capacitors, CPUs, LCD screens, batteries, wires, power supplies, memory modules, hard drives, optical drives, cooling fans) that might be found inside. If no e-waste is present, state that clearly and briefly. Be concise and provide a list of identified items and their components.’;

 

                        const payload = {

                            contents: [

                                {

                                    role: ‘user’,

                                    parts: [

                                        { text: prompt },

                                        {

                                            inlineData: {

                                                mimeType: selectedImageFile.type,

                                                data: base64ImageData

                                            }

                                        }

                                    ]

                                }

                            ],

                        };

                        const apiKey = ”; // Leave this empty. Canvas will provide at runtime for its environment.

                                         // For your external website, this would typically be a server-side call

                                         // or you’d manage API keys securely.

                        const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${apiKey}`;

 

                        const response = await fetch(apiUrl, {

                            method: ‘POST’,

                            headers: { ‘Content-Type’: ‘application/json’ },

                            body: JSON.stringify(payload)

                        });

 

                        const result = await response.json();

 

                        if (result.candidates && result.candidates.length > 0 &&

                            result.candidates[0].content && result.candidates[0].content.parts &&

                            result.candidates[0].content.parts.length > 0) {

                            const text = result.candidates[0].content.parts[0].text;

                            aiResponseText.textContent = text;

                            aiResponseSection.classList.remove(‘hidden’);

 

                            // Save initial classification result to Firestore

                            const classificationRef = collection(db, `artifacts/${appId}/public/data/eWasteClassifications`);

                            const docRef = await addDoc(classificationRef, {

                                userId: currentUserId,

                                timestamp: new Date(),

                                imagePrompt: prompt,

                                aiPrediction: text,

                                userRating: ‘Not Rated’

                            });

                            lastClassificationDocId = docRef.id; // Store for rating

                        } else {

                            aiResponseText.textContent = ‘Could not identify e-waste. Please try another image.’;

                            displayAppError(‘AI response was empty or malformed.’);

                        }

                    } catch (err) {

                        console.error(‘AI Classification Error:’, err);

                        displayAppError(`Failed to classify image: ${err.message}.`);

                    } finally {

                        classifyButton.disabled = false;

                        classifyButton.textContent = ‘Classify E-Waste’;

                    }

                });

 

                // — Rating Functionality —

                accurateButton.addEventListener(‘click’, () => updateRating(‘Accurate’));

                inaccurateButton.addEventListener(‘click’, () => updateRating(‘Inaccurate’));

 

                async function updateRating(rating) {

                    clearErrors();

                    if (!lastClassificationDocId || !currentUserId) {

                        displayAppError(‘No recent classification found for your user to rate or not logged in.’);

                        return;

                    }

 

                    // Visually update buttons immediately

                    accurateButton.classList.remove(‘bg-green-600’, ‘bg-red-600’, ‘btn-primary’);

                    inaccurateButton.classList.remove(‘bg-green-600’, ‘bg-red-600’, ‘btn-red’);

                    if (rating === ‘Accurate’) {

                        accurateButton.classList.add(‘bg-green-600’);

                        inaccurateButton.classList.add(‘btn-red’); // Keep default style for inactive

                    } else {

                        inaccurateButton.classList.add(‘bg-red-600’);

                        accurateButton.classList.add(‘btn-primary’); // Keep default style for inactive

                    }

 

                    try {

                        const classificationDocRef = doc(db, `artifacts/${appId}/public/data/eWasteClassifications`, lastClassificationDocId);

                        await updateDoc(classificationDocRef, { userRating: rating });

                        // Firestore onSnapshot will automatically update the list

                    } catch (err) {

                        console.error(‘Error updating rating:’, err);

                        displayAppError(`Failed to update rating: ${err.message}.`);

                    }

                }

 

                // — Load Classifications (Real-time) —

                function loadClassifications() {

                    if (!db || !currentUserId) { // Only load if Firebase is initialized and user is logged in

                        console.log(‘Firebase DB not ready or user not logged in, skipping classification load.’);

                        return;

                    }

 

                    const classificationsCollectionRef = collection(db, `artifacts/${appId}/public/data/eWasteClassifications`);

                    const q = query(classificationsCollectionRef, orderBy(‘timestamp’, ‘desc’), limit(10));

 

                    onSnapshot(q, (snapshot) => {

                        let htmlContent = ”;

                        if (snapshot.empty) {

                            htmlContent = ‘<p class=\’text-center text-gray-600\’>No classifications yet. Be the first to submit one!</p>’;

                        } else {

                            snapshot.docs.forEach(doc => {

                                const item = doc.data();

                                const timestamp = item.timestamp?.toDate ? item.timestamp.toDate().toLocaleString() : ‘N/A’;

                                const userIdShort = item.userId ? `${item.userId.substring(0, 8)}…` : ‘Anonymous’;

                                let ratingColorClass = ‘bg-gray-100 text-gray-800’;

                                if (item.userRating === ‘Accurate’) {

                                    ratingColorClass = ‘bg-green-100 text-green-800’;

                                } else if (item.userRating === ‘Inaccurate’) {

                                    ratingColorClass = ‘bg-red-100 text-red-800’;

                                }

 

                                htmlContent += `

                                    <div class=’bg-emerald-50 rounded-xl p-5 shadow-md border border-emerald-200′>

                                        <div class=’flex justify-between items-start mb-2′>

                                            <p class=’text-sm font-medium text-gray-600′>

                                                User: <span class=’font-bold text-emerald-700′>${userIdShort}</span>

                                            </p>

                                            <p class=’text-xs text-gray-500′>${timestamp}</p>

                                        </div>

                                        <h3 class=’text-lg font-semibold text-gray-800 mb-2′>AI identified:</h3>

                                        <p class=’text-gray-700 mb-3 whitespace-pre-wrap’>${item.aiPrediction || ‘No prediction available.’}</p>

                                        <div class=’text-right’>

                                            <span class=’inline-flex items-center px-3 py-1 rounded-full text-sm font-medium ${ratingColorClass}’>

                                                Rating: ${item.userRating}

                                            </span>

                                        </div>

                                    </div>

                                `;

                            });

                        }

                        classificationsList.innerHTML = htmlContent;

                    }, (error) => {

                        console.error(‘Error fetching classifications:’, error);

                        displayAppError(‘Failed to load past classifications.’);

                    });

                }

 

                // Initialize Firebase when the window loads

                window.onload = initFirebase;

            </script>

        </body>

        </html>

    “

></iframe>