Files
ai-g3sb-backman2.0/main.spec
T

270 lines
7.7 KiB
RPMSpec
Raw Normal View History

2026-04-14 17:07:08 +08:00
# -*- mode: python ; coding: utf-8 -*-
import os
from pathlib import Path
from PyInstaller.utils.hooks import collect_data_files, collect_submodules, collect_dynamic_libs
2026-04-14 17:07:08 +08:00
# 获取项目根目录(spec 文件所在目录)
import sys
_REPO_DIR = Path(os.getcwd()).resolve()
2026-04-15 13:07:39 +08:00
def _strip_msvc_runtime_binaries(bin_list):
"""
从 ``collect_dynamic_libs`` 等额外收集的 binaries 中移除 MSVC 运行库 DLL。
chromadb / hnswlib 等 wheel 常自带 ``MSVCP140.dll`` 等;与 PyInstaller 已为
``python.exe`` 解析到的 CRT 一并打入单文件包时,易在运行期混用多份 CRT
导致 ``MSVCP140.dll`` 内 ``0xc0000005``。统一依赖解释器自带的 CRT 集更安全。
"""
skip = frozenset({
'msvcp140.dll',
'msvcp140_1.dll',
'msvcp140_2.dll',
'msvcp140_atomic_wait.dll',
'msvcp140_codecvt_ids.dll',
'vcruntime140.dll',
'vcruntime140_1.dll',
'concrt140.dll',
})
out = []
for item in bin_list:
dest = item[0]
base = Path(dest).name.lower()
if base in skip:
continue
out.append(item)
return out
2026-04-14 17:07:08 +08:00
# 根目录执行:pyinstaller --clean main.spec
#
# ---------------------------------------------------------------------------
# 向量「数据库文件」/ 业务数据 —— 明确不打入 onefile EXE
# ---------------------------------------------------------------------------
# 下列目录为运行时读写或外置分发的数据,禁止加入下方 ``datas``(勿取消注释):
# - Schema 侧:环境变量 VECTOR_DB_PATH(默认如 ./data/embeddings/chroma)
# - Few-shot 侧:FEWSHOT_CHROMA_PATH(默认如 ./data/embeddings/chroma_fewshot)
# 部署:将上述目录放在 exe 同目录旁,或通过 .env 指向可写绝对路径。
# SchemaIndexer 默认使用 PersistentClient(VECTOR_DB_PATH);仅 SCHEMA_INDEXER_EPHEMERAL=true 时为内存索引。
# ---------------------------------------------------------------------------
# 可选:仅当需要把 Schema JSON 等打进包时再取消注释(向量库目录仍不要加)
2026-04-14 17:07:08 +08:00
datas = [
# ('.env', '.'),
# ('data/schemas', 'data/schemas'),
# 勿打包 data/embeddings、data/experiences(向量库与样本数据外置)
2026-04-14 17:07:08 +08:00
]
# Chroma **Python 包**在 Windows 单文件 exe 下如缺少 native 动态库,可能在初始化时直接退出
# 这里收集的是 chromadb / hnswlib 的 **wheel 内 DLL**,不是用户磁盘上的 Chroma 持久化目录
binaries = []
try:
binaries += collect_dynamic_libs("chromadb")
except Exception:
pass
try:
binaries += collect_dynamic_libs("hnswlib")
except Exception:
pass
# chromadb 包自带的非 Python 资源(如 migrations),非业务向量库文件
try:
datas += collect_data_files("chromadb")
except Exception:
pass
2026-04-15 13:07:39 +08:00
binaries = _strip_msvc_runtime_binaries(binaries)
def _dedupe_msvc_runtime_in_analysis_binaries(toc):
"""
对 ``Analysis`` 产出的 ``a.binaries`` 去重:同名 MSVC 运行库 DLL 只保留一份。
PyInstaller 会从 Python 安装目录、numpy、torch、chromadb 等多个依赖各自打入
同名 ``MSVCP140.dll`` 等;单文件解压到 ``_MEI*`` 后若出现多份或加载顺序混乱,
易在 ``MSVCP140.dll`` 内触发 ``0xc0000005``。优先保留 **源路径位于**
``sys.base_prefix`` 下的条目(与解释器主 CRT 一致)。
"""
vc_names = frozenset({
'msvcp140.dll',
'msvcp140_1.dll',
'msvcp140_2.dll',
'msvcp140_atomic_wait.dll',
'msvcp140_codecvt_ids.dll',
'vcruntime140.dll',
'vcruntime140_1.dll',
'concrt140.dll',
})
try:
base_root = str(Path(sys.base_prefix).resolve()).lower()
except OSError:
base_root = str(Path(sys.base_prefix)).lower()
rest = []
vc_groups = {}
for item in toc:
dest = item[0]
bname = Path(dest).name.lower()
if bname not in vc_names:
rest.append(item)
continue
vc_groups.setdefault(bname, []).append(item)
picked = []
for bname, items in vc_groups.items():
if len(items) == 1:
picked.append(items[0])
continue
def _score(it):
try:
sp = str(Path(it[1]).resolve()).lower()
except OSError:
sp = str(it[1]).lower()
under = 0 if sp.startswith(base_root) else 1
return (under, len(sp))
items_sorted = sorted(items, key=_score)
picked.append(items_sorted[0])
return rest + picked
2026-04-14 17:07:08 +08:00
# 收集所有需要的隐藏导入
hiddenimports = [
# Web 框架
'fastapi',
'fastapi.middleware.cors',
'fastapi.responses',
'uvicorn',
'uvicorn.lifespan.on',
'uvicorn.config',
'uvicorn.protocols.http.auto',
'uvicorn.protocols.websockets.auto',
'uvicorn.loops.auto',
2026-04-15 13:07:39 +08:00
2026-04-14 17:07:08 +08:00
# Backend 模块(重要!)
'main', # backend/main.py
'backend.main',
'backend.nl_lite_store',
'backend.agents',
'backend.agents.orchestrator',
'backend.agents.schema_linker',
'backend.agents.sql_generator',
'backend.agents.validator',
'backend.config',
'backend.config.prompts',
'backend.config.settings',
'backend.db',
'backend.db.engine',
'backend.db.dbhub_tools',
'backend.db.dbhub_sql_parser',
'backend.db.dbhub_allowed_keywords',
'backend.llm',
'backend.llm.deepseek_client',
'backend.schema',
'backend.schema.manager',
'backend.schema.loader',
'backend.schema.indexer',
'backend.schema.models',
'backend.utils',
'backend.utils.dialog_classifier',
'backend.utils.dialog_context',
2026-04-14 17:07:08 +08:00
'backend.utils.embedding',
'backend.utils.fewshot_selector',
'backend.utils.question_locale',
'backend.utils.sql_parser',
'backend.utils.validators',
2026-04-15 13:07:39 +08:00
2026-04-14 17:07:08 +08:00
# 数据库相关
'pymssql',
'sqlalchemy',
'sqlalchemy.dialects.mssql.pymssql',
'sqlalchemy.dialects.mysql',
'sqlalchemy.dialects.postgresql',
'sqlglot',
'sqlglot.dialects',
'sqlparse',
2026-04-15 13:07:39 +08:00
2026-04-14 17:07:08 +08:00
# 向量数据库 - 使用 collect_submodules 自动收集所有子模块
2026-04-15 13:07:39 +08:00
# Embedding 相关
'sentencepiece',
'accelerate',
'safetensors',
2026-04-14 17:07:08 +08:00
# LLM API
'openai',
2026-04-15 13:07:39 +08:00
2026-04-14 17:07:08 +08:00
# 数据处理
'numpy',
'jieba',
2026-04-15 13:07:39 +08:00
2026-04-14 17:07:08 +08:00
# Pydantic
'pydantic',
'pydantic_settings',
'dotenv',
2026-04-15 13:07:39 +08:00
2026-04-14 17:07:08 +08:00
# 工具库
'tenacity',
'structlog',
'tqdm',
'camel_ai',
2026-04-15 13:07:39 +08:00
2026-04-14 17:07:08 +08:00
# 标准库中可能被遗漏的
'email.mime.text',
'email.mime.multipart',
] + collect_submodules('chromadb')
# 排除不必要的模块以减小体积
excludes = [
'tkinter',
'matplotlib',
'scipy',
'pandas.tests',
'numpy.testing',
'jupyter',
'notebook',
'IPython',
'pytest',
]
a = Analysis(
['api_server.py'],
pathex=[str(_REPO_DIR)],
binaries=binaries,
2026-04-14 17:07:08 +08:00
datas=datas,
hiddenimports=hiddenimports,
hookspath=[],
hooksconfig={},
2026-04-15 13:07:39 +08:00
runtime_hooks=[str(_REPO_DIR / 'packaging' / 'pyi_rth_crt_path.py')],
2026-04-14 17:07:08 +08:00
excludes=excludes,
noarchive=False,
optimize=0,
)
2026-04-15 13:07:39 +08:00
# 去掉 Analysis 自动收集到的重复 MSVC 运行库(比仅过滤手动 binaries 更关键)
a.binaries = _dedupe_msvc_runtime_in_analysis_binaries(list(a.binaries))
2026-04-14 17:07:08 +08:00
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas, # 单文件:仅打包 spec 中 datas(chromadb 包资源等),不含业务向量持久化目录
2026-04-14 17:07:08 +08:00
[],
name='Backman_Text2SQL_Server',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False, # 禁用 UPX,避免兼容性问题
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)