340 lines
11 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""
MCP Interactive Feedback Enhanced - 主程式入口
==============================================
此檔案允許套件透過 `python -m mcp_feedback_enhanced` 執行
使用方法:
python -m mcp_feedback_enhanced # 啟動 MCP 伺服器
python -m mcp_feedback_enhanced test # 執行測試
"""
import argparse
2025-06-10 09:55:34 +08:00
import asyncio
2025-06-11 03:25:08 +08:00
import os
import sys
2025-06-10 09:55:34 +08:00
import warnings
2025-06-11 03:25:08 +08:00
2025-06-10 09:55:34 +08:00
# 抑制 Windows 上的 asyncio ResourceWarning
2025-06-11 03:25:08 +08:00
if sys.platform == "win32":
warnings.filterwarnings(
"ignore", category=ResourceWarning, message=".*unclosed transport.*"
)
2025-06-10 09:55:34 +08:00
warnings.filterwarnings("ignore", category=ResourceWarning, message=".*unclosed.*")
# 設置 asyncio 事件循環策略以減少警告
try:
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
except AttributeError:
pass
2025-06-11 03:25:08 +08:00
def main():
"""主程式入口點"""
parser = argparse.ArgumentParser(
description="MCP Feedback Enhanced Enhanced - 互動式回饋收集 MCP 伺服器"
)
2025-06-11 03:25:08 +08:00
subparsers = parser.add_subparsers(dest="command", help="可用命令")
# 伺服器命令(預設)
2025-06-11 06:11:29 +08:00
subparsers.add_parser("server", help="啟動 MCP 伺服器(預設)")
2025-06-11 03:25:08 +08:00
# 測試命令
2025-06-11 03:25:08 +08:00
test_parser = subparsers.add_parser("test", help="執行測試")
test_parser.add_argument(
"--web", action="store_true", help="測試 Web UI (自動持續運行)"
)
2025-06-15 11:34:34 +08:00
test_parser.add_argument(
"--desktop", action="store_true", help="啟動桌面應用程式模式"
)
2025-06-11 03:25:08 +08:00
test_parser.add_argument(
"--timeout", type=int, default=60, help="測試超時時間 (秒)"
)
# 版本命令
2025-06-11 06:11:29 +08:00
subparsers.add_parser("version", help="顯示版本資訊")
2025-06-11 03:25:08 +08:00
args = parser.parse_args()
2025-06-11 03:25:08 +08:00
if args.command == "test":
run_tests(args)
2025-06-11 03:25:08 +08:00
elif args.command == "version":
show_version()
2025-06-11 03:25:08 +08:00
elif args.command == "server" or args.command is None:
run_server()
else:
# 不應該到達這裡
parser.print_help()
sys.exit(1)
2025-06-11 03:25:08 +08:00
def run_server():
"""啟動 MCP 伺服器"""
from .server import main as server_main
2025-06-11 03:25:08 +08:00
return server_main()
2025-06-11 03:25:08 +08:00
def run_tests(args):
"""執行測試"""
# 啟用調試模式以顯示測試過程
os.environ["MCP_DEBUG"] = "true"
2025-06-10 09:55:34 +08:00
# 在 Windows 上抑制 asyncio 警告
2025-06-11 03:25:08 +08:00
if sys.platform == "win32":
import warnings
# 設置更全面的警告抑制
os.environ["PYTHONWARNINGS"] = (
"ignore::ResourceWarning,ignore::DeprecationWarning"
)
warnings.filterwarnings("ignore", category=ResourceWarning)
warnings.filterwarnings("ignore", message=".*unclosed transport.*")
warnings.filterwarnings("ignore", message=".*I/O operation on closed pipe.*")
warnings.filterwarnings("ignore", message=".*unclosed.*")
# 抑制 asyncio 相關的所有警告
warnings.filterwarnings("ignore", module="asyncio.*")
2025-06-10 09:55:34 +08:00
2025-06-10 08:40:47 +08:00
if args.web:
print("🧪 執行 Web UI 測試...")
2025-06-10 08:40:47 +08:00
success = test_web_ui_simple()
if not success:
sys.exit(1)
2025-06-15 11:34:34 +08:00
elif args.desktop:
print("🖥️ 啟動桌面應用程式...")
success = test_desktop_app()
if not success:
sys.exit(1)
else:
2025-06-10 08:40:47 +08:00
print("❌ 測試功能已簡化")
2025-06-10 09:55:34 +08:00
print("💡 可用的測試選項:")
print(" --web 測試 Web UI")
2025-06-15 11:34:34 +08:00
print(" --desktop 啟動桌面應用程式")
2025-06-10 08:40:47 +08:00
print("💡 對於開發者:使用 'uv run pytest' 執行完整測試")
sys.exit(1)
2025-06-10 08:40:47 +08:00
def test_web_ui_simple():
"""簡單的 Web UI 測試"""
try:
import tempfile
import time
import webbrowser
2025-06-11 03:25:08 +08:00
from .web.main import WebUIManager
2025-06-11 03:38:21 +08:00
# 設置測試模式,禁用自動清理避免權限問題
os.environ["MCP_TEST_MODE"] = "true"
# 設置更高的端口範圍避免系統保留端口
os.environ["MCP_WEB_PORT"] = "9765"
2025-06-10 08:40:47 +08:00
print("🔧 創建 Web UI 管理器...")
2025-06-11 03:38:21 +08:00
manager = WebUIManager(host="127.0.0.1") # 使用動態端口分配
2025-06-10 08:40:47 +08:00
print("🔧 創建測試會話...")
with tempfile.TemporaryDirectory() as temp_dir:
2025-06-11 06:11:29 +08:00
created_session_id = manager.create_session(
temp_dir, "Web UI 測試 - 驗證基本功能"
)
2025-06-10 08:40:47 +08:00
2025-06-11 06:11:29 +08:00
if created_session_id:
2025-06-10 08:40:47 +08:00
print("✅ 會話創建成功")
print("🚀 啟動 Web 服務器...")
manager.start_server()
time.sleep(5) # 等待服務器完全啟動
2025-06-11 06:11:29 +08:00
if (
manager.server_thread is not None
and manager.server_thread.is_alive()
):
2025-06-10 08:40:47 +08:00
print("✅ Web 服務器啟動成功")
url = f"http://{manager.host}:{manager.port}"
print(f"🌐 服務器運行在: {url}")
# 嘗試開啟瀏覽器
print("🌐 正在開啟瀏覽器...")
try:
webbrowser.open(url)
print("✅ 瀏覽器已開啟")
except Exception as e:
print(f"⚠️ 無法自動開啟瀏覽器: {e}")
print(f"💡 請手動開啟瀏覽器並訪問: {url}")
print("📝 Web UI 測試完成,進入持續模式...")
print("💡 提示:服務器將持續運行,可在瀏覽器中測試互動功能")
print("💡 按 Ctrl+C 停止服務器")
try:
# 保持服務器運行
while True:
time.sleep(1)
except KeyboardInterrupt:
print("\n🛑 停止服務器...")
return True
else:
print("❌ Web 服務器啟動失敗")
return False
else:
print("❌ 會話創建失敗")
return False
2025-06-10 08:40:47 +08:00
except Exception as e:
print(f"❌ Web UI 測試失敗: {e}")
import traceback
2025-06-11 03:25:08 +08:00
2025-06-10 08:40:47 +08:00
traceback.print_exc()
return False
2025-06-11 03:38:21 +08:00
finally:
# 清理測試環境變數
os.environ.pop("MCP_TEST_MODE", None)
os.environ.pop("MCP_WEB_PORT", None)
2025-06-15 11:34:34 +08:00
def test_desktop_app():
"""測試桌面應用程式"""
try:
print("🔧 檢查桌面應用程式依賴...")
# 檢查是否有 Tauri 桌面模組
try:
import os
import sys
# 嘗試導入桌面應用程式模組
def import_desktop_app():
# 首先嘗試從發佈包位置導入
try:
from .desktop_app import launch_desktop_app as desktop_func
print("✅ 找到發佈包中的桌面應用程式模組")
return desktop_func
except ImportError:
pass
# 回退到開發環境路徑
tauri_python_path = os.path.join(
os.path.dirname(__file__), "..", "..", "src-tauri", "python"
)
if os.path.exists(tauri_python_path):
sys.path.insert(0, tauri_python_path)
print(f"✅ 找到 Tauri Python 模組路徑: {tauri_python_path}")
try:
from mcp_feedback_enhanced_desktop import ( # type: ignore
launch_desktop_app as dev_func,
)
return dev_func
except ImportError:
print("❌ 無法從開發環境路徑導入桌面應用程式模組")
return None
else:
print(f"⚠️ Tauri Python 模組路徑不存在: {tauri_python_path}")
print("💡 請確保已正確建立 PyTauri 專案結構")
return None
launch_desktop_app_func = import_desktop_app()
if launch_desktop_app_func is None:
return False
print("✅ 桌面應用程式模組導入成功")
except ImportError as e:
print(f"❌ 無法導入桌面應用程式模組: {e}")
print(
"💡 請確保已執行 'make build-desktop''python scripts/build_desktop.py'"
)
return False
print("🚀 啟動桌面應用程式...")
# 設置桌面模式環境變數
os.environ["MCP_DESKTOP_MODE"] = "true"
# 使用 asyncio 啟動桌面應用程式
if sys.platform == "win32":
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
# 使用 WebUIManager 來管理桌面應用實例
from .web.main import get_web_ui_manager
manager = get_web_ui_manager()
# 啟動桌面應用並保存實例到 manager
app = loop.run_until_complete(launch_desktop_app_func(test_mode=True))
manager.desktop_app_instance = app
print("✅ 桌面應用程式啟動成功")
print("💡 桌面應用程式正在運行,按 Ctrl+C 停止...")
# 保持應用程式運行
try:
while True:
import time
time.sleep(1)
except KeyboardInterrupt:
print("\n🛑 停止桌面應用程式...")
app.stop()
return True
except Exception as e:
print(f"❌ 桌面應用程式啟動失敗: {e}")
import traceback
traceback.print_exc()
return False
finally:
loop.close()
except Exception as e:
print(f"❌ 桌面應用程式測試失敗: {e}")
import traceback
traceback.print_exc()
return False
finally:
# 清理環境變數
os.environ.pop("MCP_DESKTOP_MODE", None)
2025-06-10 09:55:34 +08:00
async def wait_for_process(process):
"""等待進程結束"""
try:
# 等待進程自然結束
await process.wait()
# 確保管道正確關閉
try:
2025-06-11 03:25:08 +08:00
if hasattr(process, "stdout") and process.stdout:
2025-06-10 09:55:34 +08:00
process.stdout.close()
2025-06-11 03:25:08 +08:00
if hasattr(process, "stderr") and process.stderr:
2025-06-10 09:55:34 +08:00
process.stderr.close()
2025-06-11 03:25:08 +08:00
if hasattr(process, "stdin") and process.stdin:
2025-06-10 09:55:34 +08:00
process.stdin.close()
except Exception as close_error:
print(f"關閉進程管道時出錯: {close_error}")
except Exception as e:
print(f"等待進程時出錯: {e}")
def show_version():
"""顯示版本資訊"""
2025-06-11 03:25:08 +08:00
from . import __author__, __version__
print(f"MCP Feedback Enhanced Enhanced v{__version__}")
print(f"作者: {__author__}")
print("GitHub: https://github.com/Minidoracat/mcp-feedback-enhanced")
2025-06-11 03:25:08 +08:00
if __name__ == "__main__":
2025-06-11 03:25:08 +08:00
main()