Spaces:
Running
Running
File size: 5,535 Bytes
877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 877b8f2 4fe2976 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
let characters=[];
// Tab switching
document.querySelectorAll(".tab-btn").forEach(btn=>{
btn.addEventListener("click",()=>{
document.querySelectorAll(".tab-btn").forEach(b=>b.classList.remove("active"));
document.querySelectorAll(".tab-content").forEach(c=>c.classList.add("hidden"));
btn.classList.add("active");
document.getElementById(btn.dataset.tab).classList.remove("hidden");
});
});
// Add character
document.getElementById("add-character").addEventListener("click",()=>{
const container=document.createElement("div");
container.className="border p-4 rounded";
container.innerHTML=`
<input class="char-name w-full p-2 border rounded mb-1" placeholder="Name">
<textarea class="char-desc w-full p-2 border rounded mb-1" placeholder="Character description (appearance, outfit, build, etc.)"></textarea>
<input type="file" class="char-img mb-1" accept="image/png, image/jpeg">
`;
document.getElementById("character-list").appendChild(container);
characters.push({name:"",desc:"",img:null});
});
// Convert file to Base64
function imageFileToBase64(file){
return new Promise((resolve,reject)=>{
const reader=new FileReader();
reader.onload=()=>resolve(reader.result);
reader.onerror=err=>reject(err);
reader.readAsDataURL(file);
});
}
// Make speech bubbles draggable
function makeDraggable(el){
let offsetX,offsetY;
el.onmousedown=e=>{
offsetX=e.clientX-el.offsetLeft; offsetY=e.clientY-el.offsetTop;
document.onmousemove=e=>{el.style.left=(e.clientX-offsetX)+"px"; el.style.top=(e.clientY-offsetY)+"px";}
document.onmouseup=()=>document.onmousemove=null;
};
}
// Comic sound effects
const comicEffects=["BAM!","KAPOW!","KA-BOOM!","WHAM!","ZAP!","BOOM!"];
// Generate panels
document.getElementById("generate-btn").addEventListener("click", async()=>{
const story=document.getElementById("story-input").value.trim();
const panels=parseInt(document.getElementById("panel-count").value);
const apiKey=document.getElementById("api-key").value.trim();
const artStyle=document.getElementById("art-style").value;
const explicit=document.getElementById("explicit-toggle").checked;
const model=document.getElementById("custom-model").value.trim() || "stabilityai/stable-diffusion-2";
const bgDesc=document.getElementById("bg-desc").value.trim();
const preview=document.getElementById("comic-preview");
preview.innerHTML="";
// Collect characters
const charPrompts=[];
const charImages=[];
const charDivs=document.querySelectorAll("#character-list .border");
for(const div of charDivs){
const name=div.querySelector(".char-name").value;
const desc=div.querySelector(".char-desc").value;
const file=div.querySelector(".char-img").files[0];
if(name && desc) charPrompts.push(`${name}: ${desc}`);
if(file) charImages.push(await imageFileToBase64(file));
}
for(let i=0;i<panels;i++){
const panelDiv=document.createElement("div");
panelDiv.className="comic-panel";
panelDiv.innerText="⏳ Generating...";
preview.appendChild(panelDiv);
try{
const prompt=`Panel ${i+1} of story: ${story}. Style: ${artStyle}${explicit ? ", mature, graphic" : ""}. Background: ${bgDesc}. Characters: ${charPrompts.join(", ")}`;
// Generate image with ControlNet reference
const imgResp=await fetch(`https://api-inference.huggingface.co/models/${model}`,{
method:"POST",
headers:{Authorization:`Bearer ${apiKey}`, "Content-Type":"application/json"},
body: JSON.stringify({
inputs: prompt,
parameters: {
guidance_scale: 7.5,
num_inference_steps: 30,
height:512,
width:512,
controlnet_reference_images: charImages
}
})
});
const imgBlob=await imgResp.blob();
const imgUrl=URL.createObjectURL(imgBlob);
panelDiv.innerHTML=`<img src="${imgUrl}" class="comic-img">`;
// Generate short dialogue for speech bubble
const textPrompt=`Generate short comic dialogue for panel ${i+1} with characters: ${charPrompts.join(", ")} including sound effects like BAM, POW, KAPOW.`;
const textResp=await fetch(`https://api-inference.huggingface.co/models/gpt2`,{
method:"POST",
headers:{Authorization:`Bearer ${apiKey}`, "Content-Type":"application/json"},
body:JSON.stringify({inputs:textPrompt,max_new_tokens:40})
}).then(r=>r.json());
// Add draggable speech bubble
const bubble=document.createElement("div");
bubble.className="speech-bubble";
bubble.contentEditable=true;
bubble.innerText=textResp[0]?.generated_text?.split(".")[0] || comicEffects[Math.floor(Math.random()*comicEffects.length)];
makeDraggable(bubble);
panelDiv.appendChild(bubble);
// Add editable caption
const caption=document.createElement("div");
caption.className="caption";
caption.contentEditable=true;
caption.innerText=textResp[0]?.generated_text || "";
panelDiv.appendChild(caption);
}catch(err){
console.error(err);
panelDiv.innerText="❌ Error generating panel";
}
}
});
// Export PDF
document.getElementById("download-btn").addEventListener("click",()=>{
const {jsPDF}=window.jspdf;
const pdf=new jsPDF();
const panels=document.querySelectorAll(".comic-panel img");
panels.forEach((img,i)=>{
if(i>0) pdf.addPage();
pdf.addImage(img.src,"JPEG",10,10,180,160);
});
pdf.save("comic-book.pdf");
});
|