jeongsoo's picture
merge1
1681cd4
/**
* RAG 검색 챗봇 UI 곡톡 μœ ν‹Έλ¦¬ν‹° JavaScript
*/
// μ „μ—­ μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜
const AppUtils = {
// μ‹œμŠ€ν…œ μ•Œλ¦Ό λ©”μ‹œμ§€ μΆ”κ°€
addSystemNotification: function(message) {
console.log(`[μ‹œμŠ€ν…œ μ•Œλ¦Ό] ${message}`);
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', 'system');
const contentDiv = document.createElement('div');
contentDiv.classList.add('message-content');
const messageP = document.createElement('p');
messageP.innerHTML = `<i class="fas fa-info-circle"></i> ${message}`;
contentDiv.appendChild(messageP);
messageDiv.appendChild(contentDiv);
// μ±„νŒ… λ©”μ‹œμ§€ μ˜μ—­μ΄ 있으면 μΆ”κ°€
const chatMessages = document.getElementById('chatMessages');
if (chatMessages) {
chatMessages.appendChild(messageDiv);
// μŠ€ν¬λ‘€μ„ κ°€μž₯ μ•„λž˜λ‘œ 이동
chatMessages.scrollTop = chatMessages.scrollHeight;
}
},
// 였λ₯˜ λ©”μ‹œμ§€ μΆ”κ°€
addErrorMessage: function(errorText) {
console.error(`[였λ₯˜] ${errorText}`);
const messageDiv = document.createElement('div');
messageDiv.classList.add('message', 'system');
const contentDiv = document.createElement('div');
contentDiv.classList.add('message-content');
contentDiv.style.backgroundColor = 'rgba(239, 68, 68, 0.1)';
contentDiv.style.color = 'var(--error-color)';
const errorP = document.createElement('p');
errorP.innerHTML = `<i class="fas fa-exclamation-circle"></i> ${errorText}`;
contentDiv.appendChild(errorP);
messageDiv.appendChild(contentDiv);
// μ±„νŒ… λ©”μ‹œμ§€ μ˜μ—­μ΄ 있으면 μΆ”κ°€
const chatMessages = document.getElementById('chatMessages');
if (chatMessages) {
chatMessages.appendChild(messageDiv);
// μŠ€ν¬λ‘€μ„ κ°€μž₯ μ•„λž˜λ‘œ 이동
chatMessages.scrollTop = chatMessages.scrollHeight;
}
},
// νƒ€μž„μ•„μ›ƒ κΈ°λŠ₯이 μžˆλŠ” fetch
fetchWithTimeout: async function(url, options = {}, timeout = 30000) {
console.log(`API μš”μ²­: ${options.method || 'GET'} ${url}`);
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
clearTimeout(id);
console.log(`API 응닡 μƒνƒœ: ${response.status}`);
return response;
} catch (error) {
clearTimeout(id);
if (error.name === 'AbortError') {
console.error(`API μš”μ²­ νƒ€μž„μ•„μ›ƒ: ${url}`);
throw new Error('μš”μ²­ μ‹œκ°„μ΄ μ΄ˆκ³Όλ˜μ—ˆμŠ΅λ‹ˆλ‹€.');
}
console.error(`API μš”μ²­ μ‹€νŒ¨: ${url}`, error);
throw error;
}
},
// λ‘œλ”© μŠ€ν”Όλ„ˆ HTML 생성
createLoadingSpinner: function() {
return '<div class="loading-spinner"></div>';
},
// λ‚ μ§œ ν¬λ§·νŒ…
formatDate: function(date) {
return new Date(date).toLocaleString('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
},
// HTML λ¬Έμžμ—΄ μ΄μŠ€μΌ€μ΄ν”„ (XSS λ°©μ§€)
escapeHtml: function(html) {
const div = document.createElement('div');
div.textContent = html;
return div.innerHTML;
}
};
// νŽ˜μ΄μ§€ λ‘œλ“œ μ™„λ£Œ μ‹œ 곡톡 μ΄ˆκΈ°ν™”
document.addEventListener('DOMContentLoaded', function() {
console.log('μ•± μ½”μ–΄ λͺ¨λ“ˆ μ΄ˆκΈ°ν™” μ™„λ£Œ');
});