function b64toBlob(b64Data, contentType, sliceSize) { contentType = contentType || ''; sliceSize = sliceSize || 512; var byteCharacters = atob(b64Data); var byteArrays = []; for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) { var slice = byteCharacters.slice(offset, offset + sliceSize); var byteNumbers = new Array(slice.length); for (var i = 0; i < slice.length; i++) { byteNumbers[i] = slice.charCodeAt(i); } var byteArray = new Uint8Array(byteNumbers); byteArrays.push(byteArray); } return new Blob(byteArrays, {type: contentType}); } function uploadImageAI(blob) { var formData = new FormData(); // 파일명은 임의로 지정 ("generated.png") formData.append("file", blob, "generated.png"); // 기존에 숨겨진 input(#editor_nonce)이 있다면 사용하고, // 없으면 전역 변수 ed_nonce를 사용합니다. var nonceElem = document.getElementById('editor_nonce'); if (nonceElem && nonceElem.value) { formData.append("editor_nonce", nonceElem.value); } else if (ed_nonce) { formData.append("editor_nonce", ed_nonce); } else { //console.warn("Nonce 값이 설정되어 있지 않습니다."); } return fetch(g5Config.g5_editor_url + '/php/rb.upload.php', { method: 'POST', body: formData }).then(function(response) { return response.json(); }); } // 함수: 작업 유형에 따른 placeholder 변경 function updatePlaceholder() { var taskType = document.querySelector('input[name="taskType"]:checked').value; var promptInput = document.getElementById('prompt'); if (taskType === 'image') { document.getElementById("prompt_ai_img").src = "./image/ai/Stability.svg"; promptInput.placeholder = "생성 하고자하는 주제를 영문(단어)로 입력하세요."; } else { document.getElementById("prompt_ai_img").src = "./image/ai/Gemini.svg"; promptInput.placeholder = "이전 대화를 기억하지 못합니다. 질의나 문장 생성용으로 사용하세요."; } } // 엔터키 입력 시 바로 요청 document.getElementById('prompt').addEventListener('keydown', function (e) { if (e.key === "Enter") { e.preventDefault(); document.getElementById('generateBtn').click(); } }); // 라디오 버튼 변경 시 플레이스홀더 업데이트 var radios = document.querySelectorAll('input[name="taskType"]'); radios.forEach(function (radio) { radio.addEventListener('change', updatePlaceholder); }); updatePlaceholder(); // 초기 로드시 설정 document.getElementById('generateBtn').addEventListener('click', function () { var prompt = document.getElementById('prompt').value.trim(); var taskType = document.querySelector('input[name="taskType"]:checked').value; // 선택된 작업 유형 if (prompt === '') { alert('생성하실 주제를 입력해 주세요.'); return; } var btn = document.getElementById('generateBtn'); btn.disabled = true; btn.textContent = '생각 중..'; document.getElementById('result').innerHTML = ''; // 로딩 오버레이 표시 var overlay = document.querySelector(".loadingOverlay_ai"); overlay.style.display = "block"; // API 요청 데이터 설정 var formData = new URLSearchParams(); formData.append("prompt", prompt); formData.append("taskType", taskType); fetch(g5Config.g5_editor_url + '/plugin/ai/ajax.generate.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: formData.toString() }) .then(response => response.json()) .then(data => { var editor = document.getElementById("editor"); var accumulateCheckbox = document.getElementById('accumulateCheckbox'); if (taskType === 'text' && data.text) { document.getElementById("prompt_ai_img").src = "./image/ai/Gemini.svg"; // 텍스트의 경우 누적 체크박스가 체크되지 않으면 에디터 초기화 if (!(accumulateCheckbox && accumulateCheckbox.checked)) { editor.innerHTML = ""; } var newText = document.createElement("div"); newText.innerHTML = data.text; var emptyDiv = document.createElement("div"); emptyDiv.innerHTML = "
"; if (editor) { editor.appendChild(newText); editor.appendChild(emptyDiv); // 빈 줄 추가 } else { //console.error("Error: #editor element not found."); } //document.getElementById('result').innerHTML = '

모델 : ' + data.model + '

'; // 텍스트 생성 후 입력창 비우기 document.getElementById('prompt').value = ""; } else if (taskType === 'image') { document.getElementById("prompt_ai_img").src = "./image/ai/Stability.svg"; if (data.image && data.image.length > 0) { // 이미지 생성 성공 시 if (!(accumulateCheckbox && accumulateCheckbox.checked)) { editor.innerHTML = ""; } // base64 데이터를 Blob으로 변환 (타입: image/png) var blob = b64toBlob(data.image, "image/png"); // 생성된 이미지를 업로드합니다. uploadImageAI(blob).then(function(uploadResponse) { if (uploadResponse.files && uploadResponse.files[0] && uploadResponse.files[0].url) { var fileUrl = uploadResponse.files[0].url; // ✅ .resizable_wrap 부모 div 생성 var resizableWrap = document.createElement("div"); resizableWrap.classList.add("resizable_wrap"); resizableWrap.style.position = "relative"; //resizableWrap.style.display = "inline-block"; // 부모 크기 유지 // ✅ AI 이미지용 wrapper 생성 (크기 및 리사이즈 핸들 포함) var newImage = document.createElement("div"); newImage.classList.add("resizable", "rb_ai_image"); newImage.style.width = "450px"; newImage.style.height = "300px"; newImage.style.position = "relative"; // 원본 크기와 비율을 data 속성에 추가 (원본 너비: 450, 원본 높이: 300) newImage.setAttribute("data-original-width", "450"); newImage.setAttribute("data-original-height", "300"); newImage.setAttribute("data-ratio", (300 / 450).toString()); newImage.innerHTML = ` Generated Image
`; // ✅ .resizable_wrap 내부에 .resizable 추가 resizableWrap.appendChild(newImage); editor.appendChild(resizableWrap); // 현재 newImage의 width에 맞춰 높이를 재계산하여 비율 유지 function updateHeight() { var ratio = parseFloat(newImage.getAttribute("data-ratio")); if (!isNaN(ratio)) { newImage.style.height = (newImage.offsetWidth * ratio) + "px"; } } // 초기 높이 업데이트 updateHeight(); // 창 크기 변경 시 업데이트 window.addEventListener("resize", updateHeight); // 필요시, 리사이즈 기능 활성화 (예: makeImageResizableWithObserver) makeImageResizableWithObserver($(newImage)); } else { document.getElementById('result').innerHTML = '

이미지 업로드 실패

'; } }).catch(function(err) { document.getElementById('result').innerHTML = '

이미지 업로드 오류

'; }); } else { // 이미지 생성 실패 또는 에러 처리... if (data.error) { document.getElementById('result').innerHTML = '

이미지 생성 실패

'; } else { document.getElementById('result').innerHTML = '

잠시후 다시 생성해주세요.

'; } } } else if (data.error) { document.getElementById('result').innerHTML = '

오류가 있습니다.

'; } overlay.style.display = "none"; btn.disabled = false; btn.textContent = '생성'; }) .catch(error => { document.getElementById('result').innerHTML = '

오류가 있습니다.

'; document.querySelector(".loadingOverlay_ai").style.display = "none"; btn.disabled = false; btn.textContent = '생성'; }); });