|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
marked.setOptions({ |
|
breaks: true, |
|
gfm: true, |
|
smartLists: true |
|
}); |
|
|
|
|
|
const API_KEY_STORAGE_KEY = 'grok2_api_key'; |
|
const apiKeyInput = document.getElementById('api-key-input'); |
|
const saveApiKeyBtn = document.getElementById('save-api-key'); |
|
const clearApiKeyBtn = document.getElementById('clear-api-key'); |
|
const apiKeyStatus = document.getElementById('api-key-status'); |
|
|
|
|
|
const navLinks = document.querySelectorAll('nav ul li a'); |
|
const sections = document.querySelectorAll('.section'); |
|
|
|
|
|
const imagePromptInput = document.getElementById('image-prompt'); |
|
const generateImageBtn = document.getElementById('generate-image'); |
|
const imageResult = document.getElementById('image-result'); |
|
const generationStatus = document.getElementById('generation-status'); |
|
|
|
|
|
const uploadArea = document.getElementById('upload-area'); |
|
const imageUploadInput = document.getElementById('image-upload'); |
|
const visionPromptInput = document.getElementById('vision-prompt'); |
|
const analyzeImageBtn = document.getElementById('analyze-image'); |
|
const uploadedImageContainer = document.getElementById('uploaded-image'); |
|
const visionResult = document.getElementById('vision-result'); |
|
const visionStatus = document.getElementById('vision-status'); |
|
|
|
let uploadedImage = null; |
|
|
|
|
|
checkStoredApiKey(); |
|
|
|
|
|
function checkStoredApiKey() { |
|
const storedApiKey = localStorage.getItem(API_KEY_STORAGE_KEY); |
|
if (storedApiKey) { |
|
apiKeyStatus.textContent = 'β
API key is stored'; |
|
apiKeyStatus.style.color = '#27ae60'; |
|
|
|
apiKeyInput.value = 'β’'.repeat(12); |
|
} else { |
|
apiKeyStatus.textContent = 'β No API key stored'; |
|
apiKeyStatus.style.color = '#e74c3c'; |
|
apiKeyInput.value = ''; |
|
} |
|
} |
|
|
|
saveApiKeyBtn.addEventListener('click', function() { |
|
const apiKey = apiKeyInput.value.trim(); |
|
if (apiKey && apiKey !== 'β’'.repeat(12)) { |
|
localStorage.setItem(API_KEY_STORAGE_KEY, apiKey); |
|
apiKeyStatus.textContent = 'β
API key saved successfully'; |
|
apiKeyStatus.style.color = '#27ae60'; |
|
|
|
apiKeyInput.value = 'β’'.repeat(12); |
|
} else if (apiKey === 'β’'.repeat(12)) { |
|
apiKeyStatus.textContent = 'β Please enter a new API key'; |
|
apiKeyStatus.style.color = '#f39c12'; |
|
} else { |
|
apiKeyStatus.textContent = 'β Please enter a valid API key'; |
|
apiKeyStatus.style.color = '#e74c3c'; |
|
} |
|
}); |
|
|
|
clearApiKeyBtn.addEventListener('click', function() { |
|
localStorage.removeItem(API_KEY_STORAGE_KEY); |
|
apiKeyInput.value = ''; |
|
apiKeyStatus.textContent = 'ποΈ API key cleared'; |
|
apiKeyStatus.style.color = '#e74c3c'; |
|
}); |
|
|
|
|
|
navLinks.forEach(link => { |
|
link.addEventListener('click', function(e) { |
|
e.preventDefault(); |
|
|
|
|
|
navLinks.forEach(l => l.classList.remove('active')); |
|
this.classList.add('active'); |
|
|
|
|
|
const targetSection = this.getAttribute('data-section'); |
|
sections.forEach(section => { |
|
section.classList.remove('active'); |
|
if (section.id === targetSection) { |
|
section.classList.add('active'); |
|
} |
|
}); |
|
}); |
|
}); |
|
|
|
|
|
uploadArea.addEventListener('click', function() { |
|
imageUploadInput.click(); |
|
}); |
|
|
|
uploadArea.addEventListener('dragover', function(e) { |
|
e.preventDefault(); |
|
this.classList.add('dragover'); |
|
}); |
|
|
|
uploadArea.addEventListener('dragleave', function() { |
|
this.classList.remove('dragover'); |
|
}); |
|
|
|
uploadArea.addEventListener('drop', function(e) { |
|
e.preventDefault(); |
|
this.classList.remove('dragover'); |
|
|
|
if (e.dataTransfer.files && e.dataTransfer.files[0]) { |
|
handleImageUpload(e.dataTransfer.files[0]); |
|
} |
|
}); |
|
|
|
imageUploadInput.addEventListener('change', function() { |
|
if (this.files && this.files[0]) { |
|
handleImageUpload(this.files[0]); |
|
} |
|
}); |
|
|
|
function handleImageUpload(file) { |
|
if (!file.type.match('image.*')) { |
|
visionStatus.textContent = 'β Please upload an image file'; |
|
return; |
|
} |
|
|
|
const reader = new FileReader(); |
|
reader.onload = function(e) { |
|
const img = document.createElement('img'); |
|
img.src = e.target.result; |
|
uploadedImageContainer.innerHTML = ''; |
|
uploadedImageContainer.appendChild(img); |
|
uploadedImage = file; |
|
analyzeImageBtn.disabled = false; |
|
visionStatus.textContent = 'β
Image uploaded successfully'; |
|
}; |
|
reader.readAsDataURL(file); |
|
} |
|
|
|
|
|
generateImageBtn.addEventListener('click', function() { |
|
const prompt = imagePromptInput.value.trim(); |
|
if (!prompt) { |
|
generationStatus.textContent = 'β Please enter a prompt'; |
|
return; |
|
} |
|
|
|
const apiKey = localStorage.getItem(API_KEY_STORAGE_KEY); |
|
if (!apiKey) { |
|
generationStatus.textContent = 'β API key is required. Please add your API key in the API Key section.'; |
|
return; |
|
} |
|
|
|
|
|
generationStatus.innerHTML = '<span class="loading"></span> Generating image...'; |
|
generateImageBtn.disabled = true; |
|
imageResult.innerHTML = ''; |
|
|
|
|
|
fetch('/api/generate-image', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json' |
|
}, |
|
body: JSON.stringify({ |
|
api_key: apiKey, |
|
prompt: prompt, |
|
use_openai_format: true |
|
}) |
|
}) |
|
.then(response => { |
|
if (!response.ok) { |
|
return response.json().then(err => { throw err; }); |
|
} |
|
return response.json(); |
|
}) |
|
.then(data => { |
|
if (data.image_url) { |
|
|
|
let imageHTML = `<img src="${data.image_url}" alt="Generated image">`; |
|
|
|
|
|
if (data.caption) { |
|
imageHTML += `<div class="image-caption">${data.caption}</div>`; |
|
} |
|
|
|
imageResult.innerHTML = imageHTML; |
|
generationStatus.textContent = 'β
Image generated successfully'; |
|
} else { |
|
throw new Error('No image URL in response'); |
|
} |
|
}) |
|
.catch(error => { |
|
generationStatus.textContent = `β Error: ${error.error || error.message || 'Unknown error'}`; |
|
console.error('Image generation error:', error); |
|
}) |
|
.finally(() => { |
|
generateImageBtn.disabled = false; |
|
}); |
|
}); |
|
|
|
|
|
analyzeImageBtn.addEventListener('click', function() { |
|
if (!uploadedImage) { |
|
visionStatus.textContent = 'β Please upload an image first'; |
|
return; |
|
} |
|
|
|
const prompt = visionPromptInput.value.trim() || 'Describe this image in detail'; |
|
const apiKey = localStorage.getItem(API_KEY_STORAGE_KEY); |
|
if (!apiKey) { |
|
visionStatus.textContent = 'β API key is required. Please add your API key in the API Key section.'; |
|
return; |
|
} |
|
|
|
|
|
visionStatus.innerHTML = '<span class="loading"></span> Analyzing image...'; |
|
analyzeImageBtn.disabled = true; |
|
visionResult.textContent = ''; |
|
|
|
|
|
const formData = new FormData(); |
|
formData.append('image', uploadedImage); |
|
formData.append('api_key', apiKey); |
|
formData.append('prompt', prompt); |
|
|
|
|
|
fetch('/api/analyze-image', { |
|
method: 'POST', |
|
body: formData |
|
}) |
|
.then(response => { |
|
if (!response.ok) { |
|
return response.json().then(err => { throw err; }); |
|
} |
|
return response.json(); |
|
}) |
|
.then(data => { |
|
if (data.analysis) { |
|
|
|
visionResult.innerHTML = marked.parse(data.analysis); |
|
visionStatus.textContent = 'β
Analysis completed'; |
|
} else { |
|
throw new Error('No analysis in response'); |
|
} |
|
}) |
|
.catch(error => { |
|
visionStatus.textContent = `β Error: ${error.error || error.message || 'Unknown error'}`; |
|
console.error('Vision analysis error:', error); |
|
}) |
|
.finally(() => { |
|
analyzeImageBtn.disabled = false; |
|
}); |
|
}); |
|
}); |