mirror of
https://github.com/countbot-ai/CountBot.git
synced 2026-09-14 20:46:47 +08:00
121 lines
3.9 KiB
Python
121 lines
3.9 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
CountBot 应用启动脚本
|
||
开发模式启动,支持热重载
|
||
支持本地网络 IP 监控,类似 Vue3 启动模式
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
from pathlib import Path
|
||
from backend.utils.network import get_local_ips
|
||
from backend.utils.runtime_env import (
|
||
apply_bind_env,
|
||
is_public_bind_host,
|
||
resolve_bind_address,
|
||
)
|
||
|
||
# Windows 平台强制 UTF-8 编码,避免 GBK 编码错误
|
||
if sys.platform == "win32":
|
||
# Python 3.7+ 支持
|
||
os.environ["PYTHONIOENCODING"] = "utf-8"
|
||
# 设置控制台代码页为 UTF-8
|
||
try:
|
||
import ctypes
|
||
kernel32 = ctypes.windll.kernel32
|
||
kernel32.SetConsoleCP(65001)
|
||
kernel32.SetConsoleOutputCP(65001)
|
||
except Exception:
|
||
pass
|
||
|
||
# 添加项目根目录到 Python 路径
|
||
project_root = Path(__file__).parent
|
||
sys.path.insert(0, str(project_root))
|
||
|
||
|
||
def main():
|
||
"""
|
||
启动应用(开发模式)
|
||
|
||
功能:
|
||
- 启动 FastAPI 应用服务器(开发模式)
|
||
- 启用热重载,文件更改自动重启
|
||
- 显示本地和网络访问地址
|
||
- 监控 backend 目录的文件变化
|
||
"""
|
||
import uvicorn
|
||
from loguru import logger
|
||
|
||
from backend.utils.logger import build_uvicorn_log_config
|
||
|
||
# 读取配置
|
||
host, port = resolve_bind_address()
|
||
apply_bind_env(host, port)
|
||
|
||
# 获取本地 IP 地址
|
||
local_ips = get_local_ips()
|
||
|
||
# 打印启动信息
|
||
logger.info("=" * 60)
|
||
logger.info("CountBot 开发模式启动中...")
|
||
logger.info("=" * 60)
|
||
|
||
try:
|
||
# 启动服务器前显示"服务器启动完成"消息和访问地址
|
||
logger.info("服务器启动完成!")
|
||
logger.info("=" * 60)
|
||
|
||
# 显示本地访问地址
|
||
logger.info(f"Local: http://localhost:{port}")
|
||
|
||
# 显示网络访问地址(如果监听了所有接口或用户明确设置了 0.0.0.0)
|
||
if is_public_bind_host(host):
|
||
if local_ips:
|
||
for ip in local_ips:
|
||
logger.info(f"Network: http://{ip}:{port}")
|
||
else:
|
||
logger.info("Network: (无法检测到本地 IP 地址)")
|
||
logger.info(f"提示: 请检查网络连接或手动访问 http://<your-ip>:{port}")
|
||
else:
|
||
# 即使监听 127.0.0.1,也显示可用的网络 IP 供参考
|
||
if local_ips:
|
||
logger.info(f"Network: http://{host}:{port}")
|
||
logger.info("提示: 如需从其他设备访问,请设置 COUNTBOT_HOST=0.0.0.0")
|
||
logger.info(f"可用网络 IP: {', '.join(local_ips)}")
|
||
else:
|
||
logger.info(f"Network: http://{host}:{port}")
|
||
logger.info("提示: 如需从其他设备访问,请设置 COUNTBOT_HOST=0.0.0.0")
|
||
|
||
logger.info("-" * 60)
|
||
logger.info("热重载已启用 - 文件更改将自动重启")
|
||
logger.info("按下 Ctrl+C 停止服务器")
|
||
logger.info("=" * 60)
|
||
|
||
# 在 Windows 开发模式下,uvicorn 的 reload 会切到 SelectorEventLoop,
|
||
# 这会让 asyncio.create_subprocess_shell 无法使用。
|
||
run_kwargs = dict(
|
||
app="backend.app:app",
|
||
host=host,
|
||
port=port,
|
||
reload=True, # 开发模式启用热重载
|
||
reload_dirs=["backend"], # 监控 backend 目录
|
||
log_level="debug", # 开发模式使用 debug 日志级别
|
||
log_config=build_uvicorn_log_config(),
|
||
)
|
||
if sys.platform == "win32":
|
||
run_kwargs["loop"] = "none"
|
||
|
||
# 启动服务器(开发模式)
|
||
uvicorn.run(**run_kwargs)
|
||
except KeyboardInterrupt:
|
||
logger.info("Received keyboard interrupt")
|
||
except Exception as e:
|
||
logger.error(f"Server error: {e}")
|
||
raise
|
||
finally:
|
||
logger.info("Application shutdown complete")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|