diff --git a/server.py b/server.py index 0d2a954..258eb42 100644 --- a/server.py +++ b/server.py @@ -186,7 +186,39 @@ def create_feedback_text(feedback_data: dict) -> str: size_mb = size / (1024 * 1024) size_str = f"{size_mb:.1f} MB" - text_parts.append(f" {i}. {name} ({size_str})") + img_info = f" {i}. {name} ({size_str})" + + # 為提高兼容性,添加 base64 預覽信息 + if img.get("data"): + try: + if isinstance(img["data"], bytes): + img_base64 = base64.b64encode(img["data"]).decode('utf-8') + elif isinstance(img["data"], str): + img_base64 = img["data"] + else: + img_base64 = None + + if img_base64: + # 只顯示前50個字符的預覽 + preview = img_base64[:50] + "..." if len(img_base64) > 50 else img_base64 + img_info += f"\n Base64 預覽: {preview}" + img_info += f"\n 完整 Base64 長度: {len(img_base64)} 字符" + + # 如果 AI 助手不支援 MCP 圖片,可以提供完整 base64 + debug_log(f"圖片 {i} Base64 已準備,長度: {len(img_base64)}") + + # 可選:根據環境變數決定是否包含完整 base64 + include_full_base64 = os.getenv("INCLUDE_BASE64_DETAIL", "").lower() in ("true", "1", "yes", "on") + if include_full_base64: + img_info += f"\n 完整 Base64: data:image/png;base64,{img_base64}" + + except Exception as e: + debug_log(f"圖片 {i} Base64 處理失敗: {e}") + + text_parts.append(img_info) + + # 添加兼容性說明 + text_parts.append("\n💡 注意:如果 AI 助手無法顯示圖片,圖片數據已包含在上述 Base64 信息中。") return "\n\n".join(text_parts) if text_parts else "用戶未提供任何回饋內容。" diff --git a/templates/feedback.html b/templates/feedback.html index a3fc22c..8b32bed 100644 --- a/templates/feedback.html +++ b/templates/feedback.html @@ -628,22 +628,22 @@ } } } - alert('剪貼板中沒有圖片!'); + showNotification('剪貼板中沒有圖片!'); } catch (error) { console.error('剪貼板讀取失敗:', error); - alert('無法從剪貼板讀取圖片'); + showNotification('無法從剪貼板讀取圖片'); } } function processFiles(files) { for (const file of files) { if (!file.type.startsWith('image/')) { - alert(`檔案 ${file.name} 不是圖片格式!`); + showNotification(`檔案 ${file.name} 不是圖片格式!`, 'warning'); continue; } if (file.size > 1024 * 1024) { // 1MB 限制 - alert(`圖片 ${file.name} 大小超過 1MB 限制!`); + showNotification(`圖片 ${file.name} 大小超過 1MB 限制!`, 'warning'); continue; } @@ -757,7 +757,7 @@ if (!command) return; if (commandRunning) { - alert('已有命令在執行中,請等待完成或停止當前命令'); + showNotification('已有命令在執行中,請等待完成或停止當前命令', 'warning'); return; } @@ -785,24 +785,63 @@ const feedback = document.getElementById('feedbackText').value.trim(); if (!feedback && images.length === 0) { - alert('請輸入回饋內容或上傳圖片!'); + showNotification('請輸入回饋內容或上傳圖片!', 'warning'); return; } if (ws && ws.readyState === WebSocket.OPEN) { + // 顯示提交中狀態 + const submitBtn = document.querySelector('.submit-btn'); + const originalText = submitBtn.textContent; + submitBtn.textContent = '提交中...'; + submitBtn.disabled = true; + ws.send(JSON.stringify({ type: 'submit_feedback', feedback: feedback, images: images })); - alert('回饋已提交!感謝您的回饋。'); - window.close(); + // 簡短延遲後自動關閉,不顯示 alert + setTimeout(() => { + window.close(); + }, 500); } else { - alert('WebSocket 連接異常,請重新整理頁面'); + showNotification('WebSocket 連接異常,請重新整理頁面', 'error'); } } + // 添加通知函數,替代 alert + function showNotification(message, type = 'info') { + // 創建通知元素 + const notification = document.createElement('div'); + notification.className = `notification ${type}`; + notification.textContent = message; + notification.style.cssText = ` + position: fixed; + top: 20px; + right: 20px; + background: ${type === 'error' ? '#dc3545' : type === 'warning' ? '#ffc107' : '#007acc'}; + color: white; + padding: 12px 20px; + border-radius: 6px; + box-shadow: 0 4px 12px rgba(0,0,0,0.3); + z-index: 10000; + font-weight: bold; + max-width: 300px; + word-wrap: break-word; + `; + + document.body.appendChild(notification); + + // 3 秒後自動移除 + setTimeout(() => { + if (notification.parentNode) { + notification.parentNode.removeChild(notification); + } + }, 3000); + } + function cancelFeedback() { if (confirm('確定要取消回饋嗎?')) { window.close();