Files
shuidrop_gui/quick_build.py

361 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
快速打包脚本 - 避免spec文件缩进问题
"""
import os
import subprocess
import shutil
from pathlib import Path
def clean_build():
"""清理构建目录"""
print("Cleaning old build files...")
# 跳过进程结束步骤,避免影响当前脚本运行
print("Skipping process termination step...")
# 等待少量时间确保文件句柄释放
import time
print("Waiting for file handles to release...")
time.sleep(0.5)
dirs_to_clean = ['dist', 'build']
for dir_name in dirs_to_clean:
print(f"Checking directory: {dir_name}")
if os.path.exists(dir_name):
try:
print(f"Deleting: {dir_name}")
shutil.rmtree(dir_name)
print(f"Deleted: {dir_name}")
except PermissionError as e:
print(f"WARNING: {dir_name} is in use, attempting force delete... Error: {e}")
try:
subprocess.run(['rd', '/s', '/q', dir_name],
shell=True, check=True)
print(f"Force delete successful: {dir_name}")
except Exception as e2:
print(f"ERROR: Cannot delete {dir_name}: {e2}")
print("TIP: Please delete manually or run force_clean_dist.bat")
except Exception as e:
print(f"ERROR: Failed to delete {dir_name}: {e}")
else:
print(f"INFO: {dir_name} does not exist, skipping")
print("Cleaning phase completed")
def build_with_command():
"""使用命令行参数直接打包"""
print("Starting build...")
cmd = [
'pyinstaller',
'--name=MultiPlatformGUI', # 直接使用最终目录名
'--onedir', # 相当于 --exclude-binaries
'--windowed', # 相当于 -w
'--icon=static/ai_assistant_icon_64.png', # 添加主程序图标
'--add-data=config.py;.',
'--add-data=exe_file_logger.py;.',
'--add-data=windows_taskbar_fix.py;.',
'--add-data=Utils/PythonNew32;Utils/PythonNew32',
'--add-data=Utils/JD;Utils/JD',
'--add-data=Utils/Dy;Utils/Dy',
'--add-data=Utils/Pdd;Utils/Pdd',
'--add-data=Utils/QianNiu;Utils/QianNiu',
'--add-data=Utils/message_models.py;Utils',
'--add-data=Utils/__init__.py;Utils',
'--add-data=WebSocket;WebSocket',
'--add-data=static;static',
'--add-binary=Utils/PythonNew32/SaiNiuApi.dll;Utils/PythonNew32',
'--add-binary=Utils/PythonNew32/SaiNiuSys.dll;Utils/PythonNew32',
'--add-binary=Utils/PythonNew32/SaiNiuServer.dll;Utils/PythonNew32',
'--add-binary=Utils/PythonNew32/python32.exe;Utils/PythonNew32',
'--add-binary=Utils/PythonNew32/python313.dll;Utils/PythonNew32',
'--add-binary=Utils/PythonNew32/vcruntime140.dll;Utils/PythonNew32',
'--hidden-import=PyQt5.QtCore',
'--hidden-import=PyQt5.QtGui',
'--hidden-import=PyQt5.QtWidgets',
'--hidden-import=websockets',
'--hidden-import=asyncio',
'--hidden-import=Utils.QianNiu.QianNiuUtils',
'--hidden-import=Utils.JD.JdUtils',
'--hidden-import=Utils.Dy.DyUtils',
'--hidden-import=Utils.Pdd.PddUtils',
'--hidden-import=WebSocket.backend_singleton',
'--hidden-import=WebSocket.BackendClient',
'--hidden-import=windows_taskbar_fix',
'main.py'
]
try:
print(f"执行命令: {' '.join(cmd[:5])}... (共{len(cmd)}个参数)")
result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8')
if result.returncode == 0:
print("Build successful!")
print("Build result: dist/MultiPlatformGUI/")
# 验证输出目录(不需要重命名了)
if os.path.exists('dist/MultiPlatformGUI/MultiPlatformGUI.exe'):
# PyInstaller 生成的 exe 名称是 MultiPlatformGUI.exe
# 重命名为 main.exe保持兼容性
try:
old_exe = 'dist/MultiPlatformGUI/MultiPlatformGUI.exe'
new_exe = 'dist/MultiPlatformGUI/main.exe'
if os.path.exists(new_exe):
os.remove(new_exe)
os.rename(old_exe, new_exe)
print("Main executable renamed: MultiPlatformGUI.exe -> main.exe")
exe_size = os.path.getsize(new_exe) / 1024 / 1024
print(f"Main executable verified: main.exe ({exe_size:.1f} MB)")
except Exception as e:
print(f"WARNING: Failed to rename main executable: {e}")
elif os.path.exists('dist/MultiPlatformGUI/main.exe'):
# 如果已经是 main.exe直接验证
exe_size = os.path.getsize('dist/MultiPlatformGUI/main.exe') / 1024 / 1024
print(f"Main executable verified: main.exe ({exe_size:.1f} MB)")
else:
print("WARNING: Main executable file not found")
# 创建使用说明
try:
create_usage_guide()
except:
create_usage_guide_fallback()
return True
else:
print("ERROR: Build failed")
if result.stderr:
print("Error messages:")
print(result.stderr)
return False
except Exception as e:
print(f"ERROR: Build process error: {e}")
return False
def create_usage_guide():
"""创建使用说明"""
guide_content = r"""# 多平台客服GUI使用说明
## 🚀 运行方式
```
cd dist/MultiPlatformGUI
.\main.exe
```
## 📝 支持平台
- 千牛 (淘宝)
- 京东 (JD)
- 抖音 (DY)
- 拼多多 (PDD)
## 🎯 特点
- 支持多平台同时监听
- 无平台间冲突
- 自动生成日志文件
- 美观的系统托盘图标
- 现代化UI界面
## 📁 文件结构
```
MultiPlatformGUI/
├── main.exe # 主程序
└── _internal/ # 程序依赖文件
├── static/ # 图标资源
│ ├── ai_assistant_icon_16.png
│ ├── ai_assistant_icon_32.png
│ └── ai_assistant_icon_64.png
├── Utils/
│ ├── PythonNew32/ # 千牛DLL文件
│ ├── JD/ # 京东模块
│ ├── Dy/ # 抖音模块
│ └── Pdd/ # 拼多多模块
└── ...
```
## 🔧 故障排除
1. **图标不显示**:检查 _internal/static/ 目录下的图标文件是否存在
2. **连接失败**:检查网络连接和令牌是否正确
3. **平台无响应**:查看日志文件了解详细错误信息
## 📞 技术支持
如有问题,请提供:
- 错误截图
- 具体的错误描述
- 操作步骤
"""
try:
with open('dist/MultiPlatformGUI/使用说明.txt', 'w', encoding='utf-8') as f:
f.write(guide_content)
print("Usage guide file generated")
except:
print("WARNING: Usage guide generation failed")
def create_usage_guide_fallback():
"""备用使用说明生成"""
guide_content = r"""# 多平台客服GUI使用说明
## 🚀 运行方式
```
cd dist/main
.\main.exe
```
## 📝 支持平台
- 千牛 (淘宝)
- 京东 (JD)
- 抖音 (DY)
- 拼多多 (PDD)
## 🎯 特点
- 支持多平台同时监听
- 无平台间冲突
- 自动生成日志文件
"""
try:
with open('dist/main/使用说明.txt', 'w', encoding='utf-8') as f:
f.write(guide_content)
print("Usage guide file generated (fallback path)")
except:
print("WARNING: Usage guide generation failed")
def verify_result():
"""验证打包结果"""
print("\nVerifying build result...")
# 检查MultiPlatformGUI目录统一输出目录
target_dir = "dist/MultiPlatformGUI"
if os.path.exists(target_dir):
return _verify_directory(target_dir)
else:
print("ERROR: Build output directory not found: dist/MultiPlatformGUI")
print("TIP: Please check if PyInstaller executed successfully")
return False
def _verify_directory(base_dir):
"""验证指定目录的打包结果"""
# 检查可能的 exe 名称
exe_path = f"{base_dir}/main.exe"
if not os.path.exists(exe_path):
exe_path = f"{base_dir}/MultiPlatformGUI.exe"
internal_dir = f"{base_dir}/_internal"
dll_path = f"{base_dir}/_internal/Utils/PythonNew32/SaiNiuApi.dll"
static_dir = f"{base_dir}/_internal/static"
print(f"Verifying directory: {base_dir}")
# 检查主程序
if os.path.exists(exe_path):
size = os.path.getsize(exe_path) / 1024 / 1024 # MB
print(f"Main executable: main.exe ({size:.1f} MB)")
else:
print("ERROR: Main executable main.exe does not exist")
return False
# 检查_internal目录
if os.path.exists(internal_dir):
file_count = len([f for f in os.listdir(internal_dir) if os.path.isfile(os.path.join(internal_dir, f))])
dir_count = len([d for d in os.listdir(internal_dir) if os.path.isdir(os.path.join(internal_dir, d))])
print(f"Dependencies directory: _internal/ ({file_count} files, {dir_count} subdirectories)")
else:
print("ERROR: _internal directory does not exist")
return False
# 检查关键DLL可选
if os.path.exists(dll_path):
dll_size = os.path.getsize(dll_path) / 1024 # KB
print(f"QianNiu DLL: SaiNiuApi.dll ({dll_size:.1f} KB)")
else:
print("WARNING: QianNiu DLL does not exist (may be normal)")
# 检查静态资源
if os.path.exists(static_dir):
icon_files = list(Path(static_dir).glob("*.png"))
print(f"Static resources: static/ ({len(icon_files)} icon files)")
else:
print("WARNING: static directory does not exist")
print(f"Directory {base_dir} verification passed")
return True
def main():
"""主函数"""
print("Multi-Platform Customer Service GUI Quick Build Tool")
print("=" * 60)
try:
# 检查依赖
print("Checking build dependencies...")
try:
import subprocess
result = subprocess.run(['pyinstaller', '--version'],
capture_output=True, text=True, check=False)
if result.returncode == 0:
print(f"PyInstaller version: {result.stdout.strip()}")
else:
print("ERROR: PyInstaller not installed or unavailable")
print("TIP: Run: pip install pyinstaller")
return False
except Exception as e:
print(f"ERROR: Failed to check PyInstaller: {e}")
return False
# 清理
print("\nCleaning phase started...")
clean_build()
print("Cleaning phase completed")
# 打包
print("\nBuild phase started...")
if not build_with_command():
print("ERROR: Build phase failed")
return False
print("Build phase completed")
# 验证
print("\nVerification phase started...")
if not verify_result():
print("ERROR: Verification phase failed")
return False
print("Verification phase completed")
print("\n" + "=" * 60)
print("Build completed successfully!")
# 显示打包结果
if os.path.exists("dist/MultiPlatformGUI"):
print("Build result: dist/MultiPlatformGUI/")
print("Run command: cd dist/MultiPlatformGUI && .\\main.exe")
print("Create installer: python installer/build_installer.py")
print("=" * 60)
return True
except Exception as e:
print(f"ERROR: Build failed: {e}")
return False
if __name__ == "__main__":
success = main()
if success:
print("\nReady for testing!")
else:
print("\nERROR: Please check error messages and retry")