227 lines
6.4 KiB
Python
227 lines
6.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
打包脚本 - 将Streamlit应用打包成exe文件
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import shutil
|
|
|
|
def install_pyinstaller():
|
|
"""安装PyInstaller"""
|
|
print("正在安装PyInstaller...")
|
|
try:
|
|
subprocess.check_call([sys.executable, "-m", "pip", "install", "pyinstaller"])
|
|
print("✅ PyInstaller安装成功")
|
|
return True
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"❌ PyInstaller安装失败: {e}")
|
|
return False
|
|
|
|
def create_spec_file():
|
|
"""创建PyInstaller spec文件"""
|
|
spec_content = '''# -*- mode: python ; coding: utf-8 -*-
|
|
|
|
import sys
|
|
from PyInstaller.utils.hooks import collect_data_files, collect_submodules
|
|
|
|
block_cipher = None
|
|
|
|
a = Analysis(
|
|
['app.py'],
|
|
pathex=[],
|
|
binaries=[],
|
|
datas=[
|
|
*collect_data_files('streamlit'),
|
|
*collect_data_files('streamlit_ace'),
|
|
*collect_data_files('streamlit_option_menu'),
|
|
('.env', '.')
|
|
],
|
|
hiddenimports=[
|
|
'streamlit',
|
|
'streamlit.web.cli',
|
|
'streamlit.runtime.scriptrunner',
|
|
'streamlit.proto',
|
|
'streamlit.config',
|
|
'streamlit.logger',
|
|
'streamlit.caching',
|
|
'streamlit.elements',
|
|
'streamlit.components',
|
|
'streamlit.server',
|
|
'streamlit.runtime',
|
|
'streamlit.delta_generator',
|
|
'streamlit.elements.lib.mutable_status_container',
|
|
'streamlit.elements.lib.dialog',
|
|
'streamlit.elements.lib.column_config',
|
|
'streamlit.elements.lib.metrics',
|
|
'streamlit.elements.lib.toast',
|
|
'streamlit.elements.lib.chat_message',
|
|
'streamlit.elements.lib.experimental_connection',
|
|
'streamlit.elements.lib.experimental_data_editor',
|
|
'streamlit.elements.lib.experimental_fragment',
|
|
'streamlit.elements.lib.experimental_get_query_params',
|
|
'streamlit.elements.lib.experimental_set_query_params',
|
|
'streamlit.elements.lib.experimental_user',
|
|
'streamlit.elements.lib.form_submit_button',
|
|
'streamlit.elements.lib.media',
|
|
'streamlit.elements.lib.progress',
|
|
'streamlit.elements.lib.snow',
|
|
'streamlit.elements.lib.spinner',
|
|
'streamlit.elements.lib.status',
|
|
'streamlit.elements.lib.tabs',
|
|
'streamlit.elements.lib.toast',
|
|
'streamlit.elements.lib.toggle',
|
|
'streamlit.elements.lib.tooltip',
|
|
'streamlit.elements.lib.widgets',
|
|
'openai',
|
|
'dotenv',
|
|
'requests',
|
|
'urllib3',
|
|
'certifi',
|
|
'charset_normalizer',
|
|
'idna',
|
|
'yaml',
|
|
'toml',
|
|
'PIL',
|
|
'numpy',
|
|
'pandas',
|
|
'altair',
|
|
'plotly',
|
|
'pydeck',
|
|
'bokeh',
|
|
'graphviz',
|
|
'keras',
|
|
'seaborn',
|
|
'sympy',
|
|
'streamlit_ace',
|
|
'streamlit_option_menu'
|
|
],
|
|
hookspath=[],
|
|
hooksconfig={},
|
|
runtime_hooks=[],
|
|
excludes=[],
|
|
win_no_prefer_redirects=False,
|
|
win_private_assemblies=False,
|
|
cipher=block_cipher,
|
|
noarchive=False,
|
|
)
|
|
|
|
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
|
|
|
exe = EXE(
|
|
pyz,
|
|
a.scripts,
|
|
a.binaries,
|
|
a.zipfiles,
|
|
a.datas,
|
|
[],
|
|
name='multi_agent_decision_workshop',
|
|
debug=False,
|
|
bootloader_ignore_signals=False,
|
|
strip=False,
|
|
upx=True,
|
|
console=False, # 设置为False以隐藏控制台窗口
|
|
disable_windowed_traceback=False,
|
|
argv_emulation=False,
|
|
target_arch=None,
|
|
codesign_identity=None,
|
|
entitlements_file=None,
|
|
)
|
|
'''
|
|
|
|
with open('app.spec', 'w', encoding='utf-8') as f:
|
|
f.write(spec_content)
|
|
print("✅ spec文件创建成功")
|
|
|
|
def build_exe():
|
|
"""构建exe文件"""
|
|
print("开始构建exe文件...")
|
|
try:
|
|
# 使用spec文件构建
|
|
subprocess.check_call([sys.executable, "-m", "PyInstaller", "app.spec", "--clean"])
|
|
print("✅ exe文件构建成功")
|
|
|
|
# 检查生成的文件
|
|
dist_dir = "dist"
|
|
if os.path.exists(dist_dir):
|
|
exe_path = os.path.join(dist_dir, "multi_agent_decision_workshop.exe")
|
|
if os.path.exists(exe_path):
|
|
file_size = os.path.getsize(exe_path) / (1024 * 1024) # MB
|
|
print(f"📦 生成的exe文件: {exe_path}")
|
|
print(f"📊 文件大小: {file_size:.2f} MB")
|
|
return True
|
|
|
|
print("❌ exe文件生成失败")
|
|
return False
|
|
|
|
except subprocess.CalledProcessError as e:
|
|
print(f"❌ 构建失败: {e}")
|
|
return False
|
|
|
|
def create_launcher_bat():
|
|
"""创建启动批处理文件"""
|
|
bat_content = '''@echo off
|
|
echo 正在启动多Agent决策工作坊...
|
|
echo.
|
|
|
|
cd /d "%~dp0"
|
|
|
|
if exist "multi_agent_decision_workshop.exe" (
|
|
echo 启动应用程序...
|
|
start "" "multi_agent_decision_workshop.exe"
|
|
echo 应用程序已启动,请在浏览器中打开 http://localhost:8501
|
|
echo 按任意键退出...
|
|
pause >nul
|
|
) else (
|
|
echo 错误:未找到 multi_agent_decision_workshop.exe
|
|
echo 请确保此文件与exe文件在同一目录
|
|
pause
|
|
)
|
|
'''
|
|
|
|
with open('启动程序.bat', 'w', encoding='gbk') as f:
|
|
f.write(bat_content)
|
|
print("✅ 启动批处理文件创建成功")
|
|
|
|
def main():
|
|
"""主函数"""
|
|
print("🚀 开始打包多Agent决策工作坊应用...")
|
|
print("=" * 50)
|
|
|
|
# 检查当前目录
|
|
if not os.path.exists('app.py'):
|
|
print("❌ 错误:请在项目根目录运行此脚本")
|
|
return
|
|
|
|
# 安装PyInstaller
|
|
if not install_pyinstaller():
|
|
return
|
|
|
|
# 创建spec文件
|
|
create_spec_file()
|
|
|
|
# 构建exe
|
|
if build_exe():
|
|
# 复制必要的文件到dist目录
|
|
dist_dir = "dist"
|
|
if os.path.exists(dist_dir):
|
|
# 复制.env文件
|
|
if os.path.exists('.env'):
|
|
shutil.copy2('.env', os.path.join(dist_dir, '.env'))
|
|
|
|
# 创建启动批处理文件
|
|
os.chdir(dist_dir)
|
|
create_launcher_bat()
|
|
|
|
print("\n🎉 打包完成!")
|
|
print("📁 生成的文件在 'dist' 目录中")
|
|
print("🚀 双击 '启动程序.bat' 即可运行应用")
|
|
print("🌐 然后在浏览器中打开 http://localhost:8501")
|
|
else:
|
|
print("❌ dist目录不存在")
|
|
else:
|
|
print("❌ 打包失败")
|
|
|
|
if __name__ == "__main__":
|
|
main() |