95 lines
2.8 KiB
Python
95 lines
2.8 KiB
Python
import logging
|
||
import os
|
||
import socket
|
||
import sys
|
||
import threading
|
||
import time
|
||
import webbrowser
|
||
from pathlib import Path
|
||
|
||
from config_manager import ConfigManager
|
||
from web_app import create_app
|
||
|
||
|
||
def get_config_path():
|
||
"""
|
||
获取配置文件的合适路径。
|
||
在开发环境使用当前目录,在打包环境使用exe所在目录。
|
||
"""
|
||
try:
|
||
# 检查是否在PyInstaller打包环境中
|
||
sys._MEIPASS
|
||
# 如果是打包环境,使用exe文件所在目录
|
||
exe_dir = os.path.dirname(sys.executable)
|
||
return os.path.join(exe_dir, "config.json")
|
||
except Exception:
|
||
# 开发环境,使用当前目录
|
||
return "config.json"
|
||
|
||
def find_available_port(start: int = 4567, limit: int = 4667) -> int:
|
||
"""Return the first free TCP port within the inclusive range."""
|
||
for port in range(start, limit + 1):
|
||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||
try:
|
||
sock.bind(("127.0.0.1", port))
|
||
return port
|
||
except OSError:
|
||
continue
|
||
raise RuntimeError(f"无法在 {start}-{limit} 范围内找到可用端口")
|
||
|
||
|
||
def open_browser_later(url: str, delay: float = 1.0) -> None:
|
||
"""Open the default browser after a small delay."""
|
||
|
||
def _opener():
|
||
time.sleep(delay)
|
||
try:
|
||
webbrowser.open_new(url)
|
||
except Exception:
|
||
pass
|
||
|
||
threading.Thread(target=_opener, daemon=True).start()
|
||
|
||
|
||
def configure_logging(base_path: Path) -> None:
|
||
"""Configure application logging."""
|
||
handlers = []
|
||
formatter = logging.Formatter(
|
||
"[%(asctime)s] %(levelname)s %(name)s: %(message)s",
|
||
datefmt="%Y-%m-%d %H:%M:%S",
|
||
)
|
||
|
||
console_handler = logging.StreamHandler()
|
||
console_handler.setFormatter(formatter)
|
||
handlers.append(console_handler)
|
||
|
||
root = logging.getLogger()
|
||
root.handlers.clear()
|
||
root.setLevel(logging.INFO)
|
||
for handler in handlers:
|
||
root.addHandler(handler)
|
||
|
||
werkzeug_logger = logging.getLogger("werkzeug")
|
||
werkzeug_logger.handlers.clear()
|
||
werkzeug_logger.setLevel(logging.WARNING)
|
||
werkzeug_logger.propagate = False
|
||
|
||
|
||
if __name__ == "__main__":
|
||
config_path = get_config_path()
|
||
runtime_dir = Path(config_path).resolve().parent
|
||
configure_logging(runtime_dir)
|
||
logger = logging.getLogger("essay_corrector.main")
|
||
logger.info("使用配置文件: %s", config_path)
|
||
|
||
config_manager = ConfigManager(config_path)
|
||
app = create_app(config_manager)
|
||
|
||
port = find_available_port()
|
||
url = f"http://127.0.0.1:{port}/"
|
||
logger.info("🚀 Web UI 已启动,访问: %s", url)
|
||
open_browser_later(url)
|
||
|
||
app.run(host="127.0.0.1", port=port, debug=False, use_reloader=False)
|