From 0f56c7c5fbb1c48aa9cb0149a440d9feb55fc9bc Mon Sep 17 00:00:00 2001 From: Minidoracat Date: Mon, 2 Jun 2025 13:13:08 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E5=B0=87=20gui=20=E5=92=8C=20webui?= =?UTF-8?q?=20=E7=9A=84=E5=B0=8D=E8=A9=B1=E6=A1=86=E5=8A=A0=E5=85=A5=20ctr?= =?UTF-8?q?l=20+v=20=E5=B0=B1=E8=83=BD=E8=A4=87=E8=A3=BD=E8=B2=BC=E4=B8=8A?= =?UTF-8?q?=E5=9C=96=E7=89=87=E7=9A=84=E6=9B=B4=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mcp_feedback_enhanced/__main__.py | 4 + src/mcp_feedback_enhanced/feedback_ui.py | 62 +++- src/mcp_feedback_enhanced/i18n.py | 4 + .../locales/en/translations.json | 4 + .../locales/zh-CN/translations.json | 4 + .../locales/zh-TW/translations.json | 6 +- src/mcp_feedback_enhanced/server.py | 21 +- src/mcp_feedback_enhanced/static/i18n.js | 184 +----------- .../templates/feedback.html | 283 ++++++++++-------- src/mcp_feedback_enhanced/test_qt_gui.py | 24 +- src/mcp_feedback_enhanced/test_web_ui.py | 60 ++-- src/mcp_feedback_enhanced/web_ui.py | 25 ++ 12 files changed, 331 insertions(+), 350 deletions(-) diff --git a/src/mcp_feedback_enhanced/__main__.py b/src/mcp_feedback_enhanced/__main__.py index 482b3ef..f8d53f4 100644 --- a/src/mcp_feedback_enhanced/__main__.py +++ b/src/mcp_feedback_enhanced/__main__.py @@ -13,6 +13,7 @@ MCP Interactive Feedback Enhanced - 主程式入口 import sys import argparse +import os def main(): """主程式入口點""" @@ -56,6 +57,9 @@ def run_server(): def run_tests(args): """執行測試""" + # 啟用調試模式以顯示測試過程 + os.environ["MCP_DEBUG"] = "true" + if args.web: print("🧪 執行 Web UI 測試...") from .test_web_ui import test_web_ui, interactive_demo diff --git a/src/mcp_feedback_enhanced/feedback_ui.py b/src/mcp_feedback_enhanced/feedback_ui.py index c0d885f..a638d7a 100644 --- a/src/mcp_feedback_enhanced/feedback_ui.py +++ b/src/mcp_feedback_enhanced/feedback_ui.py @@ -745,6 +745,24 @@ class FeedbackWindow(QMainWindow): if hasattr(self, 'summary_title'): self.summary_title.setText(t('ai_summary')) + # 更新摘要內容(如果是測試摘要) + if hasattr(self, 'summary_text'): + # 檢查是否為測試摘要,需要動態翻譯 + if self._is_test_summary(): + # 判斷是哪種測試類型並重新獲取翻譯 + if '圖片預覽' in self.summary or 'Image Preview' in self.summary or '图片预览' in self.summary: + # Qt GUI 測試 + translated_summary = t('test.qtGuiSummary') + elif 'Web UI' in self.summary: + # Web UI 測試 + translated_summary = t('test.webUiSummary') + else: + translated_summary = self.summary + + self.summary_text.setPlainText(translated_summary) + # 更新儲存的摘要以保持一致 + self.summary = translated_summary + # 更新專案目錄標籤 if hasattr(self, 'project_label'): self.project_label.setText(f"{t('project_directory')}: {self.project_dir}") @@ -780,6 +798,38 @@ class FeedbackWindow(QMainWindow): if hasattr(self, 'output_title'): self.output_title.setText(t('command_output')) + def _is_test_summary(self) -> bool: + """檢查是否為測試摘要,使用更嚴格的檢測邏輯""" + # 更嚴格的測試摘要特徵組合檢測 + test_patterns = [ + # Qt GUI 測試特徵 + ('測試 Qt GUI 功能', '🎯 **功能測試項目'), + ('Test Qt GUI Functionality', '🎯 **Test Items'), + ('测试 Qt GUI 功能', '🎯 **功能测试项目'), + + # Web UI 測試特徵 + ('測試 Web UI 功能', '🎯 **功能測試項目'), + ('Test Web UI Functionality', '🎯 **Test Items'), + ('测试 Web UI 功能', '🎯 **功能测试项目'), + + # 具體的測試項目描述 + ('圖片上傳和預覽', '智能 Ctrl+V 圖片貼上'), + ('Image upload and preview', 'Smart Ctrl+V image paste'), + ('图片上传和预览', '智能 Ctrl+V 图片粘贴'), + + # WebSocket 和服務器啟動描述 + ('WebSocket 即時通訊', 'Web UI 服務器啟動'), + ('WebSocket real-time communication', 'Web UI server startup'), + ('WebSocket 即时通讯', 'Web UI 服务器启动') + ] + + # 必須同時包含模式中的兩個特徵才認為是測試摘要 + for pattern1, pattern2 in test_patterns: + if pattern1 in self.summary and pattern2 in self.summary: + return True + + return False + def _update_image_upload_texts(self) -> None: """更新圖片上傳元件的文字""" if hasattr(self, 'image_upload'): @@ -812,12 +862,12 @@ class FeedbackWindow(QMainWindow): summary_layout.addLayout(header_layout) - # 摘要內容(可滾動的文本區域) - summary_text = QTextEdit() - summary_text.setPlainText(self.summary) - summary_text.setReadOnly(True) - summary_text.setMaximumHeight(120) - summary_layout.addWidget(summary_text) + # 摘要內容(可滾動的文本區域)- 儲存為實例變數以支援動態更新 + self.summary_text = QTextEdit() + self.summary_text.setPlainText(self.summary) + self.summary_text.setReadOnly(True) + self.summary_text.setMaximumHeight(120) + summary_layout.addWidget(self.summary_text) layout.addWidget(summary_group) diff --git a/src/mcp_feedback_enhanced/i18n.py b/src/mcp_feedback_enhanced/i18n.py index 1febbc3..9755ee7 100644 --- a/src/mcp_feedback_enhanced/i18n.py +++ b/src/mcp_feedback_enhanced/i18n.py @@ -268,6 +268,10 @@ class I18nManager: 'language_zh_tw': 'languageNames.zhTw', 'language_en': 'languageNames.en', 'language_zh_cn': 'languageNames.zhCn', + + # 測試 + 'test_qt_gui_summary': 'test.qtGuiSummary', + 'test_web_ui_summary': 'test.webUiSummary', } # 檢查是否有對應的新鍵 diff --git a/src/mcp_feedback_enhanced/locales/en/translations.json b/src/mcp_feedback_enhanced/locales/en/translations.json index 357bf3b..8f414da 100644 --- a/src/mcp_feedback_enhanced/locales/en/translations.json +++ b/src/mcp_feedback_enhanced/locales/en/translations.json @@ -82,5 +82,9 @@ "zhTw": "繁體中文", "en": "English", "zhCn": "简体中文" + }, + "test": { + "qtGuiSummary": "🎯 Image Preview and Window Adjustment Test\n\nThis is a test session to verify the following features:\n\n✅ Test Items:\n1. Image upload and preview functionality\n2. Image X delete button in top-right corner\n3. Free window resizing\n4. Flexible splitter adjustment\n5. Dynamic layout of all areas\n6. Smart Ctrl+V image paste functionality\n\n📋 Test Steps:\n1. Try uploading some images (drag & drop, file selection, clipboard)\n2. Check if image preview displays correctly\n3. Click the X button in the top-right corner of images to delete them\n4. Try resizing the window, check if it can be freely adjusted\n5. Drag the splitter to adjust area sizes\n6. Press Ctrl+V in the text box to test smart paste functionality\n7. Provide any feedback or issues found\n\nPlease test these features and provide feedback!", + "webUiSummary": "Test Web UI Functionality\n\n🎯 **Test Items:**\n- Web UI server startup and operation\n- WebSocket real-time communication\n- Feedback submission functionality\n- Image upload and preview\n- Command execution functionality\n- Smart Ctrl+V image paste\n- Multi-language interface switching\n\n📋 **Test Steps:**\n1. Test image upload (drag & drop, file selection, clipboard)\n2. Press Ctrl+V in text box to test smart paste\n3. Try switching languages (Traditional Chinese/Simplified Chinese/English)\n4. Test command execution functionality\n5. Submit feedback and images\n\nPlease test these features and provide feedback!" } } \ No newline at end of file diff --git a/src/mcp_feedback_enhanced/locales/zh-CN/translations.json b/src/mcp_feedback_enhanced/locales/zh-CN/translations.json index 41d4934..b8159dc 100644 --- a/src/mcp_feedback_enhanced/locales/zh-CN/translations.json +++ b/src/mcp_feedback_enhanced/locales/zh-CN/translations.json @@ -82,5 +82,9 @@ "zhTw": "繁體中文", "en": "English", "zhCn": "简体中文" + }, + "test": { + "qtGuiSummary": "🎯 图片预览和窗口调整测试\n\n这是一个测试会话,用于验证以下功能:\n\n✅ 功能测试项目:\n1. 图片上传和预览功能\n2. 图片右上角X删除按钮\n3. 窗口自由调整大小\n4. 分割器的灵活调整\n5. 各区域的动态布局\n6. 智能 Ctrl+V 图片粘贴功能\n\n📋 测试步骤:\n1. 尝试上传一些图片(拖拽、文件选择、剪贴板)\n2. 检查图片预览是否正常显示\n3. 点击图片右上角的X按钮删除图片\n4. 尝试调整窗口大小,检查是否可以自由调整\n5. 拖动分割器调整各区域大小\n6. 在文本框内按 Ctrl+V 测试智能粘贴功能\n7. 提供任何回馈或发现的问题\n\n请测试这些功能并提供回馈!", + "webUiSummary": "测试 Web UI 功能\n\n🎯 **功能测试项目:**\n- Web UI 服务器启动和运行\n- WebSocket 即时通讯\n- 回馈提交功能\n- 图片上传和预览\n- 命令执行功能\n- 智能 Ctrl+V 图片粘贴\n- 多语言界面切换\n\n📋 **测试步骤:**\n1. 测试图片上传(拖拽、选择文件、剪贴板)\n2. 在文本框内按 Ctrl+V 测试智能粘贴\n3. 尝试切换语言(繁中/简中/英文)\n4. 测试命令执行功能\n5. 提交回馈和图片\n\n请测试这些功能并提供回馈!" } } \ No newline at end of file diff --git a/src/mcp_feedback_enhanced/locales/zh-TW/translations.json b/src/mcp_feedback_enhanced/locales/zh-TW/translations.json index ba69ad0..9ddd8dc 100644 --- a/src/mcp_feedback_enhanced/locales/zh-TW/translations.json +++ b/src/mcp_feedback_enhanced/locales/zh-TW/translations.json @@ -77,10 +77,14 @@ "fileTooLarge": "文件過大(最大 1MB)" }, "aiSummary": "AI 工作摘要", - "languageSelector": "🌐 語言", + "languageSelector": "🌐 語言選擇", "languageNames": { "zhTw": "繁體中文", "en": "English", "zhCn": "简体中文" + }, + "test": { + "qtGuiSummary": "🎯 圖片預覽和視窗調整測試\n\n這是一個測試會話,用於驗證以下功能:\n\n✅ 功能測試項目:\n1. 圖片上傳和預覽功能\n2. 圖片右上角X刪除按鈕\n3. 視窗自由調整大小\n4. 分割器的靈活調整\n5. 各區域的動態佈局\n6. 智能 Ctrl+V 圖片貼上功能\n\n📋 測試步驟:\n1. 嘗試上傳一些圖片(拖拽、文件選擇、剪貼板)\n2. 檢查圖片預覽是否正常顯示\n3. 點擊圖片右上角的X按鈕刪除圖片\n4. 嘗試調整視窗大小,檢查是否可以自由調整\n5. 拖動分割器調整各區域大小\n6. 在文字框內按 Ctrl+V 測試智能貼上功能\n7. 提供任何回饋或發現的問題\n\n請測試這些功能並提供回饋!", + "webUiSummary": "測試 Web UI 功能\n\n🎯 **功能測試項目:**\n- Web UI 服務器啟動和運行\n- WebSocket 即時通訊\n- 回饋提交功能\n- 圖片上傳和預覽\n- 命令執行功能\n- 智能 Ctrl+V 圖片貼上\n- 多語言介面切換\n\n📋 **測試步驟:**\n1. 測試圖片上傳(拖拽、選擇檔案、剪貼簿)\n2. 在文字框內按 Ctrl+V 測試智能貼上\n3. 嘗試切換語言(繁中/簡中/英文)\n4. 測試命令執行功能\n5. 提交回饋和圖片\n\n請測試這些功能並提供回饋!" } } \ No newline at end of file diff --git a/src/mcp_feedback_enhanced/server.py b/src/mcp_feedback_enhanced/server.py index 0df2673..b3d83c8 100644 --- a/src/mcp_feedback_enhanced/server.py +++ b/src/mcp_feedback_enhanced/server.py @@ -373,8 +373,7 @@ def launch_gui(project_dir: str, summary: str) -> dict: async def interactive_feedback( project_directory: Annotated[str, Field(description="專案目錄路徑")] = ".", summary: Annotated[str, Field(description="AI 工作完成的摘要說明")] = "我已完成了您請求的任務。", - timeout: Annotated[int, Field(description="等待用戶回饋的超時時間(秒)")] = 600, - force_web_ui: Annotated[bool, Field(description="強制使用 Web UI(用於測試或特殊需求)")] = False + timeout: Annotated[int, Field(description="等待用戶回饋的超時時間(秒)")] = 600 ) -> List: """ 收集用戶的互動回饋,支援文字和圖片 @@ -382,7 +381,7 @@ async def interactive_feedback( 此工具會自動偵測運行環境: - 遠端環境:使用 Web UI - 本地環境:使用 Qt GUI - - 可透過 force_web_ui 參數或 FORCE_WEB 環境變數強制使用 Web UI + - 可透過 FORCE_WEB 環境變數強制使用 Web UI 用戶可以: 1. 執行命令來驗證結果 @@ -390,6 +389,10 @@ async def interactive_feedback( 3. 上傳圖片作為回饋 4. 查看 AI 的工作摘要 + 介面控制(按優先級排序): + 1. **FORCE_WEB 環境變數**:在 mcp.json 中設置 "FORCE_WEB": "true" + 2. 自動檢測:根據運行環境自動選擇 + 調試模式: - 設置環境變數 MCP_DEBUG=true 可啟用詳細調試輸出 - 生產環境建議關閉調試模式以避免輸出干擾 @@ -398,26 +401,26 @@ async def interactive_feedback( project_directory: 專案目錄路徑 summary: AI 工作完成的摘要說明 timeout: 等待用戶回饋的超時時間(秒),預設為 600 秒(10 分鐘) - force_web_ui: 強制使用 Web UI,即使在本地環境也使用 Web UI(用於測試) Returns: List: 包含 TextContent 和 MCPImage 對象的列表 """ - # 檢查環境變數,如果設定了 FORCE_WEB 就覆蓋 force_web_ui 參數 + # 檢查環境變數 FORCE_WEB + force_web = False env_force_web = os.getenv("FORCE_WEB", "").lower() if env_force_web in ("true", "1", "yes", "on"): - force_web_ui = True + force_web = True debug_log("環境變數 FORCE_WEB 已啟用,強制使用 Web UI") elif env_force_web in ("false", "0", "no", "off"): - force_web_ui = False + force_web = False debug_log("環境變數 FORCE_WEB 已停用,使用預設邏輯") # 環境偵測 is_remote = is_remote_environment() can_gui = can_use_gui() - use_web_ui = is_remote or not can_gui or force_web_ui + use_web_ui = is_remote or not can_gui or force_web - debug_log(f"環境偵測結果 - 遠端: {is_remote}, GUI 可用: {can_gui}, 強制 Web UI: {force_web_ui}") + debug_log(f"環境偵測結果 - 遠端: {is_remote}, GUI 可用: {can_gui}, 強制 Web UI: {force_web}") debug_log(f"決定使用介面: {'Web UI' if use_web_ui else 'Qt GUI'}") try: diff --git a/src/mcp_feedback_enhanced/static/i18n.js b/src/mcp_feedback_enhanced/static/i18n.js index a913792..7c37f62 100644 --- a/src/mcp_feedback_enhanced/static/i18n.js +++ b/src/mcp_feedback_enhanced/static/i18n.js @@ -26,185 +26,27 @@ class I18nManager { } /** - * 獲取內嵌的備用翻譯 + * 獲取內嵌的備用翻譯(僅保留基本錯誤訊息) */ _getEmbeddedTranslations() { return { 'zh-TW': { - app: { - title: 'Interactive Feedback MCP', - projectDirectory: '專案目錄', - language: '語言' - }, - tabs: { - feedback: '💬 回饋', - command: '⚡ 命令' - }, - feedback: { - title: '💬 您的回饋', - description: '請在這裡輸入您的回饋、建議或問題。您的意見將幫助 AI 更好地理解您的需求。', - placeholder: '請在這裡輸入您的回饋、建議或問題...\n\n💡 小提示:\n• 按 Ctrl+Enter 可快速提交回饋\n• 按 Ctrl+V 可直接貼上剪貼簿圖片' - }, - command: { - title: '⚡ 命令執行', - description: '您可以在此執行系統命令來驗證結果或獲取更多資訊。', - placeholder: '輸入要執行的命令...', - output: '命令輸出' - }, - images: { - title: '🖼️ 圖片附件(可選)', - status: '已選擇 {count} 張圖片', - statusWithSize: '已選擇 {count} 張圖片 (總計 {size})', - dragHint: '🎯 拖拽圖片到這裡 或 按 Ctrl+V 貼上剪貼簿圖片 (PNG、JPG、JPEG、GIF、BMP、WebP)', - deleteConfirm: '確定要移除圖片 "{filename}" 嗎?', - deleteTitle: '確認刪除' - }, - buttons: { - selectFiles: '📁 選擇文件', - pasteClipboard: '📋 剪貼板', - clearAll: '✕ 清除', - runCommand: '▶️ 執行', - submitFeedback: '✅ 提交回饋', - cancel: '❌ 取消' - }, - status: { - uploading: '上傳中...', - uploadSuccess: '上傳成功', - uploadFailed: '上傳失敗', - commandRunning: '命令執行中...', - commandFinished: '命令執行完成', - pasteSuccess: '已從剪貼板貼上圖片', - pasteFailed: '無法從剪貼板獲取圖片', - paste_no_image: '剪貼簿中沒有圖片可貼上', - paste_image_from_textarea: '已將圖片從文字框智能貼到圖片區域', - invalidFileType: '不支援的文件類型', - fileTooLarge: '文件過大(最大 1MB)' - }, - aiSummary: '📋 AI 工作摘要', - languageSelector: '🌐 語言選擇', - languageNames: { - zhTw: '繁體中文', - en: 'English', - zhCn: '简体中文' - } + app: { title: 'Interactive Feedback MCP' }, + loading: '載入中...', + error: '載入失敗', + retry: '重試' }, - 'en': { - app: { - title: 'Interactive Feedback MCP', - projectDirectory: 'Project Directory', - language: 'Language' - }, - tabs: { - feedback: '💬 Feedback', - command: '⚡ Commands' - }, - feedback: { - title: '💬 Your Feedback', - description: 'Please enter your feedback, suggestions, or questions here. Your input helps AI better understand your needs.', - placeholder: 'Please enter your feedback, suggestions, or questions here...\n\n💡 Tips:\n• Press Ctrl+Enter to submit quickly\n• Press Ctrl+V to paste images from clipboard' - }, - command: { - title: '⚡ Command Execution', - description: 'You can execute system commands here to verify results or get additional information.', - placeholder: 'Enter command to execute...', - output: 'Command Output' - }, - images: { - title: '🖼️ Image Attachments (Optional)', - status: '{count} images selected', - statusWithSize: '{count} images selected (Total {size})', - dragHint: '🎯 Drag images here or press Ctrl+V to paste from clipboard (PNG, JPG, JPEG, GIF, BMP, WebP)', - deleteConfirm: 'Are you sure you want to remove image "{filename}"?', - deleteTitle: 'Confirm Delete' - }, - buttons: { - selectFiles: '📁 Select Files', - pasteClipboard: '📋 Clipboard', - clearAll: '✕ Clear', - runCommand: '▶️ Run', - submitFeedback: '✅ Submit Feedback', - cancel: '❌ Cancel' - }, - status: { - uploading: 'Uploading...', - uploadSuccess: 'Upload successful', - uploadFailed: 'Upload failed', - commandRunning: 'Command running...', - commandFinished: 'Command finished', - pasteSuccess: 'Image pasted from clipboard', - pasteFailed: 'Failed to get image from clipboard', - paste_no_image: 'No image to paste from clipboard', - paste_image_from_textarea: 'Image pasted from text area to image area', - invalidFileType: 'Unsupported file type', - fileTooLarge: 'File too large (max 1MB)' - }, - aiSummary: '📋 AI Work Summary', - languageSelector: '🌐 Language', - languageNames: { - zhTw: '繁體中文', - en: 'English', - zhCn: '简体中文' - } + app: { title: 'Interactive Feedback MCP' }, + loading: 'Loading...', + error: 'Loading failed', + retry: 'Retry' }, - 'zh-CN': { - app: { - title: 'Interactive Feedback MCP', - projectDirectory: '项目目录', - language: '语言' - }, - tabs: { - feedback: '💬 反馈', - command: '⚡ 命令' - }, - feedback: { - title: '💬 您的反馈', - description: '请在这里输入您的反馈、建议或问题。您的意见将帮助 AI 更好地理解您的需求。', - placeholder: '请在这里输入您的反馈、建议或问题...\n\n💡 小提示:\n• 按 Ctrl+Enter 可快速提交反馈\n• 按 Ctrl+V 可直接贴上剪贴板图片' - }, - command: { - title: '⚡ 命令执行', - description: '您可以在此执行系统命令来验证结果或获取更多信息。', - placeholder: '输入要执行的命令...', - output: '命令输出' - }, - images: { - title: '🖼️ 图片附件(可选)', - status: '已选择 {count} 张图片', - statusWithSize: '已选择 {count} 张图片 (总计 {size})', - dragHint: '🎯 拖拽图片到这里 或 按 Ctrl+V 贴上剪贴板图片 (PNG、JPG、JPEG、GIF、BMP、WebP)', - deleteConfirm: '确定要移除图片 "{filename}" 吗?', - deleteTitle: '确认删除' - }, - buttons: { - selectFiles: '📁 选择文件', - pasteClipboard: '📋 剪贴板', - clearAll: '✕ 清除', - runCommand: '▶️ 执行', - submitFeedback: '✅ 提交反馈', - cancel: '❌ 取消' - }, - status: { - uploading: '上传中...', - uploadSuccess: '上传成功', - uploadFailed: '上传失败', - commandRunning: '命令执行中...', - commandFinished: '命令执行完成', - pasteSuccess: '已从剪贴板粘贴图片', - pasteFailed: '无法从剪贴板获取图片', - paste_no_image: '剪贴板中没有图片可粘贴', - paste_image_from_textarea: '已将图片从文字框智能贴到图片区域', - invalidFileType: '不支持的文件类型', - fileTooLarge: '文件过大(最大 1MB)' - }, - aiSummary: '📋 AI 工作摘要', - languageSelector: '🌐 语言选择', - languageNames: { - zhTw: '繁體中文', - en: 'English', - zhCn: '简体中文' - } + app: { title: 'Interactive Feedback MCP' }, + loading: '加载中...', + error: '加载失败', + retry: '重试' } }; } diff --git a/src/mcp_feedback_enhanced/templates/feedback.html b/src/mcp_feedback_enhanced/templates/feedback.html index 0434dc9..4479969 100644 --- a/src/mcp_feedback_enhanced/templates/feedback.html +++ b/src/mcp_feedback_enhanced/templates/feedback.html @@ -1,5 +1,6 @@ + @@ -103,7 +104,8 @@ } } - .feedback-section, .summary-section { + .feedback-section, + .summary-section { background: var(--bg-secondary); border: 1px solid var(--border-color); border-radius: 8px; @@ -180,7 +182,8 @@ color: var(--text-primary); } - .text-input, .command-input { + .text-input, + .command-input { width: 100%; background: var(--bg-tertiary); border: 1px solid var(--border-color); @@ -199,13 +202,15 @@ font-family: 'Consolas', 'Monaco', 'Courier New', monospace; } - .text-input:focus, .command-input:focus { + .text-input:focus, + .command-input:focus { outline: none; border-color: var(--accent-color); box-shadow: 0 0 0 2px rgba(0, 122, 204, 0.2); } - .text-input::placeholder, .command-input::placeholder { + .text-input::placeholder, + .command-input::placeholder { color: var(--text-secondary); } @@ -333,7 +338,7 @@ border-radius: 6px; padding: 15px; background: var(--bg-tertiary); - background-image: + background-image: linear-gradient(90deg, rgba(70, 70, 71, 0.1) 1px, transparent 1px), linear-gradient(rgba(70, 70, 71, 0.1) 1px, transparent 1px); background-size: 120px 120px; @@ -509,11 +514,11 @@ .container { padding: 15px; } - + .header-content { padding: 0 15px; } - + .image-preview-area { grid-template-columns: repeat(auto-fill, minmax(90px, 1fr)); gap: 10px; @@ -553,14 +558,14 @@ flex-direction: column; gap: 15px; } - + .image-preview-area { grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); gap: 8px; padding: 10px; max-height: 300px; } - + .image-preview { height: 80px; } @@ -572,7 +577,7 @@ gap: 15px; padding: 20px; } - + .image-preview { height: 120px; } @@ -602,6 +607,7 @@ } +
@@ -653,11 +659,8 @@
請在這裡輸入您的回饋、建議或問題。您的意見將幫助 AI 更好地理解您的需求。
- +
@@ -665,7 +668,8 @@

🖼️ 圖片附件(可選)

- +
@@ -685,13 +689,8 @@
- +
@@ -716,7 +715,7 @@ - + + \ No newline at end of file diff --git a/src/mcp_feedback_enhanced/test_qt_gui.py b/src/mcp_feedback_enhanced/test_qt_gui.py index 04f8cde..b944d45 100644 --- a/src/mcp_feedback_enhanced/test_qt_gui.py +++ b/src/mcp_feedback_enhanced/test_qt_gui.py @@ -28,6 +28,7 @@ from typing import Optional, Dict, Any sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) from .debug import debug_log +from .i18n import t # 嘗試導入 Qt GUI 模組 try: @@ -42,26 +43,8 @@ def test_qt_gui(): try: # 測試參數 project_directory = os.getcwd() - prompt = """🎯 圖片預覽和視窗調整測試 - -這是一個測試會話,用於驗證以下功能: - -✅ 功能測試項目: -1. 圖片上傳和預覽功能 -2. 圖片右上角X刪除按鈕 -3. 視窗自由調整大小 -4. 分割器的靈活調整 -5. 各區域的動態佈局 - -📋 測試步驟: -1. 嘗試上傳一些圖片(拖拽、文件選擇、剪貼板) -2. 檢查圖片預覽是否正常顯示 -3. 點擊圖片右上角的X按鈕刪除圖片 -4. 嘗試調整視窗大小,檢查是否可以自由調整 -5. 拖動分割器調整各區域大小 -6. 提供任何回饋或發現的問題 - -請測試這些功能並提供回饋!""" + # 使用國際化系統獲取測試摘要 + prompt = t('test.qtGuiSummary') debug_log("🚀 啟動 Qt GUI 測試...") debug_log("📝 測試項目:") @@ -69,6 +52,7 @@ def test_qt_gui(): debug_log(" - X刪除按鈕") debug_log(" - 視窗大小調整") debug_log(" - 分割器調整") + debug_log(" - 智能 Ctrl+V 功能") debug_log("") # 啟動 GUI diff --git a/src/mcp_feedback_enhanced/test_web_ui.py b/src/mcp_feedback_enhanced/test_web_ui.py index ff7718c..a355eb9 100644 --- a/src/mcp_feedback_enhanced/test_web_ui.py +++ b/src/mcp_feedback_enhanced/test_web_ui.py @@ -34,6 +34,7 @@ from typing import Dict, Any, Optional sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) from .debug import debug_log +from .i18n import t # 嘗試導入 Web UI 模組 try: @@ -43,6 +44,10 @@ except ImportError as e: debug_log(f"⚠️ 無法導入 Web UI 模組: {e}") WEB_UI_AVAILABLE = False +def get_test_summary(): + """獲取測試摘要,使用國際化系統""" + return t('test.webUiSummary') + def find_free_port(): """Find a free port to use for testing""" with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: @@ -125,7 +130,8 @@ def test_web_ui(keep_running=False): session_info = None try: project_dir = str(Path.cwd()) - summary = "測試 Web UI 功能" + # 使用國際化系統獲取測試摘要 + summary = t('test.webUiSummary') session_id = manager.create_session(project_dir, summary) session_info = { 'manager': manager, @@ -145,6 +151,7 @@ def test_web_ui(keep_running=False): debug_log(" - 本地環境會繼續使用 Qt GUI") debug_log(" - 支援即時命令執行和 WebSocket 通訊") debug_log(" - 提供現代化的深色主題界面") + debug_log(" - 支援智能 Ctrl+V 圖片貼上功能") return True, session_info @@ -185,8 +192,8 @@ def test_mcp_integration(): # Test timeout parameter debug_log("✅ 支援 timeout 參數") - # Test force_web_ui parameter - debug_log("✅ 支援 force_web_ui 參數") + # Test environment-based Web UI selection + debug_log("✅ 支援基於環境變數的 Web UI 選擇") # Test would require actual MCP call, so just verify import debug_log("✅ 準備接受來自 AI 助手的調用") @@ -197,8 +204,8 @@ def test_mcp_integration(): return False def test_new_parameters(): - """Test new timeout and force_web_ui parameters""" - debug_log("\n🆕 測試新增參數功能") + """Test timeout parameter and environment variable support""" + debug_log("\n🆕 測試參數功能") debug_log("-" * 30) try: @@ -216,45 +223,50 @@ def test_new_parameters(): debug_log("❌ timeout 參數不存在") return False - # 檢查 force_web_ui 參數 - if 'force_web_ui' in sig.parameters: - force_web_ui_param = sig.parameters['force_web_ui'] - debug_log(f"✅ force_web_ui 參數存在,預設值: {force_web_ui_param.default}") + # 檢查環境變數支援 + import os + current_force_web = os.getenv("FORCE_WEB") + if current_force_web: + debug_log(f"✅ 檢測到 FORCE_WEB 環境變數: {current_force_web}") else: - debug_log("❌ force_web_ui 參數不存在") - return False + debug_log("ℹ️ FORCE_WEB 環境變數未設定(將使用預設邏輯)") - debug_log("✅ 所有新參數功能正常") + debug_log("✅ 參數功能正常") return True except Exception as e: - debug_log(f"❌ 新參數測試失敗: {e}") + debug_log(f"❌ 參數測試失敗: {e}") return False -def test_force_web_ui_mode(): - """Test force web UI mode""" - debug_log("\n🌐 測試強制 Web UI 模式") +def test_environment_web_ui_mode(): + """Test environment-based Web UI mode""" + debug_log("\n🌐 測試環境變數控制 Web UI 模式") debug_log("-" * 30) try: from .server import interactive_feedback, is_remote_environment, can_use_gui + import os # 顯示當前環境狀態 is_remote = is_remote_environment() gui_available = can_use_gui() + force_web_env = os.getenv("FORCE_WEB", "").lower() debug_log(f"當前環境 - 遠端: {is_remote}, GUI 可用: {gui_available}") + debug_log(f"FORCE_WEB 環境變數: {force_web_env or '未設定'}") - if not is_remote and gui_available: - debug_log("✅ 在本地 GUI 環境中可以使用 force_web_ui=True 強制使用 Web UI") - debug_log("💡 這對於測試 Web UI 功能非常有用") + if force_web_env in ("true", "1", "yes", "on"): + debug_log("✅ FORCE_WEB 已啟用,將強制使用 Web UI") + elif not is_remote and gui_available: + debug_log("ℹ️ 本地 GUI 環境,將使用 Qt GUI") + debug_log("💡 可設定 FORCE_WEB=true 強制使用 Web UI 進行測試") else: - debug_log("ℹ️ 當前環境會自動使用 Web UI") + debug_log("ℹ️ 將自動使用 Web UI(遠端環境或 GUI 不可用)") return True except Exception as e: - debug_log(f"❌ 強制 Web UI 測試失敗: {e}") + debug_log(f"❌ 環境變數測試失敗: {e}") return False def interactive_demo(session_info): @@ -309,8 +321,8 @@ if __name__ == "__main__": # Test new parameters params_test = test_new_parameters() - # Test force web UI mode - force_test = test_force_web_ui_mode() + # Test environment-based Web UI mode + env_web_test = test_environment_web_ui_mode() # Test MCP integration mcp_test = test_mcp_integration() @@ -319,7 +331,7 @@ if __name__ == "__main__": web_test, session_info = test_web_ui() debug_log("\n" + "=" * 60) - if env_test and params_test and force_test and mcp_test and web_test: + if env_test and params_test and env_web_test and mcp_test and web_test: debug_log("🎊 所有測試完成!準備使用 Interactive Feedback MCP") debug_log("\n📖 使用方法:") debug_log(" 1. 在 Cursor/Cline 中配置此 MCP 服務器") diff --git a/src/mcp_feedback_enhanced/web_ui.py b/src/mcp_feedback_enhanced/web_ui.py index 34c36ca..0e82547 100644 --- a/src/mcp_feedback_enhanced/web_ui.py +++ b/src/mcp_feedback_enhanced/web_ui.py @@ -298,6 +298,31 @@ class WebUIManager: else: return HTMLResponse(self._get_simple_feedback_html(session_id, session)) + @self.app.get("/api/translations") + async def get_translations(): + """提供語系檔案 API""" + try: + translations = {} + locales_dir = package_dir / "locales" + + if locales_dir.exists(): + for lang_dir in locales_dir.iterdir(): + if lang_dir.is_dir(): + lang_code = lang_dir.name + translation_file = lang_dir / "translations.json" + + if translation_file.exists(): + try: + with open(translation_file, 'r', encoding='utf-8') as f: + translations[lang_code] = json.load(f) + except Exception as e: + debug_log(f"載入語言檔案失敗 {lang_code}: {e}") + + return JSONResponse(translations) + except Exception as e: + debug_log(f"語系 API 錯誤: {e}") + return JSONResponse({}, status_code=500) + @self.app.websocket("/ws/{session_id}") async def websocket_endpoint(websocket: WebSocket, session_id: str): """WebSocket 連接處理"""