cythonize.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. print(f"✅ 部署包: {deploy_dir}")
  150. def create_start_scripts(deploy_dir):
  151. """创建启动脚本"""
  152. # Windows
  153. bat_content = """@echo off
  154. chcp 65001 >nul
  155. echo === LongjoeAgent ===
  156. echo.
  157. REM 检查Python
  158. python --version >nul 2>&1
  159. if errorlevel 1 (
  160. echo 错误: 未找到Python
  161. pause
  162. exit /b 1
  163. )
  164. REM 启动
  165. echo 启动服务...
  166. python app.py
  167. pause
  168. """
  169. bat_file = deploy_dir / "start.bat"
  170. bat_file.write_text(bat_content, encoding="utf-8")
  171. # Linux/Mac
  172. sh_content = """#!/bin/bash
  173. echo "=== LongjoeAgent ==="
  174. # 检查Python
  175. if ! command -v python3 &> /dev/null; then
  176. echo "错误: 未找到Python3"
  177. exit 1
  178. fi
  179. # 启动
  180. echo "启动服务..."
  181. python3 app.py
  182. """
  183. sh_file = deploy_dir / "start.sh"
  184. sh_file.write_text(sh_content, encoding="utf-8")
  185. if sys.platform != "win32":
  186. os.chmod(sh_file, 0o755)
  187. print(" 创建启动脚本: start.bat, start.sh")
  188. def main():
  189. """主函数"""
  190. print_banner()
  191. # 1. 检查环境
  192. if not check_environment():
  193. sys.exit(1)
  194. # 2. 清理
  195. clean_build()
  196. # 3. 编译
  197. if not compile_project():
  198. sys.exit(1)
  199. # 4. 创建部署包
  200. create_deployment()
  201. # 5. 完成
  202. print("\n" + "=" * 60)
  203. print("🎉 编译完成!")
  204. print("=" * 60)
  205. print("\n📁 文件结构:")
  206. print(" • 源代码: 保持不变")
  207. print(" • 编译文件: build/compiled/")
  208. print(" • 部署包: build/deploy/")
  209. print("\n🚀 使用方法:")
  210. print(" 开发: python app.py")
  211. print(" 部署: 复制 build/deploy/ 到服务器")
  212. print(" 运行: 执行 start.sh 或 start.bat")
  213. if __name__ == "__main__":
  214. main()