This commit is contained in:
parent
806502d926
commit
1f89ffa3a7
|
|
@ -3,10 +3,11 @@ Lib/
|
|||
Scripts/
|
||||
__pycache__/
|
||||
build/
|
||||
dist/
|
||||
pyvenv.cfg
|
||||
*.log
|
||||
*.log.*
|
||||
*.pyc
|
||||
browsers/user_data
|
||||
browsers/whale/user_data
|
||||
browsers/whale/cache
|
||||
browsers/whale/cache
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import requests
|
|||
import numpy as np
|
||||
import cv2
|
||||
import time
|
||||
import os
|
||||
import os, sys
|
||||
from datetime import datetime
|
||||
import random
|
||||
import pywinauto
|
||||
|
|
@ -18,13 +18,25 @@ class ClipboardImageManager:
|
|||
self.debug = debug_flag # 디버그 플래그를 클래스 변수로 사용
|
||||
|
||||
# 프로그램이 위치한 경로 기준으로 폰트 경로 설정
|
||||
self.font_path = os.path.join(os.path.dirname(__file__), 'src', 'font', 'HakgyoansimDunggeunmisoTTFB.ttf')
|
||||
self.base_path = self.get_base_dir()
|
||||
self.font_path = os.path.join(self.base_path, 'src', 'font', 'HakgyoansimDunggeunmisoTTFB.ttf')
|
||||
|
||||
# 폰트 로드
|
||||
self.font = ImageFont.truetype(self.font_path, watermark_font_size)
|
||||
|
||||
# self.debug = True
|
||||
|
||||
def get_base_dir(self):
|
||||
"""
|
||||
실행 환경에 따라 base_dir을 설정하는 메서드.
|
||||
cx_Freeze로 패키징된 경우 실행 파일의 경로, 일반 Python 환경일 경우 __file__을 기준으로 설정.
|
||||
"""
|
||||
if getattr(sys, 'frozen', False): # 패키징된 경우
|
||||
base_dir = os.path.dirname(sys.executable)
|
||||
else: # 일반 Python 실행 환경
|
||||
base_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
return base_dir
|
||||
|
||||
def get_clipboard_data(self):
|
||||
"""클립보드의 텍스트 또는 이미지 데이터를 가져옵니다."""
|
||||
self.logger.debug("클립보드의 텍스트 또는 이미지 데이터를 가져옵니다")
|
||||
|
|
|
|||
15
gui.py
15
gui.py
|
|
@ -107,9 +107,6 @@ class AutoPercentyGUI(QWidget):
|
|||
# 이전에 저장된 설정 불러오기
|
||||
self.load_settings()
|
||||
|
||||
# 로거 초기화
|
||||
self.add_text_edit_logger()
|
||||
|
||||
# 프로그래스바 초기화
|
||||
self.update_total_progress(0,0)
|
||||
|
||||
|
|
@ -142,17 +139,7 @@ class AutoPercentyGUI(QWidget):
|
|||
except Exception as e:
|
||||
self.logger.error(f"DB 파일 복사 중 오류 발생: {e}", exc_info=True)
|
||||
raise e
|
||||
|
||||
def add_text_edit_logger(self):
|
||||
"""QTextEdit에 로그를 출력하기 위한 핸들러 추가"""
|
||||
text_edit_logger = QTextEditLogger()
|
||||
text_edit_logger.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
|
||||
# text_edit_logger.appendHtml.connect(self.log.appendHtml)
|
||||
text_edit_logger.appendHtml.connect(self.log.append) # appendHtml 대신 append로 수정
|
||||
text_edit_logger.scrollToBottom.connect(lambda: self.log.verticalScrollBar().setValue(self.log.verticalScrollBar().maximum()))
|
||||
self.logger.addHandler(text_edit_logger)
|
||||
self.logger.debug('로그기록이 설정되었습니다.')
|
||||
|
||||
|
||||
def start_stage(self, stage_index):
|
||||
"""지정한 단계에 깜빡임 효과 적용"""
|
||||
if 0 <= stage_index < len(self.stage_labels):
|
||||
|
|
|
|||
101
logger_module.py
101
logger_module.py
|
|
@ -1,7 +1,8 @@
|
|||
import logging
|
||||
import os
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from PyQt5.QtCore import pyqtSignal, QObject
|
||||
from PySide6.QtCore import Signal, QObject # PyQt5.QtCore.pyqtSignal -> PySide6.QtCore.Signal
|
||||
from PySide6.QtWidgets import QTextEdit
|
||||
|
||||
def setup_logger(name, log_file, level=logging.DEBUG, max_bytes=20*1024*1024, backup_count=5):
|
||||
"""로거 설정을 위한 함수"""
|
||||
|
|
@ -23,34 +24,84 @@ def setup_logger(name, log_file, level=logging.DEBUG, max_bytes=20*1024*1024, ba
|
|||
logger.addHandler(console_handler)
|
||||
|
||||
return logger
|
||||
|
||||
class QTextEditLogger(logging.Handler, QObject):
|
||||
appendHtml = pyqtSignal(str) # HTML 메시지를 전달할 시그널 정의
|
||||
scrollToBottom = pyqtSignal() # 스크롤을 최하단으로 이동시키는 시그널
|
||||
"""
|
||||
PySide6 QTextEdit와 연동하여 로그 메시지를 출력하는 로깅 핸들러.
|
||||
"""
|
||||
appendHtml = Signal(str) # HTML 메시지를 전달하는 시그널
|
||||
scrollToBottom = Signal() # 텍스트 영역의 스크롤을 최하단으로 이동시키는 시그널
|
||||
|
||||
def __init__(self):
|
||||
logging.Handler.__init__(self)
|
||||
QObject.__init__(self)
|
||||
def __init__(self, text_edit):
|
||||
"""
|
||||
QTextEditLogger 초기화.
|
||||
:param text_edit: 로그 메시지를 표시할 QTextEdit 위젯
|
||||
"""
|
||||
QObject.__init__(self) # QObject 초기화
|
||||
logging.Handler.__init__(self) # logging.Handler 초기화
|
||||
self.text_edit = text_edit # 로그를 출력할 QTextEdit 위젯
|
||||
|
||||
# 시그널 연결
|
||||
self.appendHtml.connect(self.text_edit.append)
|
||||
self.scrollToBottom.connect(self.scroll_to_bottom)
|
||||
|
||||
def emit(self, record):
|
||||
msg = self.format(record) # 로그 레코드를 문자열로 포매팅
|
||||
|
||||
color = {
|
||||
logging.DEBUG: "black",
|
||||
logging.INFO: "grey",
|
||||
logging.WARNING: "orange",
|
||||
logging.ERROR: "red",
|
||||
logging.CRITICAL: "purple",
|
||||
}.get(record.levelno, "black")
|
||||
|
||||
# HTML 스타일을 적용한 메시지 생성
|
||||
message = f"<span style=\"color:{color};\">{msg}</span><br/>"
|
||||
self.appendHtml.emit(message) # HTML 메시지로 변경
|
||||
self.scrollToBottom.emit() # 스크롤 시그널 발생
|
||||
|
||||
"""
|
||||
로그 레코드를 처리하고 QTextEdit에 출력.
|
||||
:param record: 로그 레코드 (LogRecord 객체)
|
||||
"""
|
||||
try:
|
||||
if not hasattr(record, "getMessage"):
|
||||
raise ValueError(f"Invalid LogRecord: {record}")
|
||||
|
||||
# 로그 레코드를 문자열로 포매팅
|
||||
msg = self.format(record) # format(record)는 getMessage를 호출
|
||||
color = {
|
||||
logging.DEBUG: "black",
|
||||
logging.INFO: "grey",
|
||||
logging.WARNING: "orange",
|
||||
logging.ERROR: "red",
|
||||
logging.CRITICAL: "purple",
|
||||
}.get(record.levelno, "black")
|
||||
|
||||
# HTML 스타일 적용한 메시지 생성
|
||||
html_message = f"<span style=\"color:{color};\">{msg}</span><br/>"
|
||||
|
||||
# 디버깅 메시지 출력
|
||||
print(f"Emitting signal with message: {html_message}")
|
||||
|
||||
# Signal.emit 호출 (문자열 하나만 전달)
|
||||
try:
|
||||
self.appendHtml.emit(html_message)
|
||||
except TypeError as te:
|
||||
print(f"TypeError while emitting appendHtml signal: {te}")
|
||||
except Exception as e:
|
||||
print(f"Error while emitting appendHtml signal: {e}")
|
||||
|
||||
# 스크롤 최하단 이동
|
||||
self.scrollToBottom.emit()
|
||||
|
||||
except ValueError as ve:
|
||||
print(f"ValueError in emit: {ve}")
|
||||
except Exception as e:
|
||||
print(f"Error in emit: {e}")
|
||||
|
||||
def scroll_to_bottom(self):
|
||||
"""
|
||||
QTextEdit의 스크롤을 최하단으로 이동.
|
||||
"""
|
||||
self.text_edit.verticalScrollBar().setValue(
|
||||
self.text_edit.verticalScrollBar().maximum()
|
||||
)
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
핸들러를 닫고 필요한 정리 작업 수행.
|
||||
"""
|
||||
self.flush()
|
||||
logging.Handler.close(self)
|
||||
|
||||
super().close()
|
||||
|
||||
def flush(self):
|
||||
pass # 필요 시 정리 작업 수행
|
||||
"""
|
||||
필요 시 출력 버퍼를 비움.
|
||||
"""
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
# import logging
|
||||
# import os
|
||||
# from logging.handlers import RotatingFileHandler
|
||||
# # from PyQt5.QtCore import pyqtSignal, QObject
|
||||
|
||||
# def setup_logger(name, log_file, level=logging.DEBUG, max_bytes=20*1024*1024, backup_count=5):
|
||||
# """로거 설정을 위한 함수"""
|
||||
# formatter = logging.Formatter('%(asctime)s - %(filename)s:%(lineno)d - %(name)s - %(levelname)s - %(message)s')
|
||||
|
||||
# # RotatingFileHandler를 사용하여 로그 파일 설정
|
||||
# handler = RotatingFileHandler(log_file, maxBytes=max_bytes, backupCount=backup_count, encoding='utf-8')
|
||||
# handler.setFormatter(formatter)
|
||||
|
||||
# logger = logging.getLogger(name)
|
||||
# logger.setLevel(level)
|
||||
# logger.addHandler(handler)
|
||||
|
||||
# # 콘솔 로그 출력을 위한 핸들러가 이미 추가되었는지 확인
|
||||
# if not any(isinstance(h, logging.StreamHandler) for h in logger.handlers):
|
||||
# console_handler = logging.StreamHandler()
|
||||
# console_handler.setFormatter(formatter)
|
||||
# console_handler.setLevel(level)
|
||||
# logger.addHandler(console_handler)
|
||||
|
||||
# return logger
|
||||
|
||||
# class QTextEditLogger(logging.Handler, QObject):
|
||||
# appendHtml = pyqtSignal(str) # HTML 메시지를 전달할 시그널 정의
|
||||
# scrollToBottom = pyqtSignal() # 스크롤을 최하단으로 이동시키는 시그널
|
||||
|
||||
# def __init__(self):
|
||||
# logging.Handler.__init__(self)
|
||||
# QObject.__init__(self)
|
||||
|
||||
# def emit(self, record):
|
||||
# msg = self.format(record) # 로그 레코드를 문자열로 포매팅
|
||||
|
||||
# color = {
|
||||
# logging.DEBUG: "black",
|
||||
# logging.INFO: "grey",
|
||||
# logging.WARNING: "orange",
|
||||
# logging.ERROR: "red",
|
||||
# logging.CRITICAL: "purple",
|
||||
# }.get(record.levelno, "black")
|
||||
|
||||
# # HTML 스타일을 적용한 메시지 생성
|
||||
# message = f"<span style=\"color:{color};\">{msg}</span><br/>"
|
||||
# self.appendHtml.emit(message) # HTML 메시지로 변경
|
||||
# self.scrollToBottom.emit() # 스크롤 시그널 발생
|
||||
|
||||
# def close(self):
|
||||
# self.flush()
|
||||
# logging.Handler.close(self)
|
||||
|
||||
# def flush(self):
|
||||
# pass # 필요 시 정리 작업 수행
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
a = Analysis(
|
||||
['main.py'], # 프로젝트 메인 스크립트 이름
|
||||
pathex=['.'], # 현재 경로
|
||||
binaries=[],
|
||||
datas=[
|
||||
('leensoo1nt.json', '.'),
|
||||
('prompt.json', '.'),
|
||||
('config.ini', '.'),
|
||||
('userDB.db', '.'),
|
||||
('src/initialDB.db', 'src'),
|
||||
('src/Percenty_SS_Code.json', 'src')
|
||||
],
|
||||
hiddenimports=[
|
||||
'playwright.async_api',
|
||||
'PySide6.QtCore',
|
||||
'PySide6.QtGui',
|
||||
'PySide6.QtWidgets',
|
||||
'win32gui',
|
||||
'win32con',
|
||||
'pyautogui',
|
||||
'bs4',
|
||||
'numpy',
|
||||
'cv2',
|
||||
'sqlalchemy',
|
||||
'sqlalchemy.orm',
|
||||
'sqlalchemy.exc',
|
||||
'logging.handlers',
|
||||
'PIL',
|
||||
'pywinauto',
|
||||
'vertexai.generative_models',
|
||||
'pyperclip',
|
||||
'ctypes',
|
||||
'pandas'
|
||||
],
|
||||
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,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='AutoPercenty3', # 실행 파일 이름
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=False, # 콘솔 창 비활성화
|
||||
)
|
||||
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
name='AutoPercenty3' # 최종 배포 폴더 이름
|
||||
)
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
a = Analysis(
|
||||
['main.py'], # 프로젝트 메인 스크립트 이름
|
||||
pathex=['.'], # 현재 경로
|
||||
binaries=[],
|
||||
datas=[
|
||||
('leensoo1nt.json', '.'),
|
||||
('prompt.json', '.'),
|
||||
('config.ini', '.'),
|
||||
('userDB.db', '.'),
|
||||
('src/initialDB.db', 'src'),
|
||||
('src/Percenty_SS_Code.json', 'src')
|
||||
],
|
||||
hiddenimports=[
|
||||
'playwright.async_api',
|
||||
'PySide6.QtCore',
|
||||
'PySide6.QtGui',
|
||||
'PySide6.QtWidgets',
|
||||
'win32gui',
|
||||
'win32con',
|
||||
'pyautogui',
|
||||
'bs4',
|
||||
'numpy',
|
||||
'cv2',
|
||||
'sqlalchemy',
|
||||
'sqlalchemy.orm',
|
||||
'sqlalchemy.exc',
|
||||
'logging.handlers',
|
||||
'PIL',
|
||||
'PIL.Image',
|
||||
'PIL.ImageTk',
|
||||
'pywinauto',
|
||||
'vertexai.generative_models',
|
||||
'pyperclip',
|
||||
'ctypes',
|
||||
'pandas'
|
||||
],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=['PyQt5'],
|
||||
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,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='AutoPercenty3', # 실행 파일 이름
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=False, # 콘솔 창 비활성화
|
||||
)
|
||||
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
name='AutoPercenty3' # 최종 배포 폴더 이름
|
||||
)
|
||||
20
whale_new.py
20
whale_new.py
|
|
@ -1,5 +1,5 @@
|
|||
import time
|
||||
import os
|
||||
import os, sys
|
||||
import re
|
||||
import pyperclip
|
||||
from pywinauto import Application, findwindows, clipboard, timings
|
||||
|
|
@ -20,10 +20,22 @@ class WhaleTranslator:
|
|||
self.min_image_width = 200
|
||||
self.min_image_height = 150
|
||||
|
||||
def get_base_dir(self):
|
||||
"""
|
||||
실행 환경에 따라 base_dir을 설정하는 메서드.
|
||||
cx_Freeze로 패키징된 경우 실행 파일의 경로, 일반 Python 환경일 경우 __file__을 기준으로 설정.
|
||||
"""
|
||||
if getattr(sys, 'frozen', False): # 패키징된 경우
|
||||
base_dir = os.path.dirname(sys.executable)
|
||||
else: # 일반 Python 실행 환경
|
||||
base_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
return base_dir
|
||||
|
||||
def start_whale_browser(self):
|
||||
whale_exe_path = os.path.join(os.getcwd(), "browsers", "whale", "whale.exe")
|
||||
user_data_dir = os.path.join(os.getcwd(), "browsers", "whale", "user_data")
|
||||
cache_dir = os.path.join(os.getcwd(), "browsers", "whale", "cache")
|
||||
base_path = self.get_base_dir()
|
||||
whale_exe_path = os.path.join(base_path, "browsers", "whale", "whale.exe")
|
||||
user_data_dir = os.path.join(base_path, "browsers", "whale", "user_data")
|
||||
cache_dir = os.path.join(base_path, "browsers", "whale", "cache")
|
||||
|
||||
self.whale_app = Application(backend="uia").start(
|
||||
f'"{whale_exe_path}" --incognito --user-data-dir="{user_data_dir}" --disk-cache-dir="{cache_dir}"'
|
||||
|
|
|
|||
Loading…
Reference in New Issue