cythonize.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. # cythonize.py
  2. import os
  3. import sys
  4. import shutil
  5. from pathlib import Path
  6. import subprocess
  7. import time
  8. def print_banner():
  9. """打印标题"""
  10. print("=" * 60)
  11. print(" LongjoeAgent - Cython 编译工具")
  12. print("=" * 60)
  13. def check_environment():
  14. """检查环境"""
  15. print("\n🔍 检查环境...")
  16. # 检查Python
  17. if sys.version_info < (3, 7):
  18. print(f"❌ 需要Python 3.7+,当前: {sys.version}")
  19. return False
  20. # 检查依赖
  21. try:
  22. import Cython
  23. print(f"✅ Cython {Cython.__version__}")
  24. except ImportError:
  25. print("❌ 未安装Cython: pip install cython")
  26. return False
  27. try:
  28. import setuptools
  29. print(f"✅ setuptools {setuptools.__version__}")
  30. except ImportError:
  31. print("❌ 未安装setuptools: pip install setuptools wheel")
  32. return False
  33. return True
  34. def clean_build():
  35. """清理构建目录"""
  36. print("\n🧹 清理之前构建...")
  37. dirs_to_remove = ["build", "dist", "cython_build", "LongjoeAgent.egg-info"]
  38. for dir_name in dirs_to_remove:
  39. dir_path = Path(dir_name)
  40. if dir_path.exists():
  41. try:
  42. shutil.rmtree(dir_path)
  43. print(f" 已删除: {dir_name}")
  44. except:
  45. pass
  46. # 清理.c文件
  47. for c_file in Path(".").rglob("*.c"):
  48. try:
  49. c_file.unlink()
  50. except:
  51. pass
  52. def compile_project():
  53. """编译项目"""
  54. print("\n⚡ 开始编译...")
  55. start_time = time.time()
  56. # 运行setup.py
  57. result = subprocess.run(
  58. [sys.executable, "setup.py"], capture_output=True, text=True, encoding="utf-8"
  59. )
  60. if result.returncode != 0:
  61. print("❌ 编译失败!")
  62. if result.stderr:
  63. # 显示关键错误信息
  64. lines = result.stderr.split("\n")
  65. for line in lines:
  66. if "error" in line.lower() or "Error" in line:
  67. print(f" {line}")
  68. return False
  69. end_time = time.time()
  70. print(f"✅ 编译完成 ({end_time - start_time:.1f}秒)")
  71. # 显示编译结果
  72. show_compile_results()
  73. return True
  74. def show_compile_results():
  75. """显示编译结果"""
  76. compiled_dir = Path("build") / "compiled"
  77. if not compiled_dir.exists():
  78. print("❌ 编译目录不存在")
  79. return
  80. # 统计编译文件
  81. pyd_files = list(compiled_dir.rglob("*.pyd"))
  82. so_files = list(compiled_dir.rglob("*.so"))
  83. if pyd_files:
  84. print(f"\n📦 生成 {len(pyd_files)} 个 .pyd 文件:")
  85. for f in pyd_files[:5]:
  86. print(f" • {f.relative_to(compiled_dir)}")
  87. if len(pyd_files) > 5:
  88. print(f" ... 和 {len(pyd_files) - 5} 个其他文件")
  89. elif so_files:
  90. print(f"\n📦 生成 {len(so_files)} 个 .so 文件:")
  91. for f in so_files[:5]:
  92. print(f" • {f.relative_to(compiled_dir)}")
  93. if len(so_files) > 5:
  94. print(f" ... 和 {len(so_files) - 5} 个其他文件")
  95. else:
  96. print("❌ 未找到编译文件")
  97. def create_deployment():
  98. """创建部署包"""
  99. print("\n📦 创建部署包...")
  100. compiled_dir = Path("build") / "compiled"
  101. deploy_dir = Path("build") / "deploy"
  102. if not compiled_dir.exists():
  103. print("❌ 编译目录不存在")
  104. return
  105. # 清理旧的部署包
  106. if deploy_dir.exists():
  107. shutil.rmtree(deploy_dir)
  108. # 复制编译文件
  109. deploy_dir.mkdir(parents=True, exist_ok=True)
  110. for src_file in compiled_dir.rglob("*"):
  111. if src_file.is_file():
  112. rel_path = src_file.relative_to(compiled_dir)
  113. dst_file = deploy_dir / rel_path
  114. dst_file.parent.mkdir(parents=True, exist_ok=True)
  115. shutil.copy2(src_file, dst_file)
  116. # 复制必要文件
  117. essential_files = [
  118. "app.py",
  119. ".env.example",
  120. "requirements.txt",
  121. ".registration.example",
  122. ]
  123. for file_name in essential_files:
  124. src = Path(file_name)
  125. if src.exists():
  126. dst = deploy_dir / file_name
  127. shutil.copy2(src, dst)
  128. print(f" 复制: {file_name}")
  129. # 复制 config 目录下的 JSON 配置文件
  130. config_src = Path("config")
  131. if config_src.exists():
  132. config_dst = deploy_dir / "config"
  133. config_dst.mkdir(exist_ok=True)
  134. # 复制所有 JSON 文件
  135. json_files = list(config_src.rglob("*.json"))
  136. for json_file in json_files:
  137. if json_file.is_file():
  138. rel_path = json_file.relative_to(config_src)
  139. dst_file = config_dst / rel_path
  140. dst_file.parent.mkdir(parents=True, exist_ok=True)
  141. shutil.copy2(json_file, dst_file)
  142. print(f" 复制配置文件: config/{rel_path}")
  143. if json_files:
  144. print(f"✅ 已复制 {len(json_files)} 个配置文件")
  145. # 创建日志目录
  146. (deploy_dir / "chat_logs").mkdir(exist_ok=True)
  147. # 创建启动脚本
  148. create_start_scripts(deploy_dir)
  149. # 创建 Windows 服务脚本(新增)
  150. if sys.platform == "win32":
  151. create_windows_service_scripts(deploy_dir)
  152. print(f"✅ 部署包: {deploy_dir}")
  153. def create_start_scripts(deploy_dir):
  154. """创建启动脚本"""
  155. # Windows
  156. bat_content = """@echo off
  157. chcp 65001 >nul
  158. echo === LongjoeAgent ===
  159. echo.
  160. REM 检查Python
  161. python --version >nul 2>&1
  162. if errorlevel 1 (
  163. echo 错误: 未找到Python
  164. pause
  165. exit /b 1
  166. )
  167. REM 启动
  168. echo 启动服务...
  169. python app.py
  170. pause
  171. """
  172. bat_file = deploy_dir / "start.bat"
  173. bat_file.write_text(bat_content, encoding="utf-8")
  174. # Linux/Mac
  175. sh_content = """#!/bin/bash
  176. echo "=== LongjoeAgent ==="
  177. # 检查Python
  178. if ! command -v python3 &> /dev/null; then
  179. echo "错误: 未找到Python3"
  180. exit 1
  181. fi
  182. # 启动
  183. echo "启动服务..."
  184. python3 app.py
  185. """
  186. sh_file = deploy_dir / "start.sh"
  187. sh_file.write_text(sh_content, encoding="utf-8")
  188. if sys.platform != "win32":
  189. os.chmod(sh_file, 0o755)
  190. print(" 创建启动脚本: start.bat, start.sh")
  191. def create_windows_service_scripts(deploy_dir):
  192. """创建 Windows 服务管理脚本"""
  193. print(" 创建 Windows 服务脚本...")
  194. # 检查本地 nssm.exe
  195. nssm_exe = Path("nssm.exe")
  196. if not nssm_exe.exists():
  197. print(" ⚠️ 未找到 nssm.exe,跳过服务脚本创建")
  198. return
  199. # 复制 nssm.exe 到部署目录
  200. nssm_dst = deploy_dir / "nssm.exe"
  201. shutil.copy2(nssm_exe, nssm_dst)
  202. print(" ✅ 复制 nssm.exe")
  203. # 服务安装脚本
  204. install_bat = """@echo off
  205. chcp 65001 >nul
  206. echo ========================================
  207. echo LongjoeAgent Windows Service Install
  208. echo ========================================
  209. echo.
  210. REM 检查是否以管理员权限运行
  211. net session >nul 2>&1
  212. if %errorlevel% neq 0 (
  213. echo Error: 请以管理员权限运行此脚本!
  214. echo 请右键点击此脚本 -> "以管理员身份运行"
  215. pause
  216. exit /b 1
  217. )
  218. REM 动态获取脚本所在目录
  219. set "PROJECT_DIR=%~dp0"
  220. set "PROJECT_DIR=%PROJECT_DIR:~0,-1%"
  221. echo 项目目录: %PROJECT_DIR%
  222. REM 检查必要文件是否存在
  223. if not exist "%PROJECT_DIR%\\nssm.exe" (
  224. echo 错误: nssm.exe 未在项目目录中找到!
  225. pause
  226. exit /b 1
  227. )
  228. if not exist "%PROJECT_DIR%\\app.py" (
  229. echo 错误: app.py 未在项目目录中找到!
  230. pause
  231. exit /b 1
  232. )
  233. REM 动态查找Python安装路径
  234. echo 搜索Python安装...
  235. for /f "delims=" %%i in ('where python') do (
  236. set "PYTHON_PATH=%%i"
  237. goto :found_python
  238. )
  239. :found_python
  240. if not defined PYTHON_PATH (
  241. echo 错误: 未找到Python!
  242. echo 请安装 Python 3.7+ 并确保其在 PATH 中
  243. pause
  244. exit /b 1
  245. )
  246. echo 找到Python: %PYTHON_PATH%
  247. REM 停止并移除现有服务
  248. echo Unstall Service
  249. net stop LongjoeAI >nul 2>&1
  250. timeout /t 2 /nobreak >nul
  251. "%PROJECT_DIR%\\nssm.exe" remove LongjoeAI confirm >nul 2>&1
  252. REM 关键修正:使用正确的引号格式(模仿您的成功命令)
  253. echo 安装 LongjoeAI 服务...
  254. "%PROJECT_DIR%\\nssm.exe" install LongjoeAI "cmd" "/c cd /d "%PROJECT_DIR%" && "%PYTHON_PATH%" app.py"
  255. if errorlevel 1 (
  256. echo 错误: 服务安装失败!
  257. echo.
  258. echo 调试信息:
  259. echo 项目目录: %PROJECT_DIR%
  260. echo Python 路径: %PYTHON_PATH%
  261. )
  262. REM 配置服务参数
  263. echo 配置服务参数...
  264. "%PROJECT_DIR%\\nssm.exe" set LongjoeAI DisplayName "Longjoe AI Agent Service"
  265. "%PROJECT_DIR%\\nssm.exe" set LongjoeAI Description "龙嘉软件AI助手服务"
  266. echo.
  267. echo LongjoeAI 服务安装完成!
  268. goto :start_service
  269. :start_service
  270. echo.
  271. echo Starting service...
  272. net start LongjoeAI
  273. if %errorlevel% equ 0 (
  274. echo SUCCESS: Service started successfully!
  275. echo.
  276. ) else (
  277. echo ERROR: Service failed to start
  278. echo.
  279. )
  280. echo.
  281. pause
  282. """
  283. # 服务卸载脚本
  284. uninstall_bat = """@echo off
  285. chcp 65001 >nul
  286. echo ========================================
  287. echo LongjoeAI Service Uninstall
  288. echo ========================================
  289. echo.
  290. REM 检查是否以管理员权限运行
  291. net session >nul 2>&1
  292. if %errorlevel% neq 0 (
  293. echo 错误: 请以管理员权限运行此脚本!
  294. echo 请右键点击此脚本 -> "以管理员身份运行"
  295. pause
  296. exit /b 1
  297. )
  298. REM 动态获取项目目录
  299. set "PROJECT_DIR=%~dp0"
  300. set "PROJECT_DIR=%PROJECT_DIR:~0,-1%"
  301. echo 停止服务...
  302. net stop LongjoeAI >nul 2>&1
  303. timeout /t 3 /nobreak >nul
  304. echo 卸载服务...
  305. "%PROJECT_DIR%\\nssm.exe" remove LongjoeAI confirm >nul 2>&1
  306. if errorlevel 1 (
  307. echo 尝试强制删除...
  308. sc delete LongjoeAI >nul 2>&1
  309. )
  310. echo LongjoeAI 服务卸载成功!
  311. echo.
  312. pause
  313. """
  314. # 服务管理脚本
  315. manage_bat = """@echo off
  316. chcp 65001 >nul
  317. echo ========================================
  318. echo LongjoeAI Service Management
  319. echo ========================================
  320. echo.
  321. set "PROJECT_DIR=%~dp0"
  322. set "PROJECT_DIR=%PROJECT_DIR:~0,-1%"
  323. echo 1. 启动服务
  324. echo 2. 停止服务
  325. echo 3. 重启服务
  326. echo 4. 服务状态
  327. echo 5. Exit
  328. echo.
  329. set /p choice=请选择操作 (1-5):
  330. if "%choice%"=="1" (
  331. net start LongjoeAI
  332. if %errorlevel% equ 0 echo Service started successfully.
  333. ) else if "%choice%"=="2" (
  334. net stop LongjoeAI
  335. if %errorlevel% equ 0 echo Service stopped successfully.
  336. ) else if "%choice%"=="3" (
  337. net stop LongjoeAI
  338. timeout /t 2 /nobreak >nul
  339. net start LongjoeAI
  340. if %errorlevel% equ 0 echo Service restarted successfully.
  341. ) else if "%choice%"=="4" (
  342. sc query LongjoeAI
  343. ) else if "%choice%"=="5" (
  344. exit
  345. ) else (
  346. echo 错误: 无效选择!
  347. )
  348. echo.
  349. pause
  350. """
  351. # 写入脚本文件
  352. (deploy_dir / "service_install.bat").write_text(install_bat, encoding="utf-8")
  353. (deploy_dir / "service_uninstall.bat").write_text(uninstall_bat, encoding="utf-8")
  354. (deploy_dir / "service_manage.bat").write_text(manage_bat, encoding="utf-8")
  355. print(
  356. " ✅ 创建服务脚本: service_install.bat, service_uninstall.bat, service_manage.bat"
  357. )
  358. def main():
  359. """主函数"""
  360. print_banner()
  361. # 1. 检查环境
  362. if not check_environment():
  363. sys.exit(1)
  364. # 2. 清理
  365. clean_build()
  366. # 3. 编译
  367. if not compile_project():
  368. sys.exit(1)
  369. # 4. 创建部署包
  370. create_deployment()
  371. # 5. 完成
  372. print("\n" + "=" * 60)
  373. print("🎉 编译完成!")
  374. print("=" * 60)
  375. print("\n📁 文件结构:")
  376. print(" • 源代码: 保持不变")
  377. print(" • 编译文件: build/compiled/")
  378. print(" • 部署包: build/deploy/")
  379. print("\n🚀 使用方法:")
  380. print(" 开发: python app.py")
  381. print(" 部署: 复制 build/deploy/ 到服务器")
  382. print(" 运行: 执行 service_install.bat")
  383. if __name__ == "__main__":
  384. main()