mirror of
https://github.com/Minidoracat/mcp-feedback-enhanced.git
synced 2025-07-27 10:42:25 +08:00
🐛 修正缺少的打包檔案
This commit is contained in:
parent
608358efc6
commit
4969e37ffe
5
.gitignore
vendored
5
.gitignore
vendored
@ -71,8 +71,9 @@ src-tauri/WixTools/
|
|||||||
src-tauri/gen/
|
src-tauri/gen/
|
||||||
|
|
||||||
# Desktop application binaries (these should be built and copied by build script)
|
# Desktop application binaries (these should be built and copied by build script)
|
||||||
src/mcp_feedback_enhanced/desktop_release/*
|
# Note: desktop_app module should be tracked, only exclude large binaries
|
||||||
src/mcp_feedback_enhanced/desktop_app/
|
src/mcp_feedback_enhanced/desktop_release/*.exe
|
||||||
|
src/mcp_feedback_enhanced/desktop_release/mcp-feedback-enhanced-desktop-*
|
||||||
src/mcp_feedback_enhanced/desktop/mcp-feedback-enhanced-desktop
|
src/mcp_feedback_enhanced/desktop/mcp-feedback-enhanced-desktop
|
||||||
|
|
||||||
|
|
||||||
|
@ -276,7 +276,7 @@ def test_desktop_app():
|
|||||||
print("✅ 找到發佈包中的桌面應用程式模組")
|
print("✅ 找到發佈包中的桌面應用程式模組")
|
||||||
return desktop_func
|
return desktop_func
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
print("🔍 發佈包中未找到桌面應用程式模組,嘗試開發環境...")
|
||||||
|
|
||||||
# 回退到開發環境路徑
|
# 回退到開發環境路徑
|
||||||
tauri_python_path = os.path.join(
|
tauri_python_path = os.path.join(
|
||||||
@ -295,12 +295,17 @@ def test_desktop_app():
|
|||||||
print("❌ 無法從開發環境路徑導入桌面應用程式模組")
|
print("❌ 無法從開發環境路徑導入桌面應用程式模組")
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
print(f"⚠️ Tauri Python 模組路徑不存在: {tauri_python_path}")
|
print(f"⚠️ 開發環境路徑不存在: {tauri_python_path}")
|
||||||
print("💡 請確保已正確建立 PyTauri 專案結構")
|
print("💡 這可能是 PyPI 安裝的版本,桌面應用功能不可用")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
launch_desktop_app_func = import_desktop_app()
|
launch_desktop_app_func = import_desktop_app()
|
||||||
if launch_desktop_app_func is None:
|
if launch_desktop_app_func is None:
|
||||||
|
print("❌ 桌面應用程式不可用")
|
||||||
|
print("💡 可能的原因:")
|
||||||
|
print(" 1. 此版本不包含桌面應用程式二進制檔案")
|
||||||
|
print(" 2. 請使用包含桌面應用的版本,或使用 Web 模式")
|
||||||
|
print(" 3. Web 模式指令:uvx mcp-feedback-enhanced test --web")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
print("✅ 桌面應用程式模組導入成功")
|
print("✅ 桌面應用程式模組導入成功")
|
||||||
|
30
src/mcp_feedback_enhanced/desktop_app/__init__.py
Normal file
30
src/mcp_feedback_enhanced/desktop_app/__init__.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
MCP Feedback Enhanced Desktop Application
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
基於 Tauri 的桌面應用程式包裝器,為 MCP Feedback Enhanced 提供原生桌面體驗。
|
||||||
|
|
||||||
|
主要功能:
|
||||||
|
- 原生桌面應用程式界面
|
||||||
|
- 整合現有的 Web UI 功能
|
||||||
|
- 跨平台支援(Windows、macOS、Linux)
|
||||||
|
- 無需瀏覽器的獨立運行環境
|
||||||
|
|
||||||
|
作者: Minidoracat
|
||||||
|
版本: 2.4.3
|
||||||
|
"""
|
||||||
|
|
||||||
|
__version__ = "2.4.3"
|
||||||
|
__author__ = "Minidoracat"
|
||||||
|
__email__ = "minidora0702@gmail.com"
|
||||||
|
|
||||||
|
from .desktop_app import DesktopApp, launch_desktop_app
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"DesktopApp",
|
||||||
|
"__author__",
|
||||||
|
"__version__",
|
||||||
|
"launch_desktop_app",
|
||||||
|
]
|
337
src/mcp_feedback_enhanced/desktop_app/desktop_app.py
Normal file
337
src/mcp_feedback_enhanced/desktop_app/desktop_app.py
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
桌面應用程式主要模組
|
||||||
|
|
||||||
|
此模組提供桌面應用程式的核心功能,包括:
|
||||||
|
- 桌面模式檢測
|
||||||
|
- Tauri 應用程式啟動
|
||||||
|
- 與現有 Web UI 的整合
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
# 導入現有的 MCP Feedback Enhanced 模組
|
||||||
|
try:
|
||||||
|
from mcp_feedback_enhanced.debug import server_debug_log as debug_log
|
||||||
|
from mcp_feedback_enhanced.web.main import WebUIManager, get_web_ui_manager
|
||||||
|
except ImportError as e:
|
||||||
|
# 在這裡無法使用 debug_log,因為導入失敗
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.stderr.write(f"無法導入 MCP Feedback Enhanced 模組: {e}\n")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
class DesktopApp:
|
||||||
|
"""桌面應用程式管理器"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.web_manager: WebUIManager | None = None
|
||||||
|
self.desktop_mode = False
|
||||||
|
self.app_handle = None
|
||||||
|
|
||||||
|
def set_desktop_mode(self, enabled: bool = True):
|
||||||
|
"""設置桌面模式"""
|
||||||
|
self.desktop_mode = enabled
|
||||||
|
if enabled:
|
||||||
|
# 設置環境變數,防止開啟瀏覽器
|
||||||
|
os.environ["MCP_DESKTOP_MODE"] = "true"
|
||||||
|
debug_log("桌面模式已啟用,將禁止開啟瀏覽器")
|
||||||
|
else:
|
||||||
|
os.environ.pop("MCP_DESKTOP_MODE", None)
|
||||||
|
debug_log("桌面模式已禁用")
|
||||||
|
|
||||||
|
def is_desktop_mode(self) -> bool:
|
||||||
|
"""檢查是否為桌面模式"""
|
||||||
|
return (
|
||||||
|
self.desktop_mode
|
||||||
|
or os.environ.get("MCP_DESKTOP_MODE", "").lower() == "true"
|
||||||
|
)
|
||||||
|
|
||||||
|
async def start_web_backend(self) -> str:
|
||||||
|
"""啟動 Web 後端服務"""
|
||||||
|
debug_log("啟動 Web 後端服務...")
|
||||||
|
|
||||||
|
# 獲取 Web UI 管理器
|
||||||
|
self.web_manager = get_web_ui_manager()
|
||||||
|
|
||||||
|
# 設置桌面模式,禁止自動開啟瀏覽器
|
||||||
|
self.set_desktop_mode(True)
|
||||||
|
|
||||||
|
# 啟動服務器
|
||||||
|
if (
|
||||||
|
self.web_manager.server_thread is None
|
||||||
|
or not self.web_manager.server_thread.is_alive()
|
||||||
|
):
|
||||||
|
self.web_manager.start_server()
|
||||||
|
|
||||||
|
# 等待服務器啟動
|
||||||
|
max_wait = 10 # 最多等待 10 秒
|
||||||
|
wait_count = 0
|
||||||
|
while wait_count < max_wait:
|
||||||
|
if (
|
||||||
|
self.web_manager.server_thread
|
||||||
|
and self.web_manager.server_thread.is_alive()
|
||||||
|
):
|
||||||
|
break
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
wait_count += 0.5
|
||||||
|
|
||||||
|
if not (
|
||||||
|
self.web_manager.server_thread and self.web_manager.server_thread.is_alive()
|
||||||
|
):
|
||||||
|
raise RuntimeError("Web 服務器啟動失敗")
|
||||||
|
|
||||||
|
server_url = self.web_manager.get_server_url()
|
||||||
|
debug_log(f"Web 後端服務已啟動: {server_url}")
|
||||||
|
return server_url
|
||||||
|
|
||||||
|
def create_test_session(self):
|
||||||
|
"""創建測試會話"""
|
||||||
|
if not self.web_manager:
|
||||||
|
raise RuntimeError("Web 管理器未初始化")
|
||||||
|
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
session_id = self.web_manager.create_session(
|
||||||
|
temp_dir, "桌面應用程式測試 - 驗證 Tauri 整合功能"
|
||||||
|
)
|
||||||
|
debug_log(f"測試會話已創建: {session_id}")
|
||||||
|
return session_id
|
||||||
|
|
||||||
|
async def launch_tauri_app(self, server_url: str):
|
||||||
|
"""啟動 Tauri 桌面應用程式"""
|
||||||
|
debug_log("正在啟動 Tauri 桌面視窗...")
|
||||||
|
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# 找到 Tauri 可執行檔案
|
||||||
|
# 首先嘗試從打包後的位置找(PyPI 安裝後的位置)
|
||||||
|
try:
|
||||||
|
from mcp_feedback_enhanced.desktop_release import __file__ as desktop_init
|
||||||
|
|
||||||
|
desktop_dir = Path(desktop_init).parent
|
||||||
|
|
||||||
|
# 根據平台選擇對應的二進制文件
|
||||||
|
import platform
|
||||||
|
|
||||||
|
system = platform.system().lower()
|
||||||
|
machine = platform.machine().lower()
|
||||||
|
|
||||||
|
# 定義平台到二進制文件的映射
|
||||||
|
if system == "windows":
|
||||||
|
tauri_exe = desktop_dir / "mcp-feedback-enhanced-desktop.exe"
|
||||||
|
elif system == "darwin": # macOS
|
||||||
|
# 檢測 Apple Silicon 或 Intel
|
||||||
|
if machine in ["arm64", "aarch64"]:
|
||||||
|
tauri_exe = (
|
||||||
|
desktop_dir / "mcp-feedback-enhanced-desktop-macos-arm64"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
tauri_exe = (
|
||||||
|
desktop_dir / "mcp-feedback-enhanced-desktop-macos-intel"
|
||||||
|
)
|
||||||
|
elif system == "linux":
|
||||||
|
tauri_exe = desktop_dir / "mcp-feedback-enhanced-desktop-linux"
|
||||||
|
else:
|
||||||
|
# 回退到通用名稱
|
||||||
|
tauri_exe = desktop_dir / "mcp-feedback-enhanced-desktop"
|
||||||
|
|
||||||
|
if tauri_exe.exists():
|
||||||
|
debug_log(f"找到打包後的 Tauri 可執行檔案: {tauri_exe}")
|
||||||
|
else:
|
||||||
|
# 嘗試回退選項
|
||||||
|
fallback_files = [
|
||||||
|
desktop_dir / "mcp-feedback-enhanced-desktop.exe",
|
||||||
|
desktop_dir / "mcp-feedback-enhanced-desktop-macos-intel",
|
||||||
|
desktop_dir / "mcp-feedback-enhanced-desktop-macos-arm64",
|
||||||
|
desktop_dir / "mcp-feedback-enhanced-desktop-linux",
|
||||||
|
desktop_dir / "mcp-feedback-enhanced-desktop",
|
||||||
|
]
|
||||||
|
|
||||||
|
for fallback in fallback_files:
|
||||||
|
if fallback.exists():
|
||||||
|
tauri_exe = fallback
|
||||||
|
debug_log(f"使用回退的可執行檔案: {tauri_exe}")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise FileNotFoundError(
|
||||||
|
f"找不到任何可執行檔案,檢查的路徑: {tauri_exe}"
|
||||||
|
)
|
||||||
|
|
||||||
|
except (ImportError, FileNotFoundError):
|
||||||
|
# 回退到開發環境路徑
|
||||||
|
debug_log("未找到打包後的可執行檔案,嘗試開發環境路徑...")
|
||||||
|
project_root = Path(__file__).parent.parent.parent.parent
|
||||||
|
tauri_exe = (
|
||||||
|
project_root
|
||||||
|
/ "src-tauri"
|
||||||
|
/ "target"
|
||||||
|
/ "debug"
|
||||||
|
/ "mcp-feedback-enhanced-desktop.exe"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not tauri_exe.exists():
|
||||||
|
# 嘗試其他可能的路徑
|
||||||
|
tauri_exe = (
|
||||||
|
project_root
|
||||||
|
/ "src-tauri"
|
||||||
|
/ "target"
|
||||||
|
/ "debug"
|
||||||
|
/ "mcp-feedback-enhanced-desktop"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not tauri_exe.exists():
|
||||||
|
# 嘗試 release 版本
|
||||||
|
tauri_exe = (
|
||||||
|
project_root
|
||||||
|
/ "src-tauri"
|
||||||
|
/ "target"
|
||||||
|
/ "release"
|
||||||
|
/ "mcp-feedback-enhanced-desktop.exe"
|
||||||
|
)
|
||||||
|
if not tauri_exe.exists():
|
||||||
|
tauri_exe = (
|
||||||
|
project_root
|
||||||
|
/ "src-tauri"
|
||||||
|
/ "target"
|
||||||
|
/ "release"
|
||||||
|
/ "mcp-feedback-enhanced-desktop"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not tauri_exe.exists():
|
||||||
|
raise FileNotFoundError(
|
||||||
|
"找不到 Tauri 可執行檔案,已嘗試的路徑包括開發和發布目錄"
|
||||||
|
) from None
|
||||||
|
|
||||||
|
debug_log(f"找到 Tauri 可執行檔案: {tauri_exe}")
|
||||||
|
|
||||||
|
# 設置環境變數
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["MCP_DESKTOP_MODE"] = "true"
|
||||||
|
env["MCP_WEB_URL"] = server_url
|
||||||
|
|
||||||
|
# 啟動 Tauri 應用程式
|
||||||
|
try:
|
||||||
|
# Windows 下隱藏控制台視窗
|
||||||
|
creation_flags = 0
|
||||||
|
if os.name == "nt":
|
||||||
|
creation_flags = subprocess.CREATE_NO_WINDOW
|
||||||
|
|
||||||
|
self.app_handle = subprocess.Popen(
|
||||||
|
[str(tauri_exe)],
|
||||||
|
env=env,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
creationflags=creation_flags,
|
||||||
|
)
|
||||||
|
debug_log("Tauri 桌面應用程式已啟動")
|
||||||
|
|
||||||
|
# 等待一下確保應用程式啟動
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
debug_log(f"啟動 Tauri 應用程式失敗: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""停止桌面應用程式"""
|
||||||
|
debug_log("正在停止桌面應用程式...")
|
||||||
|
|
||||||
|
# 停止 Tauri 應用程式
|
||||||
|
if self.app_handle:
|
||||||
|
try:
|
||||||
|
self.app_handle.terminate()
|
||||||
|
self.app_handle.wait(timeout=5)
|
||||||
|
debug_log("Tauri 應用程式已停止")
|
||||||
|
except Exception as e:
|
||||||
|
debug_log(f"停止 Tauri 應用程式時發生錯誤: {e}")
|
||||||
|
try:
|
||||||
|
self.app_handle.kill()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
self.app_handle = None
|
||||||
|
|
||||||
|
if self.web_manager:
|
||||||
|
# 注意:不停止 Web 服務器,保持持久性
|
||||||
|
debug_log("Web 服務器保持運行狀態")
|
||||||
|
|
||||||
|
# 注意:不清除桌面模式設置,保持 MCP_DESKTOP_MODE 環境變數
|
||||||
|
# 這樣下次 MCP 調用時仍然會啟動桌面應用程式
|
||||||
|
# self.set_desktop_mode(False) # 註釋掉這行
|
||||||
|
debug_log("桌面應用程式已停止")
|
||||||
|
|
||||||
|
|
||||||
|
async def launch_desktop_app(test_mode: bool = False) -> DesktopApp:
|
||||||
|
"""啟動桌面應用程式
|
||||||
|
|
||||||
|
Args:
|
||||||
|
test_mode: 是否為測試模式,測試模式下會創建測試會話
|
||||||
|
"""
|
||||||
|
debug_log("正在啟動桌面應用程式...")
|
||||||
|
|
||||||
|
app = DesktopApp()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 啟動 Web 後端
|
||||||
|
server_url = await app.start_web_backend()
|
||||||
|
|
||||||
|
if test_mode:
|
||||||
|
# 測試模式:創建測試會話
|
||||||
|
debug_log("測試模式:創建測試會話")
|
||||||
|
app.create_test_session()
|
||||||
|
else:
|
||||||
|
# MCP 調用模式:使用現有會話
|
||||||
|
debug_log("MCP 調用模式:使用現有 MCP 會話,不創建新的測試會話")
|
||||||
|
|
||||||
|
# 啟動 Tauri 桌面應用程式
|
||||||
|
await app.launch_tauri_app(server_url)
|
||||||
|
|
||||||
|
debug_log(f"桌面應用程式已啟動,後端服務: {server_url}")
|
||||||
|
return app
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
debug_log(f"桌面應用程式啟動失敗: {e}")
|
||||||
|
app.stop()
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def run_desktop_app():
|
||||||
|
"""同步方式運行桌面應用程式"""
|
||||||
|
try:
|
||||||
|
# 設置事件循環策略(Windows)
|
||||||
|
if sys.platform == "win32":
|
||||||
|
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
|
||||||
|
|
||||||
|
# 運行應用程式
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
|
app = loop.run_until_complete(launch_desktop_app())
|
||||||
|
|
||||||
|
# 保持應用程式運行
|
||||||
|
debug_log("桌面應用程式正在運行,按 Ctrl+C 停止...")
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
time.sleep(1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
debug_log("收到停止信號...")
|
||||||
|
finally:
|
||||||
|
app.stop()
|
||||||
|
loop.close()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
debug_log(f"桌面應用程式運行失敗: {e}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
run_desktop_app()
|
@ -613,7 +613,7 @@ class WebUIManager:
|
|||||||
debug_log("使用發佈包中的桌面應用程式模組")
|
debug_log("使用發佈包中的桌面應用程式模組")
|
||||||
return desktop_func
|
return desktop_func
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
debug_log("發佈包中未找到桌面應用程式模組,嘗試開發環境...")
|
||||||
|
|
||||||
# 回退到開發環境路徑
|
# 回退到開發環境路徑
|
||||||
import sys
|
import sys
|
||||||
@ -633,6 +633,7 @@ class WebUIManager:
|
|||||||
return dev_func
|
return dev_func
|
||||||
except ImportError:
|
except ImportError:
|
||||||
debug_log("無法從開發環境路徑導入桌面應用程式模組")
|
debug_log("無法從開發環境路徑導入桌面應用程式模組")
|
||||||
|
debug_log("這可能是 PyPI 安裝的版本,桌面應用功能不可用")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
launch_desktop_app_func = import_desktop_app()
|
launch_desktop_app_func = import_desktop_app()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user