mirror of
https://github.com/1SecondEveryday/image-analysis-eval.git
synced 2026-03-25 09:05:49 +00:00
278 lines
No EOL
8.8 KiB
HTML
278 lines
No EOL
8.8 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Image Keyword Selector</title>
|
|
<style>
|
|
body {
|
|
font-family: Arial, sans-serif;
|
|
margin: 20px;
|
|
background-color: #f5f5f5;
|
|
}
|
|
.container {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
}
|
|
.header {
|
|
background-color: #333;
|
|
color: white;
|
|
padding: 20px;
|
|
text-align: center;
|
|
margin-bottom: 30px;
|
|
border-radius: 8px;
|
|
}
|
|
.controls {
|
|
text-align: center;
|
|
margin-bottom: 30px;
|
|
}
|
|
.download-btn {
|
|
background-color: #4CAF50;
|
|
color: white;
|
|
padding: 12px 30px;
|
|
font-size: 16px;
|
|
border: none;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
margin: 10px;
|
|
}
|
|
.download-btn:hover {
|
|
background-color: #45a049;
|
|
}
|
|
.clear-btn {
|
|
background-color: #f44336;
|
|
color: white;
|
|
padding: 12px 30px;
|
|
font-size: 16px;
|
|
border: none;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
margin: 10px;
|
|
}
|
|
.clear-btn:hover {
|
|
background-color: #da190b;
|
|
}
|
|
.image-section {
|
|
background-color: white;
|
|
margin-bottom: 30px;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
.image-container {
|
|
display: flex;
|
|
gap: 20px;
|
|
margin-bottom: 20px;
|
|
}
|
|
.image-wrapper {
|
|
flex: 0 0 auto;
|
|
}
|
|
.image-wrapper img {
|
|
max-width: 400px;
|
|
height: auto;
|
|
border-radius: 4px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
.keywords-container {
|
|
flex: 1;
|
|
}
|
|
.filename {
|
|
font-weight: bold;
|
|
font-size: 18px;
|
|
margin-bottom: 15px;
|
|
color: #333;
|
|
}
|
|
.model-section {
|
|
margin-bottom: 15px;
|
|
}
|
|
.model-name {
|
|
font-weight: bold;
|
|
color: #666;
|
|
margin-bottom: 5px;
|
|
}
|
|
.keyword {
|
|
display: inline-block;
|
|
padding: 5px 10px;
|
|
margin: 3px;
|
|
background-color: #e0e0e0;
|
|
border-radius: 15px;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
font-size: 14px;
|
|
}
|
|
.keyword:hover {
|
|
background-color: #d0d0d0;
|
|
}
|
|
.keyword.selected {
|
|
background-color: #4CAF50;
|
|
color: white;
|
|
}
|
|
.stats {
|
|
text-align: center;
|
|
margin: 20px 0;
|
|
font-size: 18px;
|
|
color: #666;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header">
|
|
<h1>Image Keyword Selector</h1>
|
|
<p>Click on keywords that should be mandatory for each image</p>
|
|
</div>
|
|
|
|
<div class="controls">
|
|
<button class="download-btn" onclick="downloadCSV()">Download Mandatory Keywords CSV</button>
|
|
<button class="clear-btn" onclick="clearAllSelections()">Clear All Selections</button>
|
|
<div class="stats" id="stats">0 keywords selected</div>
|
|
</div>
|
|
|
|
<div id="images-container"></div>
|
|
</div>
|
|
|
|
<script src="image-data.js"></script>
|
|
<script>
|
|
const selectedKeywords = {};
|
|
|
|
// Function to update selection stats
|
|
function updateStats() {
|
|
let total = 0;
|
|
Object.values(selectedKeywords).forEach(keywords => {
|
|
total += keywords.size;
|
|
});
|
|
document.getElementById('stats').textContent = `${total} keywords selected across ${Object.keys(selectedKeywords).length} images`;
|
|
}
|
|
|
|
// Function to toggle keyword selection
|
|
function toggleKeyword(filename, keyword) {
|
|
if (!selectedKeywords[filename]) {
|
|
selectedKeywords[filename] = new Set();
|
|
}
|
|
|
|
if (selectedKeywords[filename].has(keyword)) {
|
|
selectedKeywords[filename].delete(keyword);
|
|
} else {
|
|
selectedKeywords[filename].add(keyword);
|
|
}
|
|
|
|
if (selectedKeywords[filename].size === 0) {
|
|
delete selectedKeywords[filename];
|
|
}
|
|
|
|
updateStats();
|
|
}
|
|
|
|
// Function to create keyword element
|
|
function createKeywordElement(keyword, filename) {
|
|
const span = document.createElement('span');
|
|
span.className = 'keyword';
|
|
span.textContent = keyword;
|
|
span.onclick = function() {
|
|
this.classList.toggle('selected');
|
|
toggleKeyword(filename, keyword);
|
|
};
|
|
return span;
|
|
}
|
|
|
|
// Function to create image section
|
|
function createImageSection(data) {
|
|
const section = document.createElement('div');
|
|
section.className = 'image-section';
|
|
|
|
const container = document.createElement('div');
|
|
container.className = 'image-container';
|
|
|
|
// Image
|
|
const imageWrapper = document.createElement('div');
|
|
imageWrapper.className = 'image-wrapper';
|
|
const img = document.createElement('img');
|
|
img.src = 'photo-768/' + data.filename;
|
|
img.alt = data.filename;
|
|
imageWrapper.appendChild(img);
|
|
|
|
// Keywords
|
|
const keywordsContainer = document.createElement('div');
|
|
keywordsContainer.className = 'keywords-container';
|
|
|
|
const filename = document.createElement('div');
|
|
filename.className = 'filename';
|
|
filename.textContent = data.filename;
|
|
keywordsContainer.appendChild(filename);
|
|
|
|
// Add keywords from each model
|
|
Object.entries(data.keywords).forEach(([model, keywords]) => {
|
|
const modelSection = document.createElement('div');
|
|
modelSection.className = 'model-section';
|
|
|
|
const modelName = document.createElement('div');
|
|
modelName.className = 'model-name';
|
|
modelName.textContent = model + ':';
|
|
modelSection.appendChild(modelName);
|
|
|
|
const keywordsDiv = document.createElement('div');
|
|
keywords.forEach(keyword => {
|
|
keywordsDiv.appendChild(createKeywordElement(keyword, data.filename));
|
|
});
|
|
modelSection.appendChild(keywordsDiv);
|
|
|
|
keywordsContainer.appendChild(modelSection);
|
|
});
|
|
|
|
container.appendChild(imageWrapper);
|
|
container.appendChild(keywordsContainer);
|
|
section.appendChild(container);
|
|
|
|
return section;
|
|
}
|
|
|
|
// Function to download CSV
|
|
function downloadCSV() {
|
|
const rows = [];
|
|
|
|
Object.entries(selectedKeywords).forEach(([filename, keywords]) => {
|
|
if (keywords.size > 0) {
|
|
const row = [filename, ...Array.from(keywords)].join(',');
|
|
rows.push(row);
|
|
}
|
|
});
|
|
|
|
if (rows.length === 0) {
|
|
alert('No keywords selected!');
|
|
return;
|
|
}
|
|
|
|
const csv = rows.join('\n');
|
|
const blob = new Blob([csv], { type: 'text/csv' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = 'mandatory-keywords.csv';
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
// Function to clear all selections
|
|
function clearAllSelections() {
|
|
if (confirm('Clear all selected keywords?')) {
|
|
document.querySelectorAll('.keyword.selected').forEach(el => {
|
|
el.classList.remove('selected');
|
|
});
|
|
Object.keys(selectedKeywords).forEach(key => delete selectedKeywords[key]);
|
|
updateStats();
|
|
}
|
|
}
|
|
|
|
// Initialize the page
|
|
function init() {
|
|
const container = document.getElementById('images-container');
|
|
imageData.forEach(data => {
|
|
container.appendChild(createImageSection(data));
|
|
});
|
|
}
|
|
|
|
// Wait for data to be populated
|
|
window.onload = init;
|
|
</script>
|
|
</body>
|
|
</html> |