// frontend/visual_search_test.js const VisualSearchTester = { config: { apiEndpoint: "", }, elements: {}, init: function(apiEndpoint) { this.config.apiEndpoint = apiEndpoint; this.elements = { apiKeyInput: document.getElementById('api-key-input'), // ID Changed fileInput: document.getElementById('image-upload-input'), searchButton: document.getElementById('search-button'), authStatus: document.getElementById('auth-status'), loader: document.getElementById('loader'), resultsContainer: document.getElementById('search-results-container'), }; // Listeners this.elements.apiKeyInput.addEventListener('input', this._updateButtonState.bind(this)); this.elements.fileInput.addEventListener('change', this._updateButtonState.bind(this)); this.elements.searchButton.addEventListener('click', this._handleSearch.bind(this)); this._updateButtonState(); }, _updateButtonState: function() { const apiKey = this.elements.apiKeyInput.value.trim(); const file = this.elements.fileInput.files[0]; // API Key 'omni_' se shuru hoti hai aur approx 30-40 chars hoti hai const isValidKey = apiKey.length > 20 && apiKey.startsWith("omni_"); const canSearch = isValidKey && file; this.elements.searchButton.disabled = !canSearch; if (isValidKey) { this.elements.authStatus.style.borderLeftColor = '#27ae60'; this.elements.authStatus.innerHTML = '

Status: Valid API Key Format ✅

'; } else { this.elements.authStatus.style.borderLeftColor = '#bdc3c7'; this.elements.authStatus.innerHTML = '

Status: Waiting for valid API Key...

'; } }, // --- 🔥 MAIN SEARCH LOGIC (API KEY UPDATE) 🔥 --- _handleSearch: async function() { const apiKey = this.elements.apiKeyInput.value.trim(); const file = this.elements.fileInput.files[0]; if (!apiKey || !file) return; this.elements.loader.style.display = 'block'; this.elements.searchButton.disabled = true; // Prevent double click this.elements.resultsContainer.innerHTML = ''; const formData = new FormData(); formData.append('file', file); try { console.log("Sending request to:", this.config.apiEndpoint); const response = await fetch(this.config.apiEndpoint, { method: 'POST', headers: { // ✅ CHANGE: Use 'x-api-key' instead of 'Authorization' 'x-api-key': apiKey, 'Accept': 'application/json' // Note: 'Content-Type' header mat lagana jab FormData bhej rahe ho, browser khud boundary set karega. }, body: formData }); const data = await response.json(); if (!response.ok) { // Handle specific Auth errors if (response.status === 401 || response.status === 403) { throw new Error("Authentication Failed! Please check your API Key or Domain Settings."); } const errorDetail = data.detail || data.message || "Unknown server error"; throw new Error(`Error ${response.status}: ${errorDetail}`); } this._renderResults(data.results); } catch (error) { this.elements.resultsContainer.innerHTML = `

❌ Search Failed

${error.message}

`; console.error("Visual Search Error:", error); } finally { this.elements.loader.style.display = 'none'; this.elements.searchButton.disabled = false; } }, _renderResults: function(results) { const container = this.elements.resultsContainer; container.innerHTML = ''; if (!results || results.length === 0) { container.innerHTML = '

🤷‍♂️ No matching products found.

'; return; } results.forEach(item => { const card = document.createElement('div'); card.className = 'result-card'; const similarityScore = (item.similarity * 100).toFixed(1); const slug = item.slug || "#"; // Image Fallback logic const imgUrl = item.image_path || "https://via.placeholder.com/200?text=No+Image"; card.innerHTML = ` Product Image
${similarityScore}% Match

ID: ${item.product_id}

`; container.appendChild(card); }); } };