| |
|
|
| import { AUTH_TOKEN_STORAGE_KEY, CURRENT_SESSION_KEY } from './constants.js'; |
| import { fileToBase64, extractContent } from './utils.js'; |
|
|
| |
| |
| |
| |
| |
| |
| |
| export function addMessageToChat(sender, text, userProvidedImageUrl = null, botImageUrls = []) { |
| const chatWindow = document.getElementById('chat-window'); |
| const messageElement = document.createElement('div'); |
| messageElement.classList.add('message', sender); |
|
|
| |
| if (userProvidedImageUrl) { |
| const imgElement = document.createElement('img'); |
| imgElement.src = userProvidedImageUrl; |
| imgElement.style.maxWidth = '200px'; |
| imgElement.style.display = 'block'; |
| imgElement.style.marginTop = '5px'; |
| imgElement.alt = '用户上传图片'; |
| messageElement.appendChild(imgElement); |
| } |
|
|
| let processedText = text; |
| let extractedMermaidCodes = []; |
|
|
| |
| if (sender === 'bot') { |
| |
| const result = extractContent(text); |
| processedText = result.cleanedText; |
| extractedMermaidCodes = result.mermaidCodes; |
| const allImageUrls = [...botImageUrls]; |
|
|
| |
| if (allImageUrls.length > 0) { |
| const authToken = localStorage.getItem(AUTH_TOKEN_STORAGE_KEY); |
| allImageUrls.forEach(imgUrl => { |
| const imgElement = document.createElement('img'); |
| imgElement.style.maxWidth = '200px'; |
| imgElement.style.display = 'block'; |
| imgElement.style.marginTop = '5px'; |
| imgElement.alt = 'Gemini 输出图片'; |
| |
| |
| imgElement.onerror = () => { |
| console.error(`图片加载失败: ${imgUrl}`); |
| imgElement.alt = `图片加载失败: ${imgUrl}`; |
| imgElement.src = ''; |
| }; |
|
|
| |
| if (imgUrl.startsWith('/v1/image_proxy?image_url=')) { |
| if (authToken) { |
| |
| fetch(imgUrl, { |
| headers: { |
| 'X-Auth-Token': authToken |
| } |
| }) |
| .then(response => { |
| if (!response.ok) { |
| throw new Error(`HTTP error! status: ${response.status}`); |
| } |
| return response.blob(); |
| }) |
| .then(imageBlob => { |
| imgElement.src = URL.createObjectURL(imageBlob); |
| messageElement.appendChild(imgElement); |
| }) |
| .catch(error => { |
| console.error(`代理图片加载失败: ${imgUrl}`, error); |
| imgElement.onerror(); |
| }); |
| } else { |
| console.error('未找到认证令牌,无法加载代理图片。'); |
| imgElement.onerror(); |
| } |
| } else { |
| |
| imgElement.src = imgUrl; |
| messageElement.appendChild(imgElement); |
| } |
| }); |
| } |
| } |
|
|
| |
| if (processedText) { |
| const textElement = document.createElement('div'); |
| textElement.innerHTML = marked.parse(processedText); |
| messageElement.appendChild(textElement); |
| } |
| |
| chatWindow.appendChild(messageElement); |
| chatWindow.scrollTop = chatWindow.scrollHeight; |
|
|
| |
| extractedMermaidCodes.forEach((mermaidCode, index) => { |
| const mermaidDiv = document.createElement('div'); |
| mermaidDiv.classList.add('mermaid'); |
| |
| const chartId = `mermaid-chart-${Date.now()}-${index}`; |
| mermaidDiv.id = chartId; |
| messageElement.appendChild(mermaidDiv); |
|
|
| |
| mermaid.render(chartId, mermaidCode) |
| .then(({ svg, bindFunctions }) => { |
| const renderedMermaidDiv = document.getElementById(chartId); |
| if (renderedMermaidDiv) { |
| renderedMermaidDiv.innerHTML = svg; |
| if (bindFunctions) { |
| bindFunctions(renderedMermaidDiv); |
| } |
| } |
| }) |
| .catch(error => { |
| console.error(`Mermaid 渲染失败 (ID: ${chartId}):`, error); |
| const renderedMermaidDiv = document.getElementById(chartId); |
| if (renderedMermaidDiv) { |
| renderedMermaidDiv.innerHTML = `<div style="color: red;">Mermaid 渲染错误: ${error.message || '语法错误'}</div>`; |
| } |
| }); |
| }); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| export function setupSendButton(sendButton, userInput, imageUpload, modelSelect) { |
| if (sendButton) { |
| sendButton.addEventListener('click', async () => { |
| const authToken = localStorage.getItem(AUTH_TOKEN_STORAGE_KEY); |
| const textInput = userInput.value.trim(); |
| const imageFile = imageUpload.files[0]; |
| const selectedModel = modelSelect ? modelSelect.value : "gemini-2.5-flash"; |
|
|
| if (!authToken) { |
| alert('认证令牌未找到,请重新登录。'); |
| window.location.href = '/static/login.html'; |
| return; |
| } |
|
|
| if (!textInput && !imageFile) { |
| alert('请输入文本或上传图片。'); |
| return; |
| } |
|
|
| sendButton.disabled = true; |
| sendButton.textContent = '发送中...'; |
|
|
| let imageUrlForDisplay = null; |
| let base64ImageForRequest = null; |
|
|
| if (imageFile) { |
| base64ImageForRequest = await fileToBase64(imageFile); |
| imageUrlForDisplay = `data:${imageFile.type};base64,${base64ImageForRequest}`; |
| } |
|
|
| const threadId = localStorage.getItem(CURRENT_SESSION_KEY) || ''; |
| |
| addMessageToChat('user', textInput, imageUrlForDisplay); |
|
|
| userInput.value = ''; |
| imageUpload.value = ''; |
|
|
| const requestBody = { |
| model: selectedModel, |
| messages: [{ role: "user", content: textInput }], |
| thread_id: threadId |
| }; |
|
|
| if (base64ImageForRequest) { |
| requestBody.image_data = base64ImageForRequest; |
| requestBody.image_mime_type = imageFile.type; |
| } |
|
|
| try { |
| const response = await fetch('/v1/chat/completions', { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json', |
| 'X-Auth-Token': authToken |
| }, |
| body: JSON.stringify(requestBody) |
| }); |
|
|
| if (response.ok) { |
| const responseData = await response.json(); |
| const botMessageContent = responseData.choices[0]?.message?.content || "无响应内容"; |
| const botImageUrls = responseData.choices[0]?.message?.image_urls || []; |
| addMessageToChat('bot', botMessageContent, null, botImageUrls); |
| } else { |
| const errorData = await response.json(); |
| addMessageToChat('system', `请求失败: ${errorData.detail || response.statusText}`); |
| } |
| } catch (error) { |
| addMessageToChat('system', `请求出错: ${error.message}`); |
| } finally { |
| sendButton.disabled = false; |
| sendButton.textContent = '发送'; |
| } |
| }); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| export function setupPasteImage(userInput, imageUpload) { |
| if (userInput) { |
| userInput.addEventListener('paste', (event) => { |
| const items = (event.clipboardData || event.originalEvent.clipboardData).items; |
| for (const item of items) { |
| if (item.kind === 'file' && item.type.startsWith('image/')) { |
| const blob = item.getAsFile(); |
| const dataTransfer = new DataTransfer(); |
| dataTransfer.items.add(blob); |
| imageUpload.files = dataTransfer.files; |
| |
| const reader = new FileReader(); |
| reader.onload = (e) => { |
| addMessageToChat('user', '图片已粘贴,等待发送...', e.target.result); |
| console.log('图片已从剪切板粘贴,准备上传。'); |
| }; |
| reader.readAsDataURL(blob); |
| event.preventDefault(); |
| break; |
| } |
| } |
| }); |
| } |
| } |
|
|