mirror of
https://github.com/countbot-ai/CountBot.git
synced 2026-09-14 20:46:47 +08:00
193 lines
5.8 KiB
Python
193 lines
5.8 KiB
Python
"""系统集成 API 端点"""
|
|
|
|
from datetime import datetime, timezone
|
|
from fastapi import APIRouter, HTTPException
|
|
from fastapi.responses import JSONResponse
|
|
from pydantic import BaseModel
|
|
from loguru import logger
|
|
from typing import Optional
|
|
|
|
from backend.version import APP_VERSION
|
|
from backend.utils.runtime_env import resolve_bind_address
|
|
|
|
router = APIRouter(prefix="/api/system", tags=["system"])
|
|
|
|
# 全局引用(由 main.py 设置)
|
|
tray_manager = None
|
|
hotkey_manager = None
|
|
autostart_manager = None
|
|
|
|
|
|
@router.get("/health")
|
|
async def health_check():
|
|
"""健康检查端点 - 用于前端检测服务器是否就绪"""
|
|
return {
|
|
"status": "ok",
|
|
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
"service": "CountBot"
|
|
}
|
|
|
|
|
|
@router.get("/info")
|
|
async def system_info():
|
|
"""返回系统运行信息,供前端侧边栏展示"""
|
|
import platform
|
|
import os
|
|
import sys
|
|
|
|
host, port = resolve_bind_address()
|
|
api_url = f"http://{host}:{port}"
|
|
|
|
return {
|
|
"api_url": api_url,
|
|
"version": APP_VERSION,
|
|
"python_version": platform.python_version(),
|
|
"os": f"{platform.system()} {platform.release()}",
|
|
"arch": platform.machine(),
|
|
"pid": os.getpid(),
|
|
"uptime_start": datetime.now(timezone.utc).isoformat(),
|
|
}
|
|
|
|
|
|
class NotificationRequest(BaseModel):
|
|
"""通知请求模型"""
|
|
title: str
|
|
message: str
|
|
icon: Optional[str] = None
|
|
|
|
|
|
class HotkeyRequest(BaseModel):
|
|
"""快捷键注册请求"""
|
|
hotkey: str
|
|
action: str
|
|
|
|
|
|
class AutoStartRequest(BaseModel):
|
|
"""自启动配置请求"""
|
|
enabled: bool
|
|
|
|
|
|
@router.post("/notify")
|
|
async def send_notification(request: NotificationRequest):
|
|
"""发送系统通知"""
|
|
try:
|
|
logger.info(f"Notification: {request.title} - {request.message}")
|
|
return {"success": True, "message": "Notification sent"}
|
|
except Exception as e:
|
|
logger.error(f"Failed to send notification: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.get("/tray/status")
|
|
async def get_tray_status():
|
|
"""获取系统托盘状态"""
|
|
return JSONResponse(content={
|
|
"available": tray_manager is not None,
|
|
"visible": True # pywebview doesn't provide tray visibility status
|
|
})
|
|
|
|
|
|
@router.post("/tray/minimize")
|
|
async def minimize_to_tray():
|
|
"""最小化到系统托盘"""
|
|
if not tray_manager:
|
|
raise HTTPException(status_code=503, detail="System tray not available")
|
|
|
|
try:
|
|
tray_manager.minimize_to_tray()
|
|
return JSONResponse(content={"success": True})
|
|
except Exception as e:
|
|
logger.error(f"Failed to minimize to tray: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.post("/tray/restore")
|
|
async def restore_from_tray():
|
|
"""从系统托盘恢复窗口"""
|
|
if not tray_manager:
|
|
raise HTTPException(status_code=503, detail="System tray not available")
|
|
|
|
try:
|
|
tray_manager.restore_from_tray()
|
|
return JSONResponse(content={"success": True})
|
|
except Exception as e:
|
|
logger.error(f"Failed to restore from tray: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.get("/hotkeys")
|
|
async def get_hotkeys():
|
|
"""获取已注册的快捷键"""
|
|
if not hotkey_manager:
|
|
raise HTTPException(status_code=503, detail="Hotkey manager not available")
|
|
|
|
return JSONResponse(content={
|
|
"hotkeys": list(hotkey_manager.hotkeys.keys()),
|
|
"enabled": hotkey_manager.enabled
|
|
})
|
|
|
|
|
|
@router.post("/hotkeys/register")
|
|
async def register_hotkey(request: HotkeyRequest):
|
|
"""注册全局快捷键"""
|
|
if not hotkey_manager:
|
|
raise HTTPException(status_code=503, detail="Hotkey manager not available")
|
|
|
|
try:
|
|
# Note: Actual hotkey implementation would need platform-specific libraries
|
|
# like keyboard or pynput
|
|
hotkey_manager.register(request.hotkey, lambda: logger.info(f"Hotkey triggered: {request.action}"))
|
|
return JSONResponse(content={"success": True})
|
|
except Exception as e:
|
|
logger.error(f"Failed to register hotkey: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.delete("/hotkeys/{hotkey}")
|
|
async def unregister_hotkey(hotkey: str):
|
|
"""注销全局快捷键"""
|
|
if not hotkey_manager:
|
|
raise HTTPException(status_code=503, detail="Hotkey manager not available")
|
|
|
|
try:
|
|
hotkey_manager.unregister(hotkey)
|
|
return JSONResponse(content={"success": True})
|
|
except Exception as e:
|
|
logger.error(f"Failed to unregister hotkey: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.get("/autostart")
|
|
async def get_autostart_status():
|
|
"""获取自启动状态"""
|
|
if not autostart_manager:
|
|
raise HTTPException(status_code=503, detail="Auto-start manager not available")
|
|
|
|
try:
|
|
enabled = autostart_manager.is_enabled()
|
|
return JSONResponse(content={"enabled": enabled})
|
|
except Exception as e:
|
|
logger.error(f"Failed to get auto-start status: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
@router.post("/autostart")
|
|
async def set_autostart(request: AutoStartRequest):
|
|
"""启用或禁用自启动"""
|
|
if not autostart_manager:
|
|
raise HTTPException(status_code=503, detail="Auto-start manager not available")
|
|
|
|
try:
|
|
if request.enabled:
|
|
success = autostart_manager.enable()
|
|
else:
|
|
success = autostart_manager.disable()
|
|
|
|
if success:
|
|
return JSONResponse(content={"success": True, "enabled": request.enabled})
|
|
else:
|
|
raise HTTPException(status_code=500, detail="Failed to update auto-start")
|
|
except Exception as e:
|
|
logger.error(f"Failed to set auto-start: {e}")
|
|
raise HTTPException(status_code=500, detail=str(e))
|