Spaces:
Sleeping
Sleeping
File size: 5,559 Bytes
ba2fc46 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
// 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 = '<p style="color: #27ae60; margin:0"><strong>Status:</strong> Valid API Key Format ✅</p>';
} else {
this.elements.authStatus.style.borderLeftColor = '#bdc3c7';
this.elements.authStatus.innerHTML = '<p style="color: #7f8c8d; margin:0"><strong>Status:</strong> Waiting for valid API Key...</p>';
}
},
// --- 🔥 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 = `
<div style="text-align:center; padding: 20px;">
<p style="color: #e74c3c; font-weight: bold; font-size: 1.2em;">❌ Search Failed</p>
<p style="color: #555;">${error.message}</p>
</div>`;
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 = '<p class="info-message">🤷♂️ No matching products found.</p>';
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 = `
<a href="/product/${slug}" target="_blank" style="text-decoration: none; color: inherit;">
<img src="${imgUrl}" alt="Product Image" onerror="this.src='https://via.placeholder.com/200?text=Error'">
<div class="card-content">
<span class="similarity-badge">${similarityScore}% Match</span>
<p style="margin-top: 10px; font-size: 0.9em; color: #555;">ID: ${item.product_id}</p>
</div>
</a>
`;
container.appendChild(card);
});
}
}; |