🐛 修正缺少的打包檔案

This commit is contained in:
Minidoracat 2025-06-15 19:16:41 +08:00
parent 608358efc6
commit 4969e37ffe
5 changed files with 380 additions and 6 deletions

5
.gitignore vendored
View File

@ -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

View File

@ -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("✅ 桌面應用程式模組導入成功")

View File

@ -0,0 +1,30 @@
#!/usr/bin/env python3
"""
MCP Feedback Enhanced Desktop Application
=========================================
基於 Tauri 的桌面應用程式包裝器 MCP Feedback Enhanced 提供原生桌面體驗
主要功能
- 原生桌面應用程式界面
- 整合現有的 Web UI 功能
- 跨平台支援WindowsmacOSLinux
- 無需瀏覽器的獨立運行環境
作者: 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",
]

View 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()

View File

@ -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()