|
|
|
|
|
function fileToBase64(file) { |
|
|
return new Promise((resolve, reject) => { |
|
|
const reader = new FileReader(); |
|
|
reader.onload = () => { |
|
|
|
|
|
const base64 = reader.result.split(',')[1] || reader.result; |
|
|
resolve(base64); |
|
|
}; |
|
|
reader.onerror = reject; |
|
|
reader.readAsDataURL(file); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
async function filesToBase64Array(fileList) { |
|
|
const base64Array = []; |
|
|
for (let i = 0; i < fileList.length; i++) { |
|
|
const base64 = await fileToBase64(fileList[i]); |
|
|
base64Array.push(base64); |
|
|
} |
|
|
return base64Array; |
|
|
} |
|
|
|
|
|
function genImage(event) { |
|
|
event.preventDefault(); |
|
|
promptDallE(); |
|
|
} |
|
|
|
|
|
async function promptDallE() { |
|
|
const loader = document.getElementById("loader"); |
|
|
const input = document.getElementById("input"); |
|
|
const generateBtn = document.getElementById("generate-btn"); |
|
|
const resultDiv = document.getElementById("result"); |
|
|
const resultPlaceholder = document.getElementById("result-placeholder"); |
|
|
|
|
|
|
|
|
loader.classList.remove("hidden"); |
|
|
if (resultPlaceholder) { |
|
|
resultPlaceholder.style.display = "none"; |
|
|
} |
|
|
input.disabled = true; |
|
|
generateBtn.disabled = true; |
|
|
|
|
|
|
|
|
const prompt = input.value.trim(); |
|
|
if (!prompt) { |
|
|
alert("Please enter a prompt"); |
|
|
loader.classList.add("hidden"); |
|
|
if (resultPlaceholder) { |
|
|
resultPlaceholder.style.display = "flex"; |
|
|
} |
|
|
input.disabled = false; |
|
|
generateBtn.disabled = false; |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
const model = document.getElementById("image-model").value; |
|
|
const size = document.getElementById("image-size").value; |
|
|
const negativePrompt = document.getElementById("negative-prompt").value.trim(); |
|
|
const n = parseInt(document.getElementById("image-count").value) || 1; |
|
|
const stepInput = document.getElementById("image-steps").value.trim(); |
|
|
const step = stepInput ? parseInt(stepInput) : undefined; |
|
|
const seedInput = document.getElementById("image-seed").value.trim(); |
|
|
const seed = seedInput ? parseInt(seedInput) : undefined; |
|
|
|
|
|
|
|
|
|
|
|
let combinedPrompt = prompt; |
|
|
if (negativePrompt) { |
|
|
combinedPrompt = prompt + "|" + negativePrompt; |
|
|
} |
|
|
|
|
|
const requestBody = { |
|
|
model: model, |
|
|
prompt: combinedPrompt, |
|
|
n: n, |
|
|
size: size, |
|
|
}; |
|
|
|
|
|
if (step !== undefined) { |
|
|
requestBody.step = step; |
|
|
} |
|
|
|
|
|
if (seed !== undefined) { |
|
|
requestBody.seed = seed; |
|
|
} |
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
const sourceImageInput = document.getElementById("source-image"); |
|
|
if (sourceImageInput.files.length > 0) { |
|
|
const base64 = await fileToBase64(sourceImageInput.files[0]); |
|
|
requestBody.file = base64; |
|
|
} |
|
|
|
|
|
|
|
|
const refImageInputs = document.querySelectorAll('.reference-image-file'); |
|
|
const refImageFiles = []; |
|
|
for (const input of refImageInputs) { |
|
|
if (input.files.length > 0) { |
|
|
refImageFiles.push(input.files[0]); |
|
|
} |
|
|
} |
|
|
if (refImageFiles.length > 0) { |
|
|
const base64Array = await filesToBase64Array(refImageFiles); |
|
|
requestBody.ref_images = base64Array; |
|
|
} |
|
|
} catch (error) { |
|
|
console.error("Error processing image files:", error); |
|
|
resultDiv.innerHTML = '<p class="text-xs text-red-500 p-2">Error processing image files: ' + error.message + '</p>'; |
|
|
loader.classList.add("hidden"); |
|
|
if (resultPlaceholder) { |
|
|
resultPlaceholder.style.display = "none"; |
|
|
} |
|
|
input.disabled = false; |
|
|
generateBtn.disabled = false; |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
try { |
|
|
const response = await fetch("v1/images/generations", { |
|
|
method: "POST", |
|
|
headers: { |
|
|
"Content-Type": "application/json", |
|
|
}, |
|
|
body: JSON.stringify(requestBody), |
|
|
}); |
|
|
|
|
|
const json = await response.json(); |
|
|
|
|
|
if (json.error) { |
|
|
|
|
|
resultDiv.innerHTML = '<p class="text-xs text-red-500 p-2">Error: ' + json.error.message + '</p>'; |
|
|
loader.classList.add("hidden"); |
|
|
if (resultPlaceholder) { |
|
|
resultPlaceholder.style.display = "none"; |
|
|
} |
|
|
input.disabled = false; |
|
|
generateBtn.disabled = false; |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
resultDiv.innerHTML = ''; |
|
|
if (resultPlaceholder) { |
|
|
resultPlaceholder.style.display = "none"; |
|
|
} |
|
|
|
|
|
|
|
|
if (json.data && json.data.length > 0) { |
|
|
json.data.forEach((item, index) => { |
|
|
const imageContainer = document.createElement("div"); |
|
|
imageContainer.className = "flex flex-col"; |
|
|
|
|
|
|
|
|
const img = document.createElement("img"); |
|
|
if (item.url) { |
|
|
img.src = item.url; |
|
|
} else if (item.b64_json) { |
|
|
img.src = "data:image/png;base64," + item.b64_json; |
|
|
} else { |
|
|
return; |
|
|
} |
|
|
img.alt = prompt; |
|
|
img.className = "w-full h-auto rounded-lg"; |
|
|
imageContainer.appendChild(img); |
|
|
|
|
|
|
|
|
const captionDiv = document.createElement("div"); |
|
|
captionDiv.className = "mt-2 p-2 bg-[var(--color-bg-secondary)] rounded-lg text-xs"; |
|
|
|
|
|
|
|
|
const promptCaption = document.createElement("p"); |
|
|
promptCaption.className = "text-[var(--color-text-primary)] mb-1.5 break-words"; |
|
|
promptCaption.innerHTML = '<strong>Prompt:</strong> ' + escapeHtml(prompt); |
|
|
captionDiv.appendChild(promptCaption); |
|
|
|
|
|
|
|
|
if (negativePrompt) { |
|
|
const negativeCaption = document.createElement("p"); |
|
|
negativeCaption.className = "text-[var(--color-text-secondary)] mb-1.5 break-words"; |
|
|
negativeCaption.innerHTML = '<strong>Negative Prompt:</strong> ' + escapeHtml(negativePrompt); |
|
|
captionDiv.appendChild(negativeCaption); |
|
|
} |
|
|
|
|
|
|
|
|
const detailsDiv = document.createElement("div"); |
|
|
detailsDiv.className = "flex flex-wrap gap-3 text-[10px] text-[var(--color-text-secondary)] mt-1.5"; |
|
|
detailsDiv.innerHTML = ` |
|
|
<span><strong>Size:</strong> ${size}</span> |
|
|
${step !== undefined ? `<span><strong>Steps:</strong> ${step}</span>` : ''} |
|
|
${seed !== undefined ? `<span><strong>Seed:</strong> ${seed}</span>` : ''} |
|
|
`; |
|
|
captionDiv.appendChild(detailsDiv); |
|
|
|
|
|
|
|
|
const copyBtn = document.createElement("button"); |
|
|
copyBtn.className = "mt-1.5 px-2 py-0.5 text-[10px] bg-[var(--color-primary)] text-white rounded hover:opacity-80"; |
|
|
copyBtn.innerHTML = '<i class="fas fa-copy mr-1"></i>Copy Prompt'; |
|
|
copyBtn.onclick = () => { |
|
|
navigator.clipboard.writeText(prompt).then(() => { |
|
|
copyBtn.innerHTML = '<i class="fas fa-check mr-1"></i>Copied!'; |
|
|
setTimeout(() => { |
|
|
copyBtn.innerHTML = '<i class="fas fa-copy mr-1"></i>Copy Prompt'; |
|
|
}, 2000); |
|
|
}); |
|
|
}; |
|
|
captionDiv.appendChild(copyBtn); |
|
|
|
|
|
imageContainer.appendChild(captionDiv); |
|
|
resultDiv.appendChild(imageContainer); |
|
|
}); |
|
|
|
|
|
if (resultPlaceholder) { |
|
|
resultPlaceholder.style.display = "none"; |
|
|
} |
|
|
} else { |
|
|
resultDiv.innerHTML = '<p class="text-xs text-[var(--color-text-secondary)] p-2">No images were generated.</p>'; |
|
|
if (resultPlaceholder) { |
|
|
resultPlaceholder.style.display = "none"; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} catch (error) { |
|
|
console.error("Error generating image:", error); |
|
|
resultDiv.innerHTML = '<p class="text-xs text-red-500 p-2">Error: ' + error.message + '</p>'; |
|
|
if (resultPlaceholder) { |
|
|
resultPlaceholder.style.display = "none"; |
|
|
} |
|
|
} finally { |
|
|
|
|
|
loader.classList.add("hidden"); |
|
|
input.disabled = false; |
|
|
generateBtn.disabled = false; |
|
|
input.focus(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function escapeHtml(text) { |
|
|
const div = document.createElement("div"); |
|
|
div.textContent = text; |
|
|
return div.innerHTML; |
|
|
} |
|
|
|
|
|
|
|
|
document.addEventListener("DOMContentLoaded", function() { |
|
|
const input = document.getElementById("input"); |
|
|
const form = document.getElementById("genimage"); |
|
|
|
|
|
if (input) { |
|
|
input.focus(); |
|
|
} |
|
|
|
|
|
if (form) { |
|
|
form.addEventListener("submit", genImage); |
|
|
} |
|
|
|
|
|
|
|
|
if (input) { |
|
|
input.addEventListener("keydown", function(event) { |
|
|
if (event.key === "Enter" && !event.shiftKey) { |
|
|
event.preventDefault(); |
|
|
genImage(event); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
const loader = document.getElementById("loader"); |
|
|
if (loader) { |
|
|
loader.classList.add("hidden"); |
|
|
} |
|
|
}); |
|
|
|