let reader; let currentStreamId; function execDocReady() { const pluginGroups = [ [ "../reference/lightblue4/docs/lib/widgster/widgster.js", "../reference/lightblue4/docs/lib/slimScroll/jquery.slimscroll.min.js", "./js/common/showdown/showdown.js", "../reference/jquery-plugins/timerStyles.js" ] ]; loadPluginGroupsParallelAndSequential(pluginGroups) .then(function () { console.log("모든 플러그인 로드 완료"); //coming soon $("#count-down").TimeCircles({ circle_bg_color: "#f8f8f8", use_background: true, bg_width: 0.2, fg_width: 0.013, time: { Days: { color: "#f8f8f8" }, Hours: { color: "#f8f8f8" }, Minutes: { color: "#f8f8f8" }, Seconds: { color: "#f8f8f8" } } }); $("#chat").slimScroll({ height: "574px", railVisible: true, railColor: "#222", railOpacity: 0.3, wheelStep: 10, allowPageScroll: false, disableFadeOut: false }); $(".widget").widgster(); setSideMenu("sidebar_large_menu_ai", "sidebar_medium_menu_ai_adms", "sidebar_small_menu_ai_ai_chat"); setSideMenu("toggle_large_menu_ai", "toggle_medium_menu_ai_dashboard"); initSendMessageEvent(); }) .catch(function () { console.error("플러그인 로드 중 오류 발생"); }); $("#message-stop-btn").click(function () { cancel(); }); } function cancel() { if (reader && currentStreamId) { fetch(`/ai-api/ai/stopStream?streamId=${currentStreamId}`) .then((response) => { if (!response.ok) { console.error("스트림 중단 요청 실패:", response.status); } else { console.log("스트림 중단 요청 성공:", currentStreamId); } }) .catch((error) => { console.error("스트림 중단 요청 중 오류:", error); }); reader.cancel(); currentStreamId = null; // 중단 후 ID 초기화 } } function initSendMessageEvent() { // 전송 버튼 클릭 시 $("#message-send-btn").on("click", function () { sendMessage(); }); // 엔터 키 눌렀을 때도 전송 $("#new_message").on("keyup", function (e) { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); // 줄바꿈 방지 sendMessage(); } }); } // 사용자 메시지 처리 함수 따로 빼기 function sendMessage() { const messageText = $("#new_message").val().trim(); if (messageText === "") return; // 사용자 메시지 UI 추가 const userMessage = $(`
${$("
").text(messageText).html()}
`); $("#chat").append(userMessage); // 입력창 초기화 + 스크롤 하단 이동 $("#new_message").val(""); $("#chat").scrollTop($("#chat")[0].scrollHeight); sendChat(messageText); // AI 응답 } // showdown.js 인스턴스 생성 const converter = new showdown.Converter(); function sendChat(userInput) { cancel(); // 이전 요청 중단 const sendBtn = $("#message-send-btn"); const stopBtn = $("#message-stop-btn"); // 버튼 상태: 전송 숨기고, 멈춤 보이기 sendBtn.hide(); stopBtn.show(); const aiMessage = $(`
loading...
`); $("#chat").append(aiMessage); $("#chat").scrollTop($("#chat")[0].scrollHeight); // 새로운 streamId 생성 currentStreamId = generateStreamId(); const params = new URLSearchParams({ message: userInput, streamId: currentStreamId }).toString(); const converter = new showdown.Converter(); fetch(`/ai-api/ai/generateStream?${params}`).then((res) => { console.log(res); aiMessage.find(".loading-gif").remove(); let accumulatedText = ""; if (res.status != 200) { aiMessage.find(".text").append("지금은 답변을 드릴 수가 없습니다."); stopBtn.hide(); sendBtn.show(); return; } reader = res.body.pipeThrough(new TextDecoderStream()).getReader(); // 멈춤 버튼 클릭 시: cancel() + 버튼 상태 복구 stopBtn.off("click").on("click", () => { cancel(); stopBtn.hide(); sendBtn.show(); }); // 스트리밍 읽기 function processStream({ done, value }) { if (done) { console.log("done"); stopBtn.hide(); // 멈춤 버튼 숨김 sendBtn.show(); // 전송 버튼 다시 보이기 currentStreamId = null; // 스트림 종료 시 ID 초기화 return; } // 누적된 텍스트에 스트리밍된 데이터 추가 accumulatedText += value; // 줄 단위로 Markdown 변환 const lines = accumulatedText.split("\n"); let formattedText = lines; if (lines.length > 1) { formattedText = lines .map((line) => { let index = line.indexOf(" "); if (index > -1) { return " " + converter.makeHtml(line.substring(index)); } return converter.makeHtml(line); }) .join("
"); } aiMessage.find(".text").html(formattedText); $("#chat").scrollTop($("#chat")[0].scrollHeight); // 다음 스트리밍 데이터를 계속 처리 reader.read().then(processStream); } // 스트리밍 시작 reader.read().then(processStream); }); } function generateStreamId() { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8; return v.toString(16); }); }