jeongsoo's picture
add function
460bd69
/**
* RAG 검색 챗봇 LLM κ΄€λ ¨ JavaScript
*/
/**
* LLM λͺ©λ‘ λ‘œλ“œ ν•¨μˆ˜
*/
async function loadLLMs() {
try {
console.log('LLM λͺ©λ‘ λ‘œλ“œ μ‹œμž‘');
// API μš”μ²­
const response = await fetch('/api/llm');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
supportedLLMs = data.supported_llms;
currentLLM = data.current_llm.id;
console.log(`λ‘œλ“œλœ LLM 수: ${supportedLLMs.length}, ν˜„μž¬ LLM: ${currentLLM}`);
// LLM 선택 λ“œλ‘­λ‹€μš΄ μ—…λ°μ΄νŠΈ
llmSelect.innerHTML = '';
supportedLLMs.forEach(llm => {
const option = document.createElement('option');
option.value = llm.id;
option.textContent = llm.name;
option.selected = llm.current;
llmSelect.appendChild(option);
});
// ν˜„μž¬ LLM ν‘œμ‹œ
updateCurrentLLMInfo(data.current_llm);
console.log('LLM λͺ©λ‘ λ‘œλ“œ μ™„λ£Œ');
} catch (error) {
console.error('LLM λͺ©λ‘ λ‘œλ“œ μ‹€νŒ¨:', error);
}
}
/**
* LLM λ³€κ²½ ν•¨μˆ˜
* @param {string} llmId - λ³€κ²½ν•  LLM ID
*/
async function changeLLM(llmId) {
try {
console.log(`LLM λ³€κ²½ μ‹œμž‘: ${llmId}`);
// API μš”μ²­
const response = await fetch('/api/llm', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ llm_id: llmId })
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
if (data.success) {
currentLLM = llmId;
updateCurrentLLMInfo(data.current_llm);
console.log(`LLM λ³€κ²½ 성곡: ${data.current_llm.name}`);
// μ‹œμŠ€ν…œ λ©”μ‹œμ§€ μΆ”κ°€
const systemMessage = `LLM이 ${data.current_llm.name}(으)둜 λ³€κ²½λ˜μ—ˆμŠ΅λ‹ˆλ‹€. λͺ¨λΈ: ${data.current_llm.model}`;
addSystemNotification(systemMessage);
} else if (data.error) {
console.error('LLM λ³€κ²½ 였λ₯˜:', data.error);
alert(`LLM λ³€κ²½ 였λ₯˜: ${data.error}`);
}
} catch (error) {
console.error('LLM λ³€κ²½ μ‹€νŒ¨:', error);
alert('LLM λ³€κ²½ 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.');
}
}
/**
* ν˜„μž¬ LLM 정보 ν‘œμ‹œ μ—…λ°μ΄νŠΈ
* @param {Object} llmInfo - LLM 정보 객체
*/
function updateCurrentLLMInfo(llmInfo) {
console.log(`ν˜„μž¬ LLM 정보 μ—…λ°μ΄νŠΈ: ${llmInfo.name} (${llmInfo.model})`);
if (currentLLMInfo) {
currentLLMInfo.textContent = `${llmInfo.name} (${llmInfo.model})`;
}
}
/**
* μ±„νŒ… λ©”μ‹œμ§€ 전솑 ν•¨μˆ˜
*/
async function sendMessage() {
const message = userInput.value.trim();
if (!message) return;
console.log(`λ©”μ‹œμ§€ 전솑: "${message}"`);
// UI μ—…λ°μ΄νŠΈ
addMessage(message, 'user');
userInput.value = '';
adjustTextareaHeight();
// λ‘œλ”© λ©”μ‹œμ§€ μΆ”κ°€
const loadingMessageId = addLoadingMessage();
try {
console.log('μ±„νŒ… API μš”μ²­ μ‹œμž‘');
// API μš”μ²­
const response = await fetch('/api/chat', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
query: message,
llm_id: currentLLM // ν˜„μž¬ μ„ νƒλœ LLM 전솑
})
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('μ±„νŒ… API 응닡 μˆ˜μ‹  μ™„λ£Œ');
// λ‘œλ”© λ©”μ‹œμ§€ 제거
removeLoadingMessage(loadingMessageId);
// 응닡 ν‘œμ‹œ
if (data.error) {
console.error('μ±„νŒ… 응닡 였λ₯˜:', data.error);
addErrorMessage(data.error);
} else {
// LLM 정보 μ—…λ°μ΄νŠΈ
if (data.llm) {
updateCurrentLLMInfo(data.llm);
}
console.log('봇 응닡 ν‘œμ‹œ');
addMessage(data.answer, 'bot', null, data.sources);
}
} catch (error) {
console.error('μ±„νŒ… μš”μ²­ 였λ₯˜:', error);
removeLoadingMessage(loadingMessageId);
addErrorMessage('였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. λ‹€μ‹œ μ‹œλ„ν•΄ μ£Όμ„Έμš”.');
}
}
/**
* μŒμ„± λ…ΉμŒ μ‹œμž‘ ν•¨μˆ˜
*/
async function startRecording() {
if (isRecording) return;
console.log('μŒμ„± λ…ΉμŒ μ‹œμž‘ μš”μ²­');
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
isRecording = true;
audioChunks = [];
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.addEventListener('dataavailable', (event) => {
if (event.data.size > 0) audioChunks.push(event.data);
console.log('μ˜€λ””μ˜€ 데이터 청크 μˆ˜μ‹ λ¨');
});
mediaRecorder.addEventListener('stop', sendAudioMessage);
// λ…ΉμŒ μ‹œμž‘
mediaRecorder.start();
console.log('MediaRecorder μ‹œμž‘λ¨');
// UI μ—…λ°μ΄νŠΈ
micButton.style.display = 'none';
recordingStatus.classList.remove('hidden');
} catch (error) {
console.error('μŒμ„± λ…ΉμŒ κΆŒν•œμ„ 얻을 수 μ—†μŠ΅λ‹ˆλ‹€:', error);
alert('마이크 μ ‘κ·Ό κΆŒν•œμ΄ ν•„μš”ν•©λ‹ˆλ‹€.');
}
}
/**
* μŒμ„± λ…ΉμŒ 쀑지 ν•¨μˆ˜
*/
function stopRecording() {
if (!isRecording || !mediaRecorder) return;
console.log('μŒμ„± λ…ΉμŒ 쀑지 μš”μ²­');
mediaRecorder.stop();
isRecording = false;
// UI μ—…λ°μ΄νŠΈ
micButton.style.display = 'flex';
recordingStatus.classList.add('hidden');
console.log('MediaRecorder 쀑지됨');
}
/**
* λ…ΉμŒλœ μ˜€λ””μ˜€ λ©”μ‹œμ§€ 전솑 ν•¨μˆ˜
*/
async function sendAudioMessage() {
if (audioChunks.length === 0) return;
console.log(`μ˜€λ””μ˜€ λ©”μ‹œμ§€ 전솑 μ€€λΉ„, ${audioChunks.length}개 청크`);
// μ˜€λ””μ˜€ Blob 생성
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
// λ‘œλ”© λ©”μ‹œμ§€ μΆ”κ°€
const loadingMessageId = addLoadingMessage();
try {
// FormData에 μ˜€λ””μ˜€ μΆ”κ°€
const formData = new FormData();
formData.append('audio', audioBlob, 'recording.wav');
// ν˜„μž¬ μ„ νƒλœ LLM μΆ”κ°€
formData.append('llm_id', currentLLM);
console.log('μŒμ„± API μš”μ²­ μ‹œμž‘');
// API μš”μ²­
const response = await fetch('/api/voice', {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log('μŒμ„± API 응닡 μˆ˜μ‹  μ™„λ£Œ');
// λ‘œλ”© λ©”μ‹œμ§€ 제거
removeLoadingMessage(loadingMessageId);
// 응닡 ν‘œμ‹œ
if (data.error) {
console.error('μŒμ„± 응닡 였λ₯˜:', data.error);
addErrorMessage(data.error);
} else {
// LLM 정보 μ—…λ°μ΄νŠΈ
if (data.llm) {
updateCurrentLLMInfo(data.llm);
}
// μ‚¬μš©μž λ©”μ‹œμ§€(μŒμ„± ν…μŠ€νŠΈ) μΆ”κ°€
if (data.transcription) {
console.log(`μŒμ„± 인식 κ²°κ³Ό: "${data.transcription}"`);
addMessage(data.transcription, 'user');
}
// 봇 응닡 μΆ”κ°€
console.log('봇 응닡 ν‘œμ‹œ');
addMessage(data.answer, 'bot', data.transcription, data.sources);
}
} catch (error) {
console.error('μŒμ„± μš”μ²­ 였λ₯˜:', error);
removeLoadingMessage(loadingMessageId);
addErrorMessage('μ˜€λ””μ˜€ 처리 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. λ‹€μ‹œ μ‹œλ„ν•΄ μ£Όμ„Έμš”.');
}
}