AutoPercenty3/setup_paddle.py

431 lines
20 KiB
Python

# import sys
# log_file = open("setup.log", "a", encoding="utf-8")
# class LoggerWriter:
# def __init__(self, stream, log_file):
# self.stream = stream
# self.log_file = log_file
# def write(self, message):
# self.stream.write(message)
# self.log_file.write(message)
# def flush(self):
# self.stream.flush()
# self.log_file.flush()
# sys.stdout = LoggerWriter(sys.stdout, log_file)
# sys.stderr = LoggerWriter(sys.stderr, log_file)# setup.py
import sys, os
from cx_Freeze import setup, Executable
# from PySide6 import QtCore
# import ssl
from setuptools import find_packages
from updateManager.__version__ import (
__title__, __version__, __description__, __author__,
__author_email__, __license__, __install_requires__,
__exe_name__, __icon_file__, __main_script__,
__file_log_level__, __gui_log_level__
)
import subprocess
from setuptools.command.build_ext import build_ext
from setuptools.command.install import install
from cx_Freeze.command.build_exe import build_exe as _build_exe
import importlib.util
import logging
# 패들 코어 패치 적용 (ONNX 사용으로 비활성화)
print("패들 코어 패치 검사 및 적용...")
try:
import patch_paddle_core
patch_paddle_core.patch_paddle_core()
except Exception as e:
print(f"패들 코어 패치 적용 중 오류 발생: {e}")
print("패치 실패, 빌드 계속 진행합니다.")
# 필요한 파일 경로 설정
base_dir = os.path.dirname(__file__)
browsers_dir = os.path.join(base_dir, 'src', 'browsers')
chromium_dir = os.path.join(browsers_dir, 'src', 'browsers', 'chromium-1155')
# whale_dir = os.path.join(browsers_dir, 'src', 'browsers', 'whale')
extensions_dir = os.path.join(browsers_dir, 'src', 'browsers', 'extensions')
# user_data_dir = os.path.join(browsers_dir, 'src', 'browsers', 'user_data')
updater_file = os.path.join(base_dir, 'updateManager', 'updater.exe')
# include_files = [
# os.path.abspath('config.ini'),
# os.path.abspath('prompt.json'),
# os.path.abspath('userDB.db'),
# os.path.abspath('HakgyoansimDunggeunmisoTTFB.ttf'),
# (os.path.abspath('src/initialDB.db'), 'src/initialDB.db'),
# (os.path.abspath('src/Percenty_SS_Code.json'), 'src/Percenty_SS_Code.json'),
# (os.path.abspath(chromium_dir), 'browsers/chromium-1155'),
# (os.path.abspath(whale_dir), 'browsers/whale'),
# (os.path.abspath(extensions_dir), 'browsers/extensions'),
# (os.path.abspath(user_data_dir), 'browsers/user_data'),
# ]
# PySide6 DLL 경로 추가
# pyside6_path = os.path.join(os.path.dirname(sys.executable), "Lib", "site-packages", "PySide6")
# pyside6_plugins_path = os.path.join(pyside6_path, "plugins")
# pyside6_bin_path = pyside6_path # 'bin' 폴더가 없으면 기본 경로 사용
dll_files = [
# "LIBPQ.dll",
# "MIMAPI64.dll",
# "Qt63DQuickScene3D.dll",
"api-ms-win-core-com-l1-1-0.dll",
"api-ms-win-core-debug-l1-1-0.dll",
"api-ms-win-core-errorhandling-l1-1-0.dll",
"api-ms-win-core-handle-l1-1-0.dll",
"api-ms-win-core-heap-l1-1-0.dll",
# "api-ms-win-core-heap-l2-1-0.dll",
"api-ms-win-core-interlocked-l1-1-0.dll",
# "api-ms-win-core-libraryloader-l1-2-0.dll",
# "api-ms-win-core-libraryloader-l1-2-1.dll",
"api-ms-win-core-localization-l1-2-0.dll",
# "api-ms-win-core-path-l1-1-0.dll",
"api-ms-win-core-processthreads-l1-1-0.dll",
"api-ms-win-core-processthreads-l1-1-1.dll",
"api-ms-win-core-profile-l1-1-0.dll",
# "api-ms-win-core-realtime-l1-1-1.dll",
"api-ms-win-core-rtlsupport-l1-1-0.dll",
"api-ms-win-core-synch-l1-1-0.dll",
"api-ms-win-core-synch-l1-2-0.dll",
"api-ms-win-core-sysinfo-l1-1-0.dll",
# "api-ms-win-core-winrt-error-l1-1-0.dll",
# "api-ms-win-core-winrt-l1-1-0.dll",
# "api-ms-win-core-winrt-string-l1-1-0.dll",
"api-ms-win-crt-conio-l1-1-0.dll",
"api-ms-win-crt-environment-l1-1-0.dll",
"api-ms-win-crt-filesystem-l1-1-0.dll",
"api-ms-win-crt-multibyte-l1-1-0.dll",
"api-ms-win-crt-private-l1-1-0.dll",
"api-ms-win-crt-process-l1-1-0.dll",
"api-ms-win-crt-time-l1-1-0.dll",
"api-ms-win-crt-utility-l1-1-0.dll",
# "api-ms-win-power-base-l1-1-0.dll",
# "api-ms-win-power-setting-l1-1-0.dll",
# "api-ms-win-shcore-scaling-l1-1-1.dll",
]
# ✅ DLL 경로 설정 (Windows 10의 System32에서 가져오기)
system32_path = "C:/Windows/System32/downlevel"
dll_include_files = [(os.path.join(system32_path, dll), dll) for dll in dll_files]
dll_include_files = [] # 충돌 가능성으로 인해 빈 리스트로 초기화
# 패들 라이브러리 경로 설정 (ONNX 사용으로 비활성화)
# 경로 수정: scripts/Lib -> Lib로 변경
base_path = os.path.dirname(os.path.abspath(__file__))
site_packages = os.path.join(base_path, "Lib", "site-packages")
# 올바른 경로 지정 (PaddlePaddle 비활성화)
paddle_path = os.path.join(site_packages, "paddle")
paddleocr_path = os.path.join(site_packages, "paddleocr")
paddle_includes = []
onnxruntime_includes = []
# NumPy .libs 경로 포함 (OpenBLAS 등 의존 DLL 로딩 문제 해결)
numpy_includes = []
bin_path_includes_extra = []
numpy_libs_path = os.path.join(site_packages, "numpy.libs")
if os.path.exists(numpy_libs_path):
numpy_includes.append((numpy_libs_path, 'lib/numpy.libs'))
bin_path_includes_extra.append(numpy_libs_path)
print(f"numpy .libs 경로 추가: {numpy_libs_path}")
# OpenCV(cv2) 패키지 폴더 포함 (config.py 누락 방지)
cv2_includes = []
cv2_path = os.path.join(site_packages, 'cv2')
if os.path.exists(cv2_path):
cv2_includes.append((cv2_path, 'lib/cv2'))
bin_path_includes_extra.append(cv2_path)
print(f"cv2 경로 추가: {cv2_path}")
# Shapely .libs (GEOS) 포함
shapely_includes = []
shapely_libs_path = os.path.join(site_packages, 'shapely.libs')
if os.path.exists(shapely_libs_path):
shapely_includes.append((shapely_libs_path, 'lib/shapely.libs'))
bin_path_includes_extra.append(shapely_libs_path)
print(f"shapely.libs 경로 추가: {shapely_libs_path}")
# Pandas .libs 포함
pandas_includes = []
pandas_libs_path = os.path.join(site_packages, 'pandas.libs')
if os.path.exists(pandas_libs_path):
pandas_includes.append((pandas_libs_path, 'lib/pandas.libs'))
bin_path_includes_extra.append(pandas_libs_path)
print(f"pandas.libs 경로 추가: {pandas_libs_path}")
# 경로가 존재하는 경우에만 포함 (PaddlePaddle 비활성화)
if os.path.exists(paddle_path):
paddle_includes.append((paddle_path, 'lib/paddle'))
print(f"paddle 경로 추가: {paddle_path}")
if os.path.exists(paddleocr_path):
paddle_includes.append((paddleocr_path, 'lib/paddleocr'))
print(f"paddleocr 경로 추가: {paddleocr_path}")
# ONNXRuntime DirectML 관련 파일들 포함
onnxruntime_path = os.path.join(site_packages, 'onnxruntime')
onnxruntime_capi = os.path.join(onnxruntime_path, 'capi')
if os.path.exists(onnxruntime_capi):
onnxruntime_includes.append((onnxruntime_capi, 'lib/onnxruntime/capi'))
print(f"onnxruntime capi 경로 추가: {onnxruntime_capi}")
# ONNXRuntime GPU 전체 패키지 포함
if os.path.exists(onnxruntime_path):
onnxruntime_includes.append((onnxruntime_path, 'lib/onnxruntime'))
print(f"onnxruntime 전체 경로 추가: {onnxruntime_path}")
vc_runtime_files = [
('C:/Windows/System32/vcruntime140.dll', 'vcruntime140.dll'),
('C:/Windows/System32/vcruntime140_1.dll', 'vcruntime140_1.dll'),
('C:/Windows/System32/msvcp140.dll', 'msvcp140.dll'),
('C:/Windows/System32/msvcp140_1.dll', 'msvcp140_1.dll'),
('C:/Windows/System32/msvcp140_2.dll', 'msvcp140_2.dll'),
('C:/Windows/System32/concrt140.dll', 'concrt140.dll'),
('C:/Windows/System32/vcomp140.dll', 'vcomp140.dll'),
]
# DirectML 사용: Windows GPU 가속을 위해 DirectML 기반 ONNXRuntime 사용
# ✅ 기존 포함 파일 + DLL 추가
include_files = dll_include_files + paddle_includes + onnxruntime_includes + vc_runtime_files + [
# 나머지 파일들
('src/ppocr/PP_Models', 'lib/src/ppocr/PP_Models'),
('src/Edit_PartTimer3.ico', 'lib/src/Edit_PartTimer3.ico'), # 아이콘 파일 경로 수정
('win.exe.manifest', 'win.exe.manifest'),
('libssl-3-x64.dll', 'libssl-3-x64.dll'),
('libcrypto-3-x64.dll', 'libcrypto-3-x64.dll'),
('kiprisCategories.json', 'kiprisCategories.json'),
('src/keyword/kiprisCategories.json', 'lib/src/keyword/kiprisCategories.json'),
('src/modules/fonts/Cafe24Ohsquare-v2.0.ttf', 'lib/src/fonts/Cafe24Ohsquare-v2.0.ttf'),
('src/modules/fonts/gamtanload.ttf', 'lib/src/fonts/gamtanload.ttf'),
('src/modules/fonts/NanumBarunGothic.ttf', 'lib/src/fonts/NanumBarunGothic.ttf'),
('src/modules/fonts/NanumSquareRoundR.ttf', 'lib/src/fonts/NanumSquareRoundR.ttf'),
('src/modules/fonts/HakgyoansimDunggeunmisoTTFB.ttf', 'lib/src/fonts/HakgyoansimDunggeunmisoTTFB.ttf'),
('src/modules/fonts/Cafe24Ohsquare-v2.0.ttf', 'lib/src/modules/fonts/Cafe24Ohsquare-v2.0.ttf'),
('src/modules/fonts/gamtanload.ttf', 'lib/src/modules/fonts/gamtanload.ttf'),
('src/modules/fonts/NanumBarunGothic.ttf', 'lib/src/modules/fonts/NanumBarunGothic.ttf'),
('src/modules/fonts/NanumSquareRoundR.ttf', 'lib/src/modules/fonts/NanumSquareRoundR.ttf'),
('src/modules/fonts/HakgyoansimDunggeunmisoTTFB.ttf', 'lib/src/modules/fonts/HakgyoansimDunggeunmisoTTFB.ttf'),
('src/modules/migan_onnx/migan_pipeline_v2.onnx', 'lib/src/modules/migan_onnx/migan_onnx/migan_pipeline_v2.onnx'),
(updater_file, 'updater.exe'),
# ONNX OCR 모듈 파일들 포함
('src/modules/onnx_ocr_module', 'lib/src/modules/onnx_ocr_module'),
('퍼센티 다양한 카테고리 엑셀 수집(스스 기준).xlsx', '퍼센티 다양한 카테고리 엑셀 수집(스스 기준).xlsx'),
('src/Percenty_SS_Code.json', 'lib/src/Percenty_SS_Code.json'),
('src/browsers/chromium-1155', 'lib/src/browsers/chromium-1155'),
# ('src/browsers/whale', 'lib/src/browsers/whale'),
('src/browsers/extensions', 'lib/src/browsers/extensions'),
# ('src/browsers/user_data', 'lib/src/browsers/user_data'),
# ('src/browsers/whale/user_data', 'lib/src/browsers/whale/user_data'),
# (pyside6_bin_path, "PySide6"), # PySide6 DLL 파일 경로
# (pyside6_plugins_path, "PySide6/plugins"), # plugins 경로 추가
('C:/Windows/System32/vcomp140.dll', 'vcomp140.dll'),
]
for src, dest in include_files:
if not os.path.exists(src):
print(f"경로가 존재하지 않습니다: {src}")
# 사용된 패키지 정의
build_exe_options = {
'include_msvcr': True, # VC++ 런타임 자동 포함
'packages': [
'ctypes', 'asyncio',
'subprocess', 'pyperclip', 'numpy',
'cv2', 'requests', 'pyclipper', 'skimage',
'PIL', 'bs4', 'PySide6', 'psutil',
# 'win32api', 'win32file', 'win32pipe', 'win32event', 'pywintypes', 'win32con', 'win32process', 'win32clipboard', 'win32gui',
'pandas', 'supabase', 'translatepy', 'markdown',
# supabase 전체 생태계 패키지들 (모든 하위 모듈 자동 포함)
'supabase', 'gotrue', 'storage3', 'postgrest', 'supafunc', 'realtime',
# pydantic 생태계 (전체 포함)
'pydantic', 'pydantic_core',
# json 모듈 순환 import 문제 해결
'json', 'json.encoder', 'json.decoder', 'json.scanner',
# httpx 의존성 모듈들 추가
'httpx', 'httpx.__version__', 'httpx._models', 'httpx._client', 'httpx._config',
# idna 모듈 (URL 인코딩) 추가
'idna', 'idna.core', 'idna.idnadata', 'idna.package_data',
'paddle', 'paddleocr', # paddle 관련 모듈 포함
'onnxruntime', # DirectML 지원 ONNXRuntime 추가
# numpy/scipy 관련 패키지 (기본 지원)
'scipy', 'scipy.special', 'scipy.sparse', 'scipy.linalg', 'scipy.ndimage',
'supabase', 'gotrue', 'storage3', 'postgrest', 'supafunc', 'realtime',
'websockets','shapely',
'anyio', 'sniffio', 'h11', 'certifi', 'pydantic_core', # realtime/httpx 계열 런타임 의존성
],
'includes': [
# 'PySide6.QtWidgets', 'PySide6.QtCore', 'PySide6.QtGui',
'shiboken6','playwright','comtypes.stream', 'win32com.client', 'win32com.server', 'pythoncom',
'loggerModule', 'toggleSwitch', 'src.modules.request_inpaint', 'onnxruntime',
'browser_control', 'locatorManager', 'src.cmdDiag', 'src.inputDiag', 'src.keyword', 'src.priceSetDiag', 'src.modules.image_processor3',
'src.modules.gpu_utils', 'src.modules.migan_module', 'src.modules.background_removal_module', # 새로 추가된 GPU 관련 모듈들
'src.modules.ocr_module', # PaddleOCR 모듈 활성화
'src.modules.gpu_status_checker', 'src.gpuDiag',
# 누락된 중요 모듈들 추가
'src.modules.postImageManager', 'src.modules.mask_module_for_paddle', 'src.modules.text_rendering_module',
'src.modules.onnx_ocr_module', 'src.modules.onnx_ocr_module.src.onnx_ocr_wrapper', # ONNX OCR 모듈 추가
'src.modules.image_worker', # OCR backends는 ONNX 모듈로 대체
'src.modules.gemma_client',
# 'src.modules.ocr_backends', 'src.modules.ocr_backends.fastdeploy_ocr', 'src.modules.ocr_backends.onnx_ocr', # 개별 백엔드 비활성화
'translatepy', 'translatepy.translators', 'translatepy.translators.google',
# supabase 전체 생태계를 includes에도 추가
'supabase', 'gotrue', 'storage3', 'postgrest', 'supafunc', 'realtime',
# pydantic 생태계를 includes에도 추가
'pydantic', 'pydantic_core',
# json 순환 import 문제 해결을 위한 명시적 포함
'json', 'json.encoder', 'json.decoder', 'json.scanner',
# httpx 의존성 모듈들을 includes에도 추가
'httpx', 'httpx.__version__', 'httpx._models', 'httpx._client', 'httpx._config',
# idna 모듈을 includes에도 추가
'idna', 'idna.core', 'idna.idnadata', 'idna.package_data',
# pathlib 명시적 포함 (PySide6에서 필요)
'pathlib',
'skimage', 'skimage.morphology', 'skimage.measure', 'skimage.filters', 'skimage.color', 'skimage.util', 'imghdr', 'imgaug', 'rapidfuzz',
'albumentations', 'albumentations', 'cython', 'fire', 'lmdb', 'PIL', 'docx', 'yaml', 'shapely', 'tqdm',
# PIL과 관련된 추가 모듈들
'PIL.Image', 'PIL.ImageFont', 'PIL.ImageDraw', 'PIL.features',
],
'include_files': include_files,
'excludes': [
'tkinter', 'PyQt4', 'PyQt5', 'AppKit', 'Foundation', 'IPython',
'OpenSSL', 'curses', 'test', 'matplotlib', 'asyncpg',
# # 순환 import 문제 해결을 위한 주요 모듈들 제외
# 'unittest', 'unittest.case', 'unittest.loader', 'unittest.suite',
# 'unittest.runner', 'unittest.signals', 'unittest._log', 'unittest.util',
# 'unittest.async_case', # asyncio와 unittest 연결 모듈 제외
# 실제 순환 import 원인인 테스트 관련 모듈들 제외
# 'numpy._pytesttester', 'numpy.testing', 'scipy._lib._testutils',
# importlib 관련 - metadata는 pydantic에서 필요하므로 제외하지 않음
'importlib._bootstrap', 'importlib.machinery',
# shiboken6 순환 참조 문제 해결
# 'shiboken6.Shiboken', 'shiboken6.libshiboken',
# 기타 순환 참조 관련 모듈들
# 'pkg_resources', 'setuptools', 'wheel', 'pip',
# 개발/테스트 도구들 제외
'pytest', 'hypothesis', 'mypy', 'coverage', 'tox',
'sympy', # ★ 가장 중요
'sympy.core',
'sympy.ntheory',
'sympy.external',
'sympy.polys',
'sympy.*', # 와일드카드가 버전에 따라 안 먹을 수 있어도 넣어두면 좋음
'mpmath',
'gmpy2',
],
'zip_include_packages': [], # 아무 패키지도 압축하지 않음 (numpy 관련 문제 해결)
'optimize': 0, # 바이트 코드 최적화 비활성화 (numpy/scipy 호환성 보장)
'silent': True, # 디버그 메시지 활성화
# numpy 바이너리 파일 강제 포함
'include_msvcr': True, # VC++ 런타임 포함
'bin_path_includes': bin_path_includes_extra,
}
# 애플리케이션 메인 파일 및 설정
base = None
if sys.platform == 'win32':
base = 'Win32GUI'
# ✅ 아이콘 지정: icon='파일경로.ico'
executables = [
Executable(
'main.py',
base=base,
target_name='Edit_PartTimer3.exe',
icon="Edit_PartTimer3.ico"
)
]
# build_exe 클래스를 확장하여 빌드 전 의존성 체크 및 빌드 후 iss 파일 생성
class build_exe(_build_exe):
def run(self):
# 빌드 전 의존성 체크 및 수정
print("\n[도구] 빌드 전 의존성 체크 시작...")
try:
result = subprocess.run([sys.executable, "check_dependencies.py"], capture_output=True, text=True)
if result.returncode == 0:
print("[성공] 의존성 체크 완료")
print(result.stdout)
else:
print("[실패] 의존성 체크 실패:")
print(result.stdout)
print(result.stderr)
print("\n[경고] 의존성 문제로 인해 빌드를 중단합니다.")
return
except Exception as e:
print(f"[오류] 의존성 체크 중 예외 발생: {e}")
print("[경고] 의존성 체크를 건너뛰고 빌드를 계속합니다.")
# # 빌드 전에 로그 레벨을 INFO로 변경
# self._set_log_level_for_production()
# 원래 빌드 프로세스 실행
_build_exe.run(self)
print("\n빌드가 완료되었습니다. 이제 Inno Setup 스크립트 생성을 시작합니다...\n")
try:
# generate_iss.py 스크립트 실행
result = subprocess.run([sys.executable, "generate_iss.py"], capture_output=True, text=True)
if result.returncode == 0:
print(result.stdout)
print("\nInno Setup 스크립트 생성이 완료되었습니다!")
else:
print(f"Inno Setup 스크립트 생성 중 오류 발생: {result.stderr}")
except Exception as e:
print(f"Inno Setup 스크립트 생성 중 예외 발생: {e}")
# def _set_log_level_for_production(self):
# """패키징 시 로그 레벨을 INFO로 설정합니다"""
# version_file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'updateManager', '__version__.py')
# # 파일 내용 읽기
# with open(version_file_path, 'r', encoding='utf-8') as f:
# content = f.read()
# # DEBUG를 INFO로 변경
# if 'logging.DEBUG' in content:
# content = content.replace('__log_level__ = logging.DEBUG', '__log_level__ = logging.INFO')
# # 변경된 내용 저장
# with open(version_file_path, 'w', encoding='utf-8') as f:
# f.write(content)
# print("로그 레벨이 배포 버전에 맞게 INFO로 변경되었습니다.")
if __name__ == '__main__':
# Setup 설정 (cmdclass에 build_exe 추가)
setup(
name=__title__,
version=__version__,
description=__description__,
author=__author__,
author_email=__author_email__,
license=__license__,
packages=find_packages(),
install_requires=__install_requires__,
python_requires='>=3.11',
include_package_data=True,
zip_safe=False,
options={'build_exe': build_exe_options},
executables=executables,
cmdclass={
"build_exe": build_exe,
},
)