Spaces:
Sleeping
Sleeping
// Get the current hostname (will work both locally and in Docker) | |
const API_BASE = `${window.location.protocol}//${window.location.hostname}:8002`; | |
// Interface switching | |
function setupNavigation() { | |
const navItems = document.querySelectorAll('.nav-item'); | |
navItems.forEach(item => { | |
item.addEventListener('click', () => { | |
const mode = item.dataset.mode; | |
// Update navigation state | |
navItems.forEach(nav => nav.classList.remove('active')); | |
item.classList.add('active'); | |
// Update interface visibility | |
document.querySelectorAll('.interface').forEach(interface => { | |
interface.classList.remove('active'); | |
}); | |
document.getElementById(mode).classList.add('active'); | |
}); | |
}); | |
} | |
// Helper functions | |
function setLoading(button, isLoading) { | |
if (isLoading) { | |
button.classList.add('loading'); | |
button.disabled = true; | |
} else { | |
button.classList.remove('loading'); | |
button.disabled = false; | |
} | |
} | |
function showError(container, message) { | |
const errorDiv = document.createElement('div'); | |
errorDiv.className = 'error-message'; | |
errorDiv.textContent = message || 'An error occurred. Please try again.'; | |
container.innerHTML = ''; | |
container.appendChild(errorDiv); | |
updateResultsPanel(null); // Clear the results panel | |
} | |
function updateResultsPanel(textData) { | |
const panel = document.getElementById('resultsPanel'); | |
const mainContent = document.querySelector('.main-content'); | |
if (!textData) { | |
panel.classList.remove('visible'); | |
mainContent.classList.remove('with-panel'); | |
return; | |
} | |
panel.innerHTML = ''; // Clear previous content | |
// Add title | |
const title = document.createElement('h2'); | |
title.textContent = 'Generated Information'; | |
title.style.marginBottom = '1.5rem'; | |
panel.appendChild(title); | |
if (typeof textData === 'string') { | |
// Handle legacy string data | |
const p = document.createElement('p'); | |
p.textContent = textData; | |
panel.appendChild(p); | |
} else { | |
// Handle structured data | |
Object.entries(textData).forEach(([section, content]) => { | |
const sectionDiv = document.createElement('div'); | |
sectionDiv.className = 'text-section'; | |
const title = document.createElement('h3'); | |
title.className = 'section-title'; | |
title.textContent = section.split('_').map(word => | |
word.charAt(0).toUpperCase() + word.slice(1) | |
).join(' '); | |
const content_p = document.createElement('p'); | |
content_p.textContent = content; | |
sectionDiv.appendChild(title); | |
sectionDiv.appendChild(content_p); | |
panel.appendChild(sectionDiv); | |
}); | |
} | |
panel.classList.add('visible'); | |
mainContent.classList.add('with-panel'); | |
} | |
function createResultElement(item) { | |
if (item.type === 'text') { | |
// Update the panel with text data | |
updateResultsPanel(item.data); | |
return null; // Don't create an element in the main content area | |
} else if (item.type === 'image') { | |
const wrapper = document.createElement('div'); | |
wrapper.className = 'image-wrapper'; | |
const img = document.createElement('img'); | |
img.src = item.data; | |
img.addEventListener('load', () => wrapper.classList.add('loaded')); | |
wrapper.appendChild(img); | |
return wrapper; | |
} | |
return null; | |
} | |
// File input handling | |
function setupFileInput() { | |
const fileInput = document.getElementById('inputImage'); | |
const dropZone = document.querySelector('.file-input-wrapper'); | |
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { | |
dropZone.addEventListener(eventName, preventDefaults, false); | |
}); | |
function preventDefaults(e) { | |
e.preventDefault(); | |
e.stopPropagation(); | |
} | |
['dragenter', 'dragover'].forEach(eventName => { | |
dropZone.addEventListener(eventName, () => { | |
dropZone.classList.add('highlight'); | |
}); | |
}); | |
['dragleave', 'drop'].forEach(eventName => { | |
dropZone.addEventListener(eventName, () => { | |
dropZone.classList.remove('highlight'); | |
}); | |
}); | |
dropZone.addEventListener('drop', (e) => { | |
const dt = e.dataTransfer; | |
const files = dt.files; | |
fileInput.files = files; | |
updateFileLabel(files[0]?.name); | |
}); | |
fileInput.addEventListener('change', (e) => { | |
updateFileLabel(e.target.files[0]?.name); | |
}); | |
} | |
function updateFileLabel(filename) { | |
const label = document.querySelector('label[for="inputImage"] span'); | |
label.textContent = filename || 'Choose an image or drag & drop here'; | |
} | |
// Text to Image Generation | |
document.getElementById('generate').addEventListener('click', async () => { | |
const prompt = document.getElementById('prompt').value.trim(); | |
const category = document.getElementById('category').value; | |
const generateButton = document.getElementById('generate'); | |
const resultsDiv = document.getElementById('results'); | |
if (!prompt) { | |
showError(resultsDiv, 'Please enter a description for the schematic.'); | |
return; | |
} | |
resultsDiv.innerHTML = ''; | |
setLoading(generateButton, true); | |
try { | |
const res = await fetch(`${API_BASE}/generate`, { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' }, | |
body: JSON.stringify({ prompt, category }) | |
}); | |
if (!res.ok) { | |
throw new Error(`Server responded with ${res.status}`); | |
} | |
const data = await res.json(); | |
const resultElements = data.results | |
.map(createResultElement) | |
.filter(element => element !== null); | |
if (resultElements.length === 0) { | |
showError(resultsDiv, 'No results generated. Please try again.'); | |
return; | |
} | |
resultElements.forEach(element => resultsDiv.appendChild(element)); | |
} catch (err) { | |
console.error(err); | |
showError(resultsDiv, 'Error generating schematic. Please try again.'); | |
} finally { | |
setLoading(generateButton, false); | |
} | |
}); | |
// Image with Text Generation | |
document.getElementById('generateWithImage').addEventListener('click', async () => { | |
const fileInput = document.getElementById('inputImage'); | |
const prompt = document.getElementById('imagePrompt').value.trim(); | |
const generateButton = document.getElementById('generateWithImage'); | |
const resultsDiv = document.getElementById('resultsImg'); | |
if (!fileInput.files.length) { | |
showError(resultsDiv, 'Please select an image file.'); | |
return; | |
} | |
const file = fileInput.files[0]; | |
if (!file.type.startsWith('image/')) { | |
showError(resultsDiv, 'Please select a valid image file.'); | |
return; | |
} | |
resultsDiv.innerHTML = ''; | |
setLoading(generateButton, true); | |
try { | |
const base64 = await new Promise((resolve, reject) => { | |
const reader = new FileReader(); | |
reader.onload = e => resolve(e.target.result); | |
reader.onerror = reject; | |
reader.readAsDataURL(file); | |
}); | |
const category = document.getElementById('imageCategory').value; | |
const res = await fetch(`${API_BASE}/generate_with_image`, { | |
method: 'POST', | |
headers: { 'Content-Type': 'application/json' }, | |
body: JSON.stringify({ | |
text: prompt || '', // Send empty string if no prompt provided | |
image: base64, | |
category | |
}) | |
}); | |
if (!res.ok) { | |
throw new Error(`Server responded with ${res.status}`); | |
} | |
const data = await res.json(); | |
const resultElements = data.results | |
.map(createResultElement) | |
.filter(element => element !== null); | |
if (resultElements.length === 0) { | |
showError(resultsDiv, 'No results generated. Please try again.'); | |
return; | |
} | |
resultElements.forEach(element => resultsDiv.appendChild(element)); | |
} catch (err) { | |
console.error(err); | |
showError(resultsDiv, 'Error generating modified schematic. Please try again.'); | |
} finally { | |
setLoading(generateButton, false); | |
} | |
}); | |
// Category handling | |
async function fetchCategories() { | |
try { | |
const res = await fetch(`${API_BASE}/categories`); | |
if (!res.ok) throw new Error('Failed to fetch categories'); | |
return await res.json(); | |
} catch (error) { | |
console.error('Error fetching categories:', error); | |
return null; | |
} | |
} | |
function updateCategoryInfo(categoryData, infoDiv) { | |
if (!infoDiv) { | |
console.error('Category info div not found'); | |
return; | |
} | |
if (!categoryData) { | |
infoDiv.innerHTML = ''; | |
infoDiv.classList.remove('visible'); | |
return; | |
} | |
const html = ` | |
<h4>${categoryData.name}</h4> | |
<p>${categoryData.description}</p> | |
<p><strong>Style Guide:</strong> ${categoryData.style_guide}</p> | |
<h4>Drawing Conventions:</h4> | |
<div class="conventions-list"> | |
${categoryData.conventions.map(conv => ` | |
<span class="convention-tag">${conv}</span> | |
`).join('')} | |
</div> | |
<h4>Common Elements:</h4> | |
<div class="elements-list"> | |
${categoryData.common_elements.map(elem => ` | |
<span class="element-tag">${elem}</span> | |
`).join('')} | |
</div> | |
`; | |
infoDiv.innerHTML = html; | |
infoDiv.classList.add('visible'); | |
} | |
async function setupCategories() { | |
try { | |
const categories = await fetchCategories(); | |
if (!categories) return; | |
// Setup for both category selects | |
[ | |
{ selectId: 'category', infoId: 'categoryInfo' }, | |
{ selectId: 'imageCategory', infoId: 'imageCategoryInfo' } | |
].forEach(({ selectId, infoId }) => { | |
const select = document.getElementById(selectId); | |
if (!select) { | |
console.error(`Select element with id ${selectId} not found`); | |
return; | |
} | |
// Clear existing options | |
select.innerHTML = '<option value="">Select Engineering Category (Optional)</option>'; | |
// Add category options | |
Object.entries(categories).forEach(([key, data]) => { | |
const option = document.createElement('option'); | |
option.value = key; | |
option.textContent = data.name; | |
select.appendChild(option); | |
}); | |
// Add change event listener | |
select.addEventListener('change', (e) => { | |
const selectedCategory = e.target.value; | |
const infoElement = document.getElementById(infoId); | |
if (selectedCategory && categories[selectedCategory]) { | |
updateCategoryInfo(categories[selectedCategory], infoElement); | |
} else { | |
updateCategoryInfo(null, infoElement); | |
} | |
}); | |
}); | |
} catch (error) { | |
console.error('Error setting up categories:', error); | |
} | |
} | |
// Initialize functionality | |
setupNavigation(); | |
setupFileInput(); | |
setupCategories(); | |