fix client search
This commit is contained in:
parent
0e5ade1cf5
commit
efe4445639
@ -679,6 +679,7 @@ This modular architecture provides several benefits:
|
|||||||
- [ ] Terraform dependencies
|
- [ ] Terraform dependencies
|
||||||
- [ ] Move all auth logic to auth module
|
- [ ] Move all auth logic to auth module
|
||||||
- [ ] Remove bootstrap endpoint
|
- [ ] Remove bootstrap endpoint
|
||||||
|
- [ ] Move cloud function code to src folder and reuse code with embedding service
|
||||||
|
|
||||||
### Pagination Status ✅
|
### Pagination Status ✅
|
||||||
- **✅ Images API**: Fully implemented with `skip`, `limit`, `total` parameters
|
- **✅ Images API**: Fully implemented with `skip`, `limit`, `total` parameters
|
||||||
|
|||||||
@ -43,9 +43,13 @@ async function performSearch() {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const results = await apiClient.searchImages(query, threshold, maxResults);
|
console.log('Performing search with:', { query, threshold, maxResults });
|
||||||
await displaySearchResults(results, query);
|
const response = await apiClient.searchImages(query, threshold, maxResults);
|
||||||
|
console.log('Search response received:', response);
|
||||||
|
|
||||||
|
await displaySearchResults(response, query);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error('Search error:', error);
|
||||||
handleApiError(error, 'searching images');
|
handleApiError(error, 'searching images');
|
||||||
resultsContainer.innerHTML = `
|
resultsContainer.innerHTML = `
|
||||||
<div class="alert alert-danger">
|
<div class="alert alert-danger">
|
||||||
@ -57,10 +61,18 @@ async function performSearch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Display search results
|
// Display search results
|
||||||
async function displaySearchResults(results, query) {
|
async function displaySearchResults(response, query) {
|
||||||
const container = document.getElementById('searchResults');
|
const container = document.getElementById('searchResults');
|
||||||
|
|
||||||
if (!results || results.length === 0) {
|
console.log('displaySearchResults called with:', { response, query });
|
||||||
|
|
||||||
|
// Extract results array from response object
|
||||||
|
const results = response.results || response;
|
||||||
|
|
||||||
|
console.log('Extracted results:', results);
|
||||||
|
console.log('Results is array:', Array.isArray(results));
|
||||||
|
|
||||||
|
if (!results || !Array.isArray(results) || results.length === 0) {
|
||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<div class="text-center py-5">
|
<div class="text-center py-5">
|
||||||
<i class="fas fa-search fa-3x text-muted mb-3"></i>
|
<i class="fas fa-search fa-3x text-muted mb-3"></i>
|
||||||
@ -71,6 +83,8 @@ async function displaySearchResults(results, query) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('Processing', results.length, 'results');
|
||||||
|
|
||||||
// Create results HTML with placeholder images first
|
// Create results HTML with placeholder images first
|
||||||
const resultsHtml = `
|
const resultsHtml = `
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
@ -78,59 +92,67 @@ async function displaySearchResults(results, query) {
|
|||||||
<p class="text-muted">Found ${results.length} images matching "${escapeHtml(query)}"</p>
|
<p class="text-muted">Found ${results.length} images matching "${escapeHtml(query)}"</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
${results.map(result => `
|
${results.map(result => {
|
||||||
|
// Handle both old format (result.image) and new format (direct result)
|
||||||
|
const image = result.image || result;
|
||||||
|
const similarity = result.similarity || result.similarity_score || 0;
|
||||||
|
|
||||||
|
console.log('Processing result:', { result, image, similarity });
|
||||||
|
|
||||||
|
return `
|
||||||
<div class="col-md-6 col-lg-4 mb-4">
|
<div class="col-md-6 col-lg-4 mb-4">
|
||||||
<div class="card search-result h-100">
|
<div class="card search-result h-100">
|
||||||
<div class="position-relative">
|
<div class="position-relative">
|
||||||
<div class="image-container" style="position: relative; height: 200px;">
|
<div class="image-container" style="position: relative; height: 200px;">
|
||||||
<img id="search-img-${result.image.id}"
|
<img id="search-img-${image.id}"
|
||||||
src="/placeholder-image.png"
|
src="/placeholder-image.png"
|
||||||
class="card-img-top"
|
class="card-img-top"
|
||||||
alt="${escapeHtml(result.image.description || 'Image')}"
|
alt="${escapeHtml(image.description || 'Image')}"
|
||||||
style="height: 200px; object-fit: cover; cursor: pointer; opacity: 0.5;"
|
style="height: 200px; object-fit: cover; cursor: pointer; opacity: 0.5;"
|
||||||
onclick="viewImage('${result.image.id}')">
|
onclick="viewImage('${image.id}')">
|
||||||
<div class="loading-overlay" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
|
<div class="loading-overlay" style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
|
||||||
<div class="loading-spinner"></div>
|
<div class="loading-spinner"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="position-absolute top-0 end-0 m-2">
|
<div class="position-absolute top-0 end-0 m-2">
|
||||||
<span class="badge bg-primary similarity-score">
|
<span class="badge bg-primary similarity-score">
|
||||||
${Math.round(result.similarity * 100)}% match
|
${Math.round(similarity * 100)}% match
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h6 class="card-title">${escapeHtml(truncateText(result.image.description || 'Untitled', 60))}</h6>
|
<h6 class="card-title">${escapeHtml(truncateText(image.description || 'Untitled', 60))}</h6>
|
||||||
<p class="card-text small text-muted">
|
<p class="card-text small text-muted">
|
||||||
<i class="fas fa-calendar me-1"></i>${formatDate(result.image.upload_date)}
|
<i class="fas fa-calendar me-1"></i>${formatDate(image.upload_date)}
|
||||||
</p>
|
</p>
|
||||||
${result.image.tags && result.image.tags.length > 0 ? `
|
${image.tags && image.tags.length > 0 ? `
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
${result.image.tags.slice(0, 3).map(tag =>
|
${image.tags.slice(0, 3).map(tag =>
|
||||||
`<span class="badge bg-secondary me-1">${escapeHtml(tag)}</span>`
|
`<span class="badge bg-secondary me-1">${escapeHtml(tag)}</span>`
|
||||||
).join('')}
|
).join('')}
|
||||||
${result.image.tags.length > 3 ?
|
${image.tags.length > 3 ?
|
||||||
`<span class="badge bg-light text-dark">+${result.image.tags.length - 3}</span>` : ''
|
`<span class="badge bg-light text-dark">+${image.tags.length - 3}</span>` : ''
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''}
|
||||||
<div class="d-flex justify-content-between align-items-center">
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<button class="btn btn-sm btn-outline-primary" onclick="viewImage('${result.image.id}')">
|
<button class="btn btn-sm btn-outline-primary" onclick="viewImage('${image.id}')">
|
||||||
<i class="fas fa-eye"></i>
|
<i class="fas fa-eye"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-sm btn-outline-secondary" onclick="editImage('${result.image.id}')">
|
<button class="btn btn-sm btn-outline-secondary" onclick="editImage('${image.id}')">
|
||||||
<i class="fas fa-edit"></i>
|
<i class="fas fa-edit"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
Similarity: ${(result.similarity * 100).toFixed(1)}%
|
Similarity: ${(similarity * 100).toFixed(1)}%
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`).join('')}
|
`;
|
||||||
|
}).join('')}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -138,9 +160,10 @@ async function displaySearchResults(results, query) {
|
|||||||
|
|
||||||
// Load actual images asynchronously (need to import loadImageBlob from images.js)
|
// Load actual images asynchronously (need to import loadImageBlob from images.js)
|
||||||
for (const result of results) {
|
for (const result of results) {
|
||||||
|
const image = result.image || result;
|
||||||
if (typeof loadImageBlob === 'function') {
|
if (typeof loadImageBlob === 'function') {
|
||||||
loadImageBlob(result.image.id).then(blobUrl => {
|
loadImageBlob(image.id).then(blobUrl => {
|
||||||
const imgElement = document.getElementById(`search-img-${result.image.id}`);
|
const imgElement = document.getElementById(`search-img-${image.id}`);
|
||||||
const loadingOverlay = imgElement?.parentElement.querySelector('.loading-overlay');
|
const loadingOverlay = imgElement?.parentElement.querySelector('.loading-overlay');
|
||||||
|
|
||||||
if (imgElement) {
|
if (imgElement) {
|
||||||
@ -151,8 +174,8 @@ async function displaySearchResults(results, query) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
console.error(`Failed to load search image ${result.image.id}:`, error);
|
console.error(`Failed to load search image ${image.id}:`, error);
|
||||||
const imgElement = document.getElementById(`search-img-${result.image.id}`);
|
const imgElement = document.getElementById(`search-img-${image.id}`);
|
||||||
const loadingOverlay = imgElement?.parentElement.querySelector('.loading-overlay');
|
const loadingOverlay = imgElement?.parentElement.querySelector('.loading-overlay');
|
||||||
|
|
||||||
if (imgElement) {
|
if (imgElement) {
|
||||||
@ -175,7 +198,10 @@ function addSearchRefinementOptions(query, results) {
|
|||||||
const container = document.getElementById('searchResults');
|
const container = document.getElementById('searchResults');
|
||||||
|
|
||||||
// Extract common tags from results
|
// Extract common tags from results
|
||||||
const allTags = results.flatMap(result => result.image.tags || []);
|
const allTags = results.flatMap(result => {
|
||||||
|
const image = result.image || result;
|
||||||
|
return image.tags || [];
|
||||||
|
});
|
||||||
const tagCounts = {};
|
const tagCounts = {};
|
||||||
allTags.forEach(tag => {
|
allTags.forEach(tag => {
|
||||||
tagCounts[tag] = (tagCounts[tag] || 0) + 1;
|
tagCounts[tag] = (tagCounts[tag] || 0) + 1;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user