document.addEventListener('DOMContentLoaded', function() { // 添加基础URL配置 const BASE_URL = 'https://jasonnoy-boss-translator.hf.space/'; // 空字符串表示使用相对路径 // 动态文案循环显示 - 打字机效果 const dynamicText = document.getElementById('dynamic-text'); if (dynamicText) { const texts = ['"丑"', '"不高级"', '"再试试"']; let currentIndex = 0; let isDeleting = false; let charIndex = 0; let typingSpeed = 150; // 打字速度 let pauseTime = 2000; // 完成后暂停时间,调整为2秒 function typeEffect() { const currentText = texts[currentIndex]; if (!isDeleting) { // 打字阶段 if (charIndex < currentText.length) { dynamicText.textContent = currentText.substring(0, charIndex + 1); charIndex++; setTimeout(typeEffect, typingSpeed); } else { // 完成打字,等待删除 setTimeout(() => { isDeleting = true; typeEffect(); }, pauseTime); } } else { // 删除阶段 if (charIndex > 0) { dynamicText.textContent = currentText.substring(0, charIndex); charIndex--; setTimeout(typeEffect, typingSpeed / 2); } else { // 完成删除,切换到下一个文案 isDeleting = false; currentIndex = (currentIndex + 1) % texts.length; setTimeout(typeEffect, 500); } } } // 开始打字机效果 typeEffect(); } // 添加花朵的微小浮动动画 const flowerImg = document.querySelector('.flower-img'); if (flowerImg) { flowerImg.style.animation = 'floatFlower 4s ease-in-out infinite alternate'; } // 添加浮动动画的CSS const style = document.createElement('style'); style.textContent = ` @keyframes floatFlower { 0% { transform: translateY(0) rotate(0); } 100% { transform: translateY(-15px) rotate(2deg); } } `; document.head.appendChild(style); // 图片上传处理 const imageUploadArea = document.getElementById('image-upload'); const imageInput = document.getElementById('image-input'); if (imageUploadArea && imageInput) { imageUploadArea.addEventListener('click', function() { imageInput.click(); }); imageInput.addEventListener('change', function() { if (this.files && this.files[0]) { const reader = new FileReader(); reader.onload = function(e) { // 移除上传按钮 while (imageUploadArea.firstChild) { imageUploadArea.removeChild(imageUploadArea.firstChild); } // 添加预览图片 const img = document.createElement('img'); img.src = e.target.result; imageUploadArea.appendChild(img); imageUploadArea.classList.add('with-image'); // 存储图片数据到 sessionStorage 以便在反馈页面使用 sessionStorage.setItem('uploadedImage', e.target.result); }; reader.readAsDataURL(this.files[0]); } }); // 拖放上传功能 ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { imageUploadArea.addEventListener(eventName, preventDefaults, false); }); function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } ['dragenter', 'dragover'].forEach(eventName => { imageUploadArea.addEventListener(eventName, function() { imageUploadArea.classList.add('highlight'); }, false); }); ['dragleave', 'drop'].forEach(eventName => { imageUploadArea.addEventListener(eventName, function() { imageUploadArea.classList.remove('highlight'); }, false); }); imageUploadArea.addEventListener('drop', function(e) { const dt = e.dataTransfer; const files = dt.files; if (files && files[0]) { imageInput.files = files; const reader = new FileReader(); reader.onload = function(e) { // 移除上传按钮 while (imageUploadArea.firstChild) { imageUploadArea.removeChild(imageUploadArea.firstChild); } // 添加预览图片 const img = document.createElement('img'); img.src = e.target.result; imageUploadArea.appendChild(img); imageUploadArea.classList.add('with-image'); sessionStorage.setItem('uploadedImage', e.target.result); console.log("image uploaded") }; reader.readAsDataURL(files[0]); } }, false); } // 解析按钮处理 const resolveButton = document.getElementById('resolve-button'); const textInput = document.getElementById('text-input'); if (resolveButton && textInput) { resolveButton.addEventListener('click', function() { const text = textInput.value.trim(); // 检查是否有文本输入 if (text === '') { alert('请输入需求方反馈内容'); return; } // 显示加载状态 resolveButton.disabled = true; // 有趣的加载文案 const loadingTexts = [ "检测到需求方第8版需求残留怨气...正在召唤阴阳师修改图层结界", "监控到大象对话框散发红光!自动生成24K纯杠精防护罩..." ]; // 随机选择一个文案作为起点 let currentTextIndex = Math.floor(Math.random() * loadingTexts.length); let currentText = loadingTexts[currentTextIndex]; let charIndex = 0; let typingSpeed = 100; // 打字速度,从50ms增加到100ms // 添加弹跳动画的CSS if (!document.getElementById('bounce-animation-style')) { const bounceStyle = document.createElement('style'); bounceStyle.id = 'bounce-animation-style'; bounceStyle.textContent = ` .wave-container { position: relative; white-space: nowrap; } .bounce-text { display: inline-block; position: relative; transition: transform 0.3s ease-out; } `; document.head.appendChild(bounceStyle); } // 创建一个容器来包含所有字符 const waveContainer = document.createElement('div'); waveContainer.className = 'wave-container'; resolveButton.innerHTML = ''; resolveButton.appendChild(waveContainer); // 跟踪波峰位置 let peakPosition = -1; let waveInterval; // 打字机效果函数 function typeLoadingText() { if (charIndex < currentText.length) { // 创建一个span元素包装字符 const charSpan = document.createElement('span'); charSpan.className = 'bounce-text'; charSpan.textContent = currentText.charAt(charIndex); // 添加到容器 waveContainer.appendChild(charSpan); charIndex++; setTimeout(typeLoadingText, typingSpeed); // 如果这是第一个字符,开始波动动画 if (charIndex === 1) { startWaveAnimation(); } } else { // 当前文案打完,等待一段时间后切换到下一个文案 setTimeout(() => { // 清除波动动画 if (waveInterval) { clearInterval(waveInterval); waveInterval = null; } // 切换到下一个文案 charIndex = 0; currentTextIndex = (currentTextIndex + 1) % loadingTexts.length; currentText = loadingTexts[currentTextIndex]; // 清空容器,准备下一个文案 waveContainer.innerHTML = ''; typeLoadingText(); }, 4000); // 完整显示时间 } } // 波动动画函数 function startWaveAnimation() { // 清除之前的间隔 if (waveInterval) clearInterval(waveInterval); // 启动波动动画 waveInterval = setInterval(() => { // 获取所有字符 const chars = waveContainer.querySelectorAll('.bounce-text'); if (chars.length === 0) return; // 移动波峰位置 peakPosition = (peakPosition + 1) % chars.length; // 应用变换 chars.forEach((char, index) => { if (index === peakPosition) { // 波峰位置 char.style.transform = 'translateY(-8px)'; } else if (Math.abs(index - peakPosition) === 1) { // 波峰旁边的字符稍微上移 char.style.transform = 'translateY(-4px)'; } else { // 其他字符回到原位 char.style.transform = 'translateY(0)'; } }); }, 100); // 每100ms更新一次波峰位置 } // 开始打字机效果 typeLoadingText(); // 存储文本到 sessionStorage sessionStorage.setItem('uploadedText', text); console.log(text) // 获取上传的图片数据 const uploadedImage = sessionStorage.getItem('uploadedImage'); // 分析反馈内容,生成解读结果 analyzeUserInput(text, uploadedImage).then(() => { // 解读完成后跳转到反馈页面 window.location.href = 'feedback.html'; }).catch(error => { console.error('解读失败:', error); alert('解读失败,请重试'); resolveButton.disabled = false; resolveButton.textContent = '一键解读'; }); }); } // 分析用户输入和图片的函数 async function analyzeUserInput(text, imageData) { try { const health = await fetch(`${BASE_URL}health`) console.log(health) const response = await fetch(`${BASE_URL}api/analyze`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: text, image_data: imageData, request_model_id: 'gpt-4.1-mini' }) }); console.log(response) const data = await response.json(); console.log(data) const rep = data['output'][0]['content'][0]['text']; sessionStorage.setItem('analysisResult', rep); } catch (error) { console.error('分析失败:', error); // 使用默认的分析结果 const defaultAnalysis = `情绪值:😠😠😠\n\n情绪分析:需求方目前很不满,需要大幅改正。 修改建议: 1. 色彩调整:在保持整体色调的基础上,加入一些明亮的点缀色,如淡黄色、淡紫蓝、淡红蓝微粉等。用于按钮、图标或重要文本,以增加吸引力。 2. 增加层级感:利用饱和度(Glassmorphism)效果,为卡片/重要框添加模糊背景和阴影,营造出浮起感,引入3D元素或深浅变化,增加页面的深度和空间感。 3. 增加互动性:为按钮和图标添加悬停动画或点击动画,提供用户及时反馈。引入微动画(Micro-interactions),如加载动画、切换动画等等,使页面更具活力。`; sessionStorage.setItem('analysisResult', defaultAnalysis); } } // 示例图片添加到参考案例 const exampleCards = document.querySelectorAll('.example-card'); if (exampleCards.length > 0) { // 为示例卡片添加示例图片背景 const exampleBgs = [ 'linear-gradient(45deg, #2d2d4e, #1e1e30)', 'linear-gradient(45deg, #2e2e2e, #1a1a1a)', 'linear-gradient(45deg, #332e42, #1f1b30)' ]; exampleCards.forEach((card, index) => { card.style.background = exampleBgs[index % exampleBgs.length]; }); } // 加载并显示反馈页面的分析结果 function loadAnalysisResult() { const analysisResult = sessionStorage.getItem('analysisResult'); console.log(analysisResult) if (!analysisResult) return; try { // 设置情绪值 if (analysisResult) { const emotionIcons = document.querySelector('.emotion-icons'); const emotionText = document.querySelector('.emotion-text'); if (emotionIcons && emotionText) { // 清空图标区域 emotionIcons.innerHTML = ''; // 提取情绪值部分 const emojiText = analysisResult.split('情绪值:')[1].split('\n')[0]; const emotionAnalyse = analysisResult.split('情绪分析:')[1].split('\n')[0]; // 提取emoji const emojis = [emojiText.codePointAt(0), emojiText.codePointAt(2), emojiText.codePointAt(4)]; console.log(emojis) emojis.forEach(emoji => { console.log(emoji) }) if (emojis) { // 只显示3个emoji,确保一致性 const displayEmojis = emojis.slice(0, 3); displayEmojis.forEach(emoji => { const span = document.createElement('span'); span.className = 'emoji'; span.textContent = String.fromCodePoint(emoji); emotionIcons.appendChild(span); }); } else { // 默认情绪 for (let i = 0; i < 3; i++) { const span = document.createElement('span'); span.className = 'emoji'; span.textContent = '😠'; emotionIcons.appendChild(span); } } // 设置文字描述 // 查找"情绪分析:"部分 let textDescription = ''; if (emotionAnalyse) { textDescription = emotionAnalyse.trim(); } else { // 如果没有情绪分析部分,根据emoji生成默认文本 if (emojis && emojis[0] === '😠') { textDescription = '需求方对设计非常不满意,建议全面改进'; } else if (emojis && emojis[0] === '🙁') { textDescription = '需求方对设计不太满意,需要较多改进'; } else if (emojis && emojis[0] === '😐') { textDescription = '需求方对设计感觉一般,有改进空间'; } else if (emojis && emojis[0] === '🙂') { textDescription = '需求方对设计比较满意,小幅改进即可'; } else if (emojis && emojis[0] === '😊') { textDescription = '需求方对设计非常满意,细节优化即可'; } else { textDescription = '需要基于反馈进行改进'; } } emotionText.textContent = textDescription; } } // 提取修改建议 const suggestionsContainer = document.querySelector('.suggestions-container'); if (suggestionsContainer) { try { // 使用split提取修改建议部分 const suggestionsText = analysisResult.split('修改建议:')[1].split('搜索内容:')[0]; sessionStorage.setItem('suggestionsText', suggestionsText) if (suggestionsText) { // 提取三个建议 const suggestionLines = suggestionsText.trim().split('\n\n'); const suggestions = []; // 处理每一行建议 for (let i = 0; i < suggestionLines.length; i++) { const line = suggestionLines[i].trim(); if (line.match(/^\d+\.\s/)) { // 找到了序号开头的行,这是建议的标题和内容 const suggestionText = line.replace(/^\d+\.\s/, ''); // 拆分标题和内容(假设冒号或:分隔) let title = suggestionText; let content = ''; if (suggestionText.includes(':')) { [title, content] = suggestionText.split(':', 2); } else if (suggestionText.includes(':')) { [title, content] = suggestionText.split(':', 2); } suggestions.push({ title: title.trim(), content: content.trim() }); // 最多收集三个建议 if (suggestions.length >= 3) break; } } // 更新建议卡片 if (suggestions.length > 0) { const cardStyles = ['yellow-top', 'cyan-top', 'purple-top']; suggestionsContainer.innerHTML = ''; suggestions.forEach((suggestion, index) => { const cardStyle = cardStyles[index % cardStyles.length]; const card = document.createElement('div'); card.className = `suggestion-card ${cardStyle}`; const titleElement = document.createElement('h3'); titleElement.className = 'suggestion-title'; titleElement.textContent = suggestion.title; const textElement = document.createElement('p'); textElement.className = 'suggestion-text'; textElement.textContent = suggestion.content; card.appendChild(titleElement); card.appendChild(textElement); suggestionsContainer.appendChild(card); }); // 加载参考案例 loadReferenceExamples(suggestions); } } } catch (error) { console.error('解析建议失败:', error); } } } catch (error) { console.error('解析分析结果失败:', error); } } // 根据建议加载参考案例 async function loadReferenceExamples(suggestions) { const analysisResult = sessionStorage.getItem('analysisResult'); const searchContent = analysisResult.split('搜索内容:')[1].trim(); const examplesContainer = document.querySelector('.examples-container'); if (!examplesContainer) return; // 获取现有的示例卡片元素 const exampleCards = examplesContainer.querySelectorAll('.example-card'); if (exampleCards.length !== 2) { console.error('未找到预期的两个示例卡片元素'); return; } try { // 显示加载状态 exampleCards.forEach(card => { const img = card.querySelector('.example-image'); const desc = card.querySelector('.example-desc'); const sourceLink = card.querySelector('.example-source a'); if (img) { img.style.display = 'none'; } if (desc) { desc.innerHTML = `
正在搜索设计参考案例...
`; } if (sourceLink) { sourceLink.href = '#'; sourceLink.textContent = '加载中...'; } }); // 获取原始反馈文本和上传的图片 const suggestionsText = sessionStorage.getItem('suggestionsText') || ''; // 调用后端搜索API const response = await fetch(`${BASE_URL}api/search`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ query: searchContent, num_results: 2 }) }); if (!response.ok) { throw new Error('搜索请求失败'); } const searchData = await response.json(); if (!searchData.items || searchData.items.length === 0) { throw new Error('未找到搜索结果'); } // 处理搜索结果 const examples = searchData.items.map(result => ({ title: result.title, sourceUrl: result.link, description: result.snippet || '', image: result.image || '' })); // 使用GPT生成描述 for (let i = 0; i < examples.length; i++) { const example = examples[i]; try { const response = await fetch(`${BASE_URL}api/analyze-case-study`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ user_input: `请分析这个设计案例:${example.title}\n${example.description}\n修改建议:${suggestionsText}\n基于原始设计反馈和修改建议,详细分析为什么这个设计案例可以解决用户面临的设计问题。描述要专业、具体,并关注设计细节。你只需要简单介绍案例内容和特点,然后简要分析即可,不要输出其他内容。`, request_model_id: 'gpt-4.1-mini' }) }); if (response.ok) { const data = await response.json(); if (data.output && data.output[0].content[0].text) { example.description = data.output[0].content[0].text.trim(); } } } catch (gptError) { console.error('生成案例描述失败:', gptError); // 使用默认描述 example.description = i === 0 ? '这个案例展示了清晰的视觉层次结构和吸引人的色彩搭配,能有效解决原设计中的平面感问题。通过对比度增强和微妙的动效,它能提高用户体验和互动性,同时保持整体设计的专业性。' : '该设计运用了精细的色彩渐变和现代化的UI元素,完美解决了原始设计中的视觉单调问题。透过精心安排的布局和适当的留白,创造出流畅的用户浏览体验,同时增加了设计的精致感和专业度。'; } } // 更新UI examples.forEach((example, index) => { const card = exampleCards[index]; if (!card) return; const img = card.querySelector('.example-image'); const desc = card.querySelector('.example-desc'); const source = card.querySelector('.example-source'); if (img) { img.style.display = 'block'; img.src = example.image; img.alt = example.title; } if (desc) { desc.innerHTML = example.description; } if (source) { const sourceLink = source.querySelector('a'); if (sourceLink) { sourceLink.href = example.sourceUrl; sourceLink.textContent = example.title; } } }); } catch (error) { console.error('加载参考案例失败:', error); // 在错误情况下更新UI exampleCards.forEach(card => { const desc = card.querySelector('.example-desc'); if (desc) { desc.textContent = '加载参考案例失败,请刷新重试'; desc.style.color = '#ff6b6b'; } }); } } // 当在反馈页面时,加载分析结果 if (window.location.pathname.includes('feedback.html')) { loadAnalysisResult(); // 优化方案功能 setupOptimizationButtons(); } // 设置优化方案按钮功能 function setupOptimizationButtons() { const gpt4Button = document.getElementById('gpt4-btn'); const mjButton = document.getElementById('mj-btn'); if (gpt4Button) { gpt4Button.addEventListener('click', function() { generateGPT4Optimization(); }); } if (mjButton) { mjButton.addEventListener('click', function() { generateDalleOptimization(); }); } } // 使用GPT-4生成优化方案 async function generateGPT4Optimization() { const gpt4Button = document.getElementById('gpt4-btn'); const gpt4Content = document.getElementById('gpt4-content'); if (!gpt4Button || !gpt4Content) return; try { // 禁用按钮 gpt4Button.disabled = true; gpt4Button.textContent = '生成中...'; // 显示加载动画 showLoadingState(gpt4Content, '正在生成优化方案,请稍候...'); // 获取原始反馈和图片 const uploadedText = sessionStorage.getItem('uploadedText') || ''; const uploadedImage = sessionStorage.getItem('uploadedImage'); const analysisResult = sessionStorage.getItem('analysisResult') || ''; if (!uploadedImage) { throw new Error('未找到原始设计图片'); } // 提取修改建议 let suggestions = []; if (analysisResult.includes('修改建议:')) { const suggestionsText = analysisResult.split('修改建议:')[1].split('搜索内容:')[0]; suggestions = suggestionsText .split('\n') .filter(line => line.match(/^\d+\./)) .map(line => line.replace(/^\d+\.\s+/, '').trim()); } // 调用后端API const response = await fetch(`${BASE_URL}api/optimize-design`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: uploadedText, image_data: uploadedImage, suggestions: suggestions, request_model_id: 'gpt-image-1', openai_key: sessionStorage.getItem('userOpenaiKey') || '', user_key: sessionStorage.getItem('userKey') || '' }) }); if (!response.ok) { throw new Error('优化请求失败'); } const data = await response.json(); if (data.data && data.data[0] && data.data[0].url) { // 展示生成的图片 showOptimizationResult(gpt4Content, data.data[0].url); gpt4Button.disabled = false; gpt4Button.textContent = '重新生成'; } else { throw new Error('API未返回图片数据'); } } catch (error) { console.error('生成优化方案失败:', error); gpt4Content.innerHTML = `

生成失败: ${error.message || '请稍后重试'}

`; gpt4Button.disabled = false; gpt4Button.textContent = '重试'; } } async function generateDalleOptimization() { const mjButton = document.getElementById('mj-btn'); const mjContent = document.getElementById('mj-content'); if (!mjButton || !mjContent) return; try { mjButton.disabled = true; mjButton.textContent = '生成中...'; showLoadingState(mjContent, '正在优化设计,请稍候...'); // 获取原始反馈和建议 const analysisResult = sessionStorage.getItem('analysisResult') || ''; let suggestions = []; if (analysisResult.includes('修改建议:')) { const suggestionsText = analysisResult.split('修改建议:')[1].split('搜索内容:')[0]; suggestions = suggestionsText .split('\n') .filter(line => line.match(/^\d+\./)) .map(line => line.replace(/^\d+\.\s+/, '').trim()); } // 获取原始图片 const uploadedImage = sessionStorage.getItem('uploadedImage'); if (!uploadedImage) { throw new Error('未找到原始设计图片'); } // 构建提示词 const uploadedText = sessionStorage.getItem('uploadedText') || ''; // 调用后端API const response = await fetch(`${BASE_URL}api/optimize-design`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text: uploadedText, image_data: uploadedImage, suggestions: suggestions, request_model_id: 'dall-e-2', openai_key: sessionStorage.getItem('userOpenaiKey') || '', user_key: sessionStorage.getItem('userKey') || '' }) }); if (response.status === 503) { const errData = await response.json(); alert(errData.detail) throw new Error('用户无生图权限') } const data = await response.json(); if (data.data && data.data[0] && data.data[0].url) { // 展示生成的图片 showOptimizationResult(mjContent, data.data[0].url); mjButton.disabled = false; mjButton.textContent = '重新生成'; } else { throw new Error('API未返回图片数据'); } } catch (error) { console.error('生成优化方案失败:', error); mjContent.innerHTML = `

生成失败: ${error.message || '请稍后重试'}

`; mjButton.disabled = false; mjButton.textContent = '重试'; } } // 显示加载状态 function showLoadingState(container, message) { container.innerHTML = `
${message}

生成中,请稍候...

`; } // 显示优化结果 function showOptimizationResult(container, imageUrl) { container.innerHTML = `
优化方案
`; } // 润色功能 const generateBtn = document.getElementById('generateBtn'); if (generateBtn) { generateBtn.addEventListener('click', function() { const userInput = document.getElementById('userInput').value.trim(); if (!userInput) { alert('请输入需要润色的内容'); return; } // 显示Toast提示 const toast = document.getElementById('toast'); toast.style.display = 'block'; // 调用OpenAI API callOptimizeText(userInput); }); } // OpenAI API调用函数 async function callOptimizeText(inputText) { try { // 获取原始反馈文本 const originalFeedback = sessionStorage.getItem('uploadedText') || ''; const response = await fetch(`${BASE_URL}api/optimize-text`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ original_feedback: originalFeedback, user_input: inputText, request_model_id: 'gpt-4.1-mini' }) }); if (!response.ok) { throw new Error('文本优化请求失败'); } const data = await response.json(); // 隐藏Toast const toast = document.getElementById('toast'); toast.style.display = 'none'; if (data.output && data.output[0].content[0].text.length > 0) { // 显示API返回的结果 const optimizedText = data['output'][0]['content'][0]['text']; const resultContent = document.getElementById('resultContent'); const resultCard = document.getElementById('resultCard'); resultContent.innerText = optimizedText; resultCard.style.display = 'block'; // 平滑滚动到结果区域 resultCard.scrollIntoView({ behavior: 'smooth' }); } else { handleAPIError('未获取到有效响应'); } } catch (error) { handleAPIError(error); } } // 处理API错误 function handleAPIError(error) { console.error('API调用失败:', error); // 隐藏Toast const toast = document.getElementById('toast'); toast.style.display = 'none'; // 显示错误信息,同时提供备选方案 const resultContent = document.getElementById('resultContent'); const resultCard = document.getElementById('resultCard'); // 备选文案,当API调用失败时使用 const userInput = document.getElementById('userInput').value.trim(); let fallbackText = ''; if (userInput.includes('不行') || userInput.includes('不能')) { fallbackText = '感谢您的建议,我们团队已经考虑过这个方案,但受到一些技术限制,暂时无法实现。我们已经记录下您的想法,并会在后续版本中尝试优化解决。'; } else if (userInput.includes('丑') || userInput.includes('难看')) { fallbackText = '非常感谢您的审美建议!我们设计团队正在不断优化视觉体验,您提出的这些意见非常有价值,我们会在下一版本中优先考虑调整。'; } else { fallbackText = '您的意见我们已经记录,团队会认真研究并在后续迭代中考虑采纳。感谢您的宝贵反馈,这对我们产品的完善非常重要!'; } resultContent.innerText = fallbackText; resultCard.style.display = 'block'; // 平滑滚动到结果区域 resultCard.scrollIntoView({ behavior: 'smooth' }); } // 添加图片转base64函数 async function convertImageToBase64(imageUrl) { try { const response = await fetch(imageUrl); const blob = await response.blob(); return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => { // 返回完整的Data URL resolve(reader.result); }; reader.onerror = reject; reader.readAsDataURL(blob); }); } catch (error) { console.error('转换图片为base64失败:', error); return imageUrl; // 如果失败,返回原始URL } } // API Key Dialog functionality const apiKeyLink = document.getElementById('apiKeyLink'); const apiKeyDialog = document.getElementById('apiKeyDialog'); const apiKeyInput = document.getElementById('apiKeyInput'); const saveApiKey = document.getElementById('saveApiKey'); const cancelApiKey = document.getElementById('cancelApiKey'); if (apiKeyLink && apiKeyDialog) { // Show dialog when clicking the link apiKeyLink.addEventListener('click', function(e) { e.preventDefault(); apiKeyDialog.style.display = 'flex'; // Load existing key if available const existingKey = sessionStorage.getItem('userOpenaiKey'); if (existingKey) { apiKeyInput.value = existingKey; } }); // Save API Key saveApiKey.addEventListener('click', function() { const key = apiKeyInput.value.trim(); if (key) { sessionStorage.setItem('userOpenaiKey', key); apiKeyDialog.style.display = 'none'; // Show success message const toast = document.getElementById('toast'); toast.textContent = 'API Key已保存'; toast.style.display = 'block'; setTimeout(() => { toast.style.display = 'none'; }, 2000); } }); // Cancel button cancelApiKey.addEventListener('click', function() { apiKeyDialog.style.display = 'none'; }); // Close dialog when clicking outside apiKeyDialog.addEventListener('click', function(e) { if (e.target === apiKeyDialog) { apiKeyDialog.style.display = 'none'; } }); } // User Key Dialog functionality const userKeyLink = document.getElementById('userKeyLink'); const userKeyDialog = document.getElementById('userKeyDialog'); const userKeyInput = document.getElementById('userKeyInput'); const saveUserKey = document.getElementById('saveUserKey'); const cancelUserKey = document.getElementById('cancelUserKey'); if (userKeyLink && userKeyDialog) { // Show dialog when clicking the link userKeyLink.addEventListener('click', function(e) { e.preventDefault(); userKeyDialog.style.display = 'flex'; // Load existing key if available const existingKey = sessionStorage.getItem('userKey'); if (existingKey) { userKeyInput.value = existingKey; } }); // Save User Key saveUserKey.addEventListener('click', function() { const key = userKeyInput.value.trim(); if (key) { sessionStorage.setItem('userKey', key); userKeyDialog.style.display = 'none'; // Show success message const toast = document.getElementById('toast'); toast.textContent = '用户密钥已保存'; toast.style.display = 'block'; setTimeout(() => { toast.style.display = 'none'; }, 2000); } }); // Cancel button cancelUserKey.addEventListener('click', function() { userKeyDialog.style.display = 'none'; }); // Close dialog when clicking outside userKeyDialog.addEventListener('click', function(e) { if (e.target === userKeyDialog) { userKeyDialog.style.display = 'none'; } }); } });