brightening-eyes's picture
initial commit
835c41f
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cloudzy AI Photo Manager</title>
<style>
body { font-family: sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
.upload-box { border: 2px dashed #ccc; padding: 20px; text-align: center; margin-bottom: 20px; }
.gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 20px; }
.photo-card { border: 1px solid #eee; padding: 10px; border-radius: 8px; }
.photo-card img { width: 100%; height: 150px; object-fit: cover; border-radius: 4px; }
.tags { font-size: 0.8em; color: #666; }
.meta { font-size: 0.7em; color: #888; margin-top: 5px; }
</style>
</head>
<body>
<h1>Cloudzy AI Challenge</h1>
<div class="upload-box">
<h3>Upload Photo</h3>
<input type="file" id="fileInput">
<button onclick="uploadPhoto()">Upload</button>
<p id="uploadStatus"></p>
</div>
<div style="margin-bottom: 20px;">
<input type="text" id="searchInput" placeholder="Search (e.g., 'dog in grass' or 'happy person')..." style="width: 70%;">
<button onclick="searchPhotos()">Semantic Search</button>
</div>
<div id="gallery" class="gallery"></div>
<script>
async function uploadPhoto() {
const fileInput = document.getElementById('fileInput');
const status = document.getElementById('uploadStatus');
if (!fileInput.files[0]) return alert("Select a file!");
const formData = new FormData();
formData.append('file', fileInput.files[0]);
status.innerText = "Uploading...";
try {
const res = await fetch('/upload', { method: 'POST', body: formData });
const data = await res.json();
status.innerText = "Upload successful! ID: " + data.id + ". Processing AI...";
setTimeout(() => searchPhotos(""), 2000); // Auto refresh
} catch (e) {
status.innerText = "Error uploading.";
}
}
async function searchPhotos() {
const query = document.getElementById('searchInput').value;
const gallery = document.getElementById('gallery');
gallery.innerHTML = "Loading...";
let url = query ? `/search?q=${encodeURIComponent(query)}` : '/search?q=recent';
// Note: Empty search isn't strictly defined in backend, using "recent" logic or just querying specific keyword for demo if empty
if (!query) return;
const res = await fetch(url);
const photos = await res.json();
gallery.innerHTML = "";
photos.forEach(photo => {
const div = document.createElement('div');
div.className = 'photo-card';
// Parse smart features for display
let faceInfo = "";
if (photo.smart_features && Array.isArray(photo.smart_features)) {
faceInfo = `${photo.smart_features.length} Face(s) detected`;
} else if (photo.smart_features && photo.smart_features.message) {
faceInfo = photo.smart_features.message;
}
div.innerHTML = `
<img src="${photo.url}" alt="photo">
<p><strong>${photo.caption || "Processing..."}</strong></p>
<div class="tags">${photo.tags.slice(0, 5).join(", ")}</div>
<div class="meta">${faceInfo}</div>
`;
gallery.appendChild(div);
});
}
</script>
</body>
</html>