- Add MongoDB type manager implementation (TypeManagerMongo) - Update environment variables configuration to support MongoDB connection - Add chat functionality - Integrate Azure OpenAI API support - Update dependencies and startup script
221 lines
7.4 KiB
JavaScript
221 lines
7.4 KiB
JavaScript
// 页面加载完成后执行
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// 初始化图片上传表单
|
||
initUploadImageForm();
|
||
|
||
// 初始化聊天表单
|
||
initChatForm();
|
||
});
|
||
|
||
// 初始化图片上传表单
|
||
function initUploadImageForm() {
|
||
const form = document.getElementById('uploadImageForm');
|
||
const fileInput = document.getElementById('chatImageFile');
|
||
const previewContainer = document.getElementById('uploadPreview');
|
||
const previewImage = document.getElementById('previewImage');
|
||
const chatContainer = document.getElementById('chatContainer');
|
||
const imageTypeElement = document.getElementById('imageType');
|
||
const imageDescriptionElement = document.getElementById('imageDescription');
|
||
|
||
// 图片选择预览
|
||
fileInput.addEventListener('change', function() {
|
||
if (this.files && this.files[0]) {
|
||
const reader = new FileReader();
|
||
|
||
reader.onload = function(e) {
|
||
previewImage.src = e.target.result;
|
||
previewContainer.classList.remove('d-none');
|
||
};
|
||
|
||
reader.readAsDataURL(this.files[0]);
|
||
}
|
||
});
|
||
|
||
// 表单提交
|
||
form.addEventListener('submit', async function(e) {
|
||
e.preventDefault();
|
||
|
||
const formData = new FormData(this);
|
||
|
||
// 显示上传中状态
|
||
const submitButton = form.querySelector('button[type="submit"]');
|
||
const originalButtonText = submitButton.innerHTML;
|
||
submitButton.disabled = true;
|
||
submitButton.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 上传中...';
|
||
|
||
try {
|
||
const response = await fetch('/api/upload-chat-image', {
|
||
method: 'POST',
|
||
body: formData
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.error) {
|
||
alert(`上传失败: ${data.error}`);
|
||
return;
|
||
}
|
||
|
||
// 显示图片信息
|
||
if (data.image_type) {
|
||
imageTypeElement.textContent = data.image_type;
|
||
imageTypeElement.classList.remove('d-none');
|
||
} else {
|
||
imageTypeElement.classList.add('d-none');
|
||
}
|
||
|
||
if (data.description) {
|
||
imageDescriptionElement.textContent = data.description;
|
||
imageDescriptionElement.classList.remove('d-none');
|
||
} else {
|
||
imageDescriptionElement.classList.add('d-none');
|
||
}
|
||
|
||
// 显示聊天界面
|
||
chatContainer.classList.remove('d-none');
|
||
|
||
// 添加欢迎消息
|
||
const chatMessages = document.getElementById('chatMessages');
|
||
chatMessages.innerHTML = '';
|
||
|
||
const welcomeMessage = document.createElement('div');
|
||
welcomeMessage.className = 'message message-assistant';
|
||
|
||
let welcomeText = '你好!我是AI助手,可以帮你分析这张图片并回答问题。';
|
||
if (data.image_type && data.description) {
|
||
welcomeText += `我看到这是一张${data.image_type}的图片,${data.description}。你有什么想问的吗?`;
|
||
} else {
|
||
welcomeText += '你有什么想问的吗?';
|
||
}
|
||
|
||
welcomeMessage.innerHTML = `
|
||
<div class="message-content">${welcomeText}</div>
|
||
<div class="message-time">${getCurrentTime()}</div>
|
||
`;
|
||
|
||
chatMessages.appendChild(welcomeMessage);
|
||
|
||
// 滚动到底部
|
||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||
|
||
} catch (error) {
|
||
alert(`上传失败: ${error.message}`);
|
||
} finally {
|
||
// 恢复按钮状态
|
||
submitButton.disabled = false;
|
||
submitButton.innerHTML = originalButtonText;
|
||
}
|
||
});
|
||
}
|
||
|
||
// 初始化聊天表单
|
||
function initChatForm() {
|
||
const form = document.getElementById('chatForm');
|
||
const messageInput = document.getElementById('messageInput');
|
||
const chatMessages = document.getElementById('chatMessages');
|
||
|
||
form.addEventListener('submit', async function(e) {
|
||
e.preventDefault();
|
||
|
||
const message = messageInput.value.trim();
|
||
if (!message) return;
|
||
|
||
// 添加用户消息到聊天界面
|
||
addMessage('user', message);
|
||
|
||
// 清空输入框
|
||
messageInput.value = '';
|
||
|
||
// 显示正在输入指示器
|
||
const typingIndicator = document.createElement('div');
|
||
typingIndicator.className = 'typing-indicator';
|
||
typingIndicator.innerHTML = '<span></span><span></span><span></span>';
|
||
chatMessages.appendChild(typingIndicator);
|
||
|
||
// 滚动到底部
|
||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||
|
||
try {
|
||
const response = await fetch('/api/chat', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
message: message
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
// 移除正在输入指示器
|
||
chatMessages.removeChild(typingIndicator);
|
||
|
||
if (data.error) {
|
||
alert(`对话失败: ${data.error}`);
|
||
return;
|
||
}
|
||
|
||
// 添加AI回复到聊天界面
|
||
addMessage('assistant', data.reply);
|
||
|
||
} catch (error) {
|
||
// 移除正在输入指示器
|
||
if (typingIndicator.parentNode === chatMessages) {
|
||
chatMessages.removeChild(typingIndicator);
|
||
}
|
||
|
||
alert(`对话失败: ${error.message}`);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 添加消息到聊天界面
|
||
function addMessage(role, content) {
|
||
const chatMessages = document.getElementById('chatMessages');
|
||
|
||
const messageElement = document.createElement('div');
|
||
messageElement.className = `message message-${role}`;
|
||
|
||
messageElement.innerHTML = `
|
||
<div class="message-content">${formatMessage(content)}</div>
|
||
<div class="message-time">${getCurrentTime()}</div>
|
||
`;
|
||
|
||
chatMessages.appendChild(messageElement);
|
||
|
||
// 滚动到底部
|
||
chatMessages.scrollTop = chatMessages.scrollHeight;
|
||
}
|
||
|
||
// 格式化消息内容,支持简单的markdown
|
||
function formatMessage(content) {
|
||
// 转义HTML特殊字符
|
||
let formatted = content
|
||
.replace(/&/g, '&')
|
||
.replace(/</g, '<')
|
||
.replace(/>/g, '>');
|
||
|
||
// 支持加粗
|
||
formatted = formatted.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
|
||
|
||
// 支持斜体
|
||
formatted = formatted.replace(/\*(.*?)\*/g, '<em>$1</em>');
|
||
|
||
// 支持代码
|
||
formatted = formatted.replace(/`(.*?)`/g, '<code>$1</code>');
|
||
|
||
// 支持换行
|
||
formatted = formatted.replace(/\n/g, '<br>');
|
||
|
||
return formatted;
|
||
}
|
||
|
||
// 获取当前时间
|
||
function getCurrentTime() {
|
||
const now = new Date();
|
||
const hours = now.getHours().toString().padStart(2, '0');
|
||
const minutes = now.getMinutes().toString().padStart(2, '0');
|
||
return `${hours}:${minutes}`;
|
||
}
|