mirror of
https://github.com/Minidoracat/mcp-feedback-enhanced.git
synced 2025-07-27 02:22:26 +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/
|
||||
|
||||
# Desktop application binaries (these should be built and copied by build script)
|
||||
src/mcp_feedback_enhanced/desktop_release/*
|
||||
src/mcp_feedback_enhanced/desktop_app/
|
||||
# Note: desktop_app module should be tracked, only exclude large binaries
|
||||
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
|
||||
|
||||
|
||||
|
@ -276,7 +276,7 @@ def test_desktop_app():
|
||||
print("✅ 找到發佈包中的桌面應用程式模組")
|
||||
return desktop_func
|
||||
except ImportError:
|
||||
pass
|
||||
print("🔍 發佈包中未找到桌面應用程式模組,嘗試開發環境...")
|
||||
|
||||
# 回退到開發環境路徑
|
||||
tauri_python_path = os.path.join(
|
||||
@ -295,12 +295,17 @@ def test_desktop_app():
|
||||
print("❌ 無法從開發環境路徑導入桌面應用程式模組")
|
||||
return None
|
||||
else:
|
||||
print(f"⚠️ Tauri Python 模組路徑不存在: {tauri_python_path}")
|
||||
print("💡 請確保已正確建立 PyTauri 專案結構")
|
||||
print(f"⚠️ 開發環境路徑不存在: {tauri_python_path}")
|
||||
print("💡 這可能是 PyPI 安裝的版本,桌面應用功能不可用")
|
||||
return None
|
||||
|
||||
launch_desktop_app_func = import_desktop_app()
|
||||
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
|
||||
|
||||
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("使用發佈包中的桌面應用程式模組")
|
||||
return desktop_func
|
||||
except ImportError:
|
||||
pass
|
||||
debug_log("發佈包中未找到桌面應用程式模組,嘗試開發環境...")
|
||||
|
||||
# 回退到開發環境路徑
|
||||
import sys
|
||||
@ -633,6 +633,7 @@ class WebUIManager:
|
||||
return dev_func
|
||||
except ImportError:
|
||||
debug_log("無法從開發環境路徑導入桌面應用程式模組")
|
||||
debug_log("這可能是 PyPI 安裝的版本,桌面應用功能不可用")
|
||||
raise
|
||||
|
||||
launch_desktop_app_func = import_desktop_app()
|
||||
|
Loading…
x
Reference in New Issue
Block a user