AutoPercenty3/gui.py

895 lines
40 KiB
Python

from PySide6.QtWidgets import QInputDialog, QWidget, QPushButton, QVBoxLayout, QGridLayout, QTextEdit, QLabel, QLineEdit, QHBoxLayout, QProgressBar, QSizePolicy
from PySide6.QtCore import Qt, QRect, QSettings, QTimer
from toggleSwitch import ToggleSwitch
from browser_control import BrowserController
from whale_translator import WhaleTranslator
from clipboardImageManager import ClipboardImageManager
from vertexAI import VertexAITranslator
from option import OptionHandler
from price import PriceHandler
from title import TitleHandler
from locatorManager import LocatorManager
from src.cmb_diag import CMBSettingsDialog
from src.DatabaseManager import DatabaseManager
from logger_module import QTextEditLogger # 추가
import logging
import asyncio, sys
import os, shutil
class TranslationApp(QWidget):
def __init__(self, logger=None, app=None):
super().__init__()
self.initUI()
self.logger = logger
self.debug = False
# key_path = 'leensoo1nt.json'
self.settings = QSettings("WhenRideMycar", "TranslationApp") # QSettings 초기화
self.locator_manager = LocatorManager()
self.browser_controller = BrowserController(self, self.logger, self.locator_manager)
# self.whale_translator = WhaleTranslator(self, self.logger, secret_mode=True,vd_mode=True) # 디버그 모드 켜기
# self.whale_translator = whale_translator
self.whale_translator = None
self.app = app
self.vertexAI = VertexAITranslator(self.logger)
self.optionHandler = None
# DB 파일 경로 설정
self.base_dir = self.get_base_dir()
self.user_db_path = os.path.join(self.base_dir, "userDB.db")
self.initial_db_path = os.path.join(self.base_dir, "src", "initialDB.db")
# userDB.db 생성 (없으면 initialDB.db 복사)
self.create_user_db_if_not_exists()
# # userDB.db 파일이 없으면 initialDB.db를 복사해서 생성
# if not os.path.exists(self.user_db_path):
# if os.path.exists(self.initial_db_path):
# shutil.copyfile(self.initial_db_path, self.user_db_path)
# print("initialDB.db를 userDB.db로 복사했습니다.")
# else:
# raise FileNotFoundError("initialDB.db 파일이 없습니다. 초기 DB 파일이 존재하는지 확인해주세요.")
# DatabaseManager 초기화
self.db_manager = DatabaseManager(db_url=f"sqlite:///{self.user_db_path}", logger=self.logger)
self.cmb_diag = CMBSettingsDialog(parent=self, logger=self.logger, db_manager=self.db_manager, initial_db_path=self.initial_db_path, user_db_path=self.user_db_path, debug=self.debug)
self.clipboardImageManager = ClipboardImageManager(self, logger, self.browser_controller, self.debug)
self.optionHandler = OptionHandler(self.locator_manager, self.browser_controller, self.whale_translator, self.logger, self.vertexAI, self.debug)
self.priceHandler = PriceHandler(self.locator_manager, self.browser_controller, self.logger, self.vertexAI, self.cmb_diag, self.debug)
self.titleHandler = TitleHandler(self.locator_manager, self.browser_controller, self.logger)
self.running = False
# 변수 설정
self.start_time = 0
self.finish_time = 0
self.total_product_count = 0
self.current_product_count = 0
self.title_count = 0
self.option_count = 0
self.price_count = 0
self.detail_image_count = 0
self.thumb_image_count = 0
self.current_stage_index = 0 # 현재 진행 중인 단계 인덱스
# 토글 상태를 저장할 딕셔너리 초기화
self.toggle_states = {
'title': False,
'optionTrnas': False,
'optionIMGTrans': False,
'optionAutoSelect': False,
'price': False,
'thumb': False,
'tag': False,
'detail_Option': False,
'detail_IMGTrans': False,
'debug_mode': False,
'vd_mode': False,
}
# self.title_modify = False
# self.optionTrnas_modify = False
# self.optionIMGTrans_modify = False
# self.optionAutoSelect_modify = False
# self.price_modify = False
# self.thumb_modify = False
# self.tag_modify = False
# self.detail_Option_modify = False
# self.detail_IMGTrans_modify = False
# 이전에 저장된 설정 불러오기
self.load_settings()
# 로거 초기화
self.add_text_edit_logger()
# 프로그래스바 초기화
self.update_total_progress(0,0)
async def run_async_tasks(self):
"""비동기 작업을 실행"""
while True:
await asyncio.sleep(0.1) # 비동기적으로 잠시 대기하여 응답성을 유지
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 create_user_db_if_not_exists(self):
"""
userDB.db 파일이 없으면 initialDB.db를 복사해서 생성하는 메서드.
"""
try:
if not os.path.exists(self.user_db_path):
self.logger.debug("userDB.db 파일이 존재하지 않아 initialDB.db를 복사합니다.")
if os.path.exists(self.initial_db_path):
shutil.copyfile(self.initial_db_path, self.user_db_path)
self.logger.debug("initialDB.db를 userDB.db로 복사했습니다.")
else:
raise FileNotFoundError(f"{self.initial_db_path} 파일이 없습니다. 초기 DB 파일이 존재하는지 확인해주세요.")
except FileNotFoundError as e:
self.logger.error(f"DB 초기화 실패: {e}", exc_info=True)
raise e
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):
self.timer = QTimer(self)
self.blink_status = True
self.timer.timeout.connect(lambda: self.blink_stage(stage_index))
self.timer.start(500) # 0.5초 간격으로 깜빡임
def blink_stage(self, stage_index):
"""지정한 단계의 색상을 주기적으로 변경하여 깜빡임 효과를 적용"""
label = self.stage_labels[stage_index]
if self.blink_status:
label.setStyleSheet("background-color: yellow; padding: 5px;")
else:
label.setStyleSheet("background-color: lightgray; padding: 5px;")
self.blink_status = not self.blink_status
def stop_blinking_effect(self):
"""깜빡임 효과 중지"""
self.timer.stop()
def complete_stage(self, stage_index):
"""단계 완료 시 깜빡임을 중지하고 완료 상태로 변경"""
if 0 <= stage_index < len(self.stage_labels):
self.stop_blinking_effect()
label = self.stage_labels[stage_index]
label.setStyleSheet("background-color: green; padding: 5px;")
self.current_stage_index += 1
# 다음 단계로 이동하여 깜빡임 시작
if self.current_stage_index < len(self.stages):
self.start_stage(self.current_stage_index)
def initUI(self):
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.setGeometry(QRect(1240, 750, 280, 600))
self.setWindowTitle('AutoPecenty2')
# 로그
self.log = QTextEdit(self)
self.log.setReadOnly(True)
# 전체 프로그레스바
self.total_progress_bar = QProgressBar(self)
self.total_progress_bar.setValue(0)
self.total_progress_bar.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
# 스테이지 타임라인
self.stageTimeline_layout = QHBoxLayout()
# self.stages = ["상품명", "옵션", "가격", "썸네일", "상페"]
self.stages = ["옵션", "상페"]
self.stage_labels = []
for stage in self.stages:
# self.stage_layout = QHBoxLayout()
label = QLabel(stage)
label.setStyleSheet("background-color: lightgray; padding: 5px;")
self.stage_labels.append(label)
# self.stage_layout.addWidget(label)
# self.stageTimeline_layout.addLayout(self.stage_layout)
self.stageTimeline_layout.addWidget(label) # 수정: QLabel을 추가할 때 addWidget() 사용
# 디테일 프로그레스바
self.detail_progress_bar = QProgressBar(self)
self.detail_progress_bar.setValue(0)
self.detail_progress_bar.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.detail_progress_bar.setVisible(False)
# 동작옵션 토글 및 레이블 설정
self.toggle_layout = QGridLayout()
# 상품명 수정 토글
self.title_toggle_label = QLabel("상품명 수정", self)
self.title_toggle = ToggleSwitch(self)
self.title_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('title', checked))
self.toggle_layout.addWidget(self.title_toggle_label, 0, 0)
self.toggle_layout.addWidget(self.title_toggle, 0, 1)
# 옵션명 AI번역 토글
self.optionTrnas_toggle_label = QLabel("옵션명 AI번역", self)
self.optionTrnas_toggle = ToggleSwitch(self)
self.optionTrnas_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('optionTrnas', checked))
self.toggle_layout.addWidget(self.optionTrnas_toggle_label, 0, 2)
self.toggle_layout.addWidget(self.optionTrnas_toggle, 0, 3)
# 옵션이미지 번역 토글
self.optionIMGTrans_toggle_label = QLabel("옵션이미지 번역", self)
self.optionIMGTrans_toggle = ToggleSwitch(self)
self.optionIMGTrans_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('optionIMGTrans', checked))
self.toggle_layout.addWidget(self.optionIMGTrans_toggle_label, 1, 0)
self.toggle_layout.addWidget(self.optionIMGTrans_toggle, 1, 1)
# 옵션Auto선택 토글
self.optionAutoSelect_toggle_label = QLabel("옵션 Auto선택", self)
self.optionAutoSelect_toggle = ToggleSwitch(self)
self.optionAutoSelect_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('optionAutoSelect', checked))
self.toggle_layout.addWidget(self.optionAutoSelect_toggle_label, 1, 2)
self.toggle_layout.addWidget(self.optionAutoSelect_toggle, 1, 3)
# 가격 수정 토글
self.price_toggle_label = QLabel("가격 수정", self)
self.price_toggle = ToggleSwitch(self)
self.price_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('price', checked))
self.toggle_layout.addWidget(self.price_toggle_label, 2, 0)
self.toggle_layout.addWidget(self.price_toggle, 2, 1)
# 썸네일 AI수정 토글
self.thumb_toggle_label = QLabel("썸네일 AI수정", self)
self.thumb_toggle = ToggleSwitch(self)
self.thumb_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('thumb', checked))
self.toggle_layout.addWidget(self.thumb_toggle_label, 2, 2)
self.toggle_layout.addWidget(self.thumb_toggle, 2, 3)
# 태그 수정 토글
self.tag_toggle_label = QLabel("태그 수정", self)
self.tag_toggle = ToggleSwitch(self)
self.tag_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('tag', checked))
self.toggle_layout.addWidget(self.tag_toggle_label, 3, 0)
self.toggle_layout.addWidget(self.tag_toggle, 3, 1)
# 상페 옵션명 삽입 토글
self.detail_Option_toggle_label = QLabel("상세 옵션명 삽입", self)
self.detail_Option_toggle = ToggleSwitch(self)
self.detail_Option_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('detail_Option', checked))
self.toggle_layout.addWidget(self.detail_Option_toggle_label, 3, 2)
self.toggle_layout.addWidget(self.detail_Option_toggle, 3, 3)
# 상페 이미지 번역 토글
self.detail_IMGTrans_toggle_label = QLabel("상세 이미지 번역", self)
self.detail_IMGTrans_toggle = ToggleSwitch(self)
self.detail_IMGTrans_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('detail_IMGTrans', checked))
self.toggle_layout.addWidget(self.detail_IMGTrans_toggle_label, 4, 0)
self.toggle_layout.addWidget(self.detail_IMGTrans_toggle, 4, 1)
# 디버그 모드 토글
self.debug_toggle_label = QLabel("디버그 모드", self)
self.debug_toggle = ToggleSwitch(self)
self.debug_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('debug_mode', checked))
self.toggle_layout.addWidget(self.debug_toggle_label, 4, 2)
self.toggle_layout.addWidget(self.debug_toggle, 4, 3)
# VD 모드 토글
self.vd_mode_toggle_label = QLabel("VD 모드", self)
self.vd_mode_toggle = ToggleSwitch(self)
self.vd_mode_toggle.clicked.connect(lambda checked: self.on_toggle_clicked_generic('vd_mode', checked))
self.toggle_layout.addWidget(self.vd_mode_toggle_label, 5, 0)
self.toggle_layout.addWidget(self.vd_mode_toggle, 5, 1)
self.vd_mode_toggle.setVisible(False)
self.vd_mode_toggle_label.setVisible(False)
# 관리자 토글
self.admin_toggle = ToggleSwitch(self)
self.admin_toggle.clicked.connect(self.on_admin_toggle_clicked)
# 관리자 ID 및 PW
self.admin_id_label = QLabel("관리자 ID:", self)
self.admin_id_input = QLineEdit(self)
# 관리자 PW
self.admin_pw_label = QLabel("관리자 PW:", self)
self.admin_pw_input = QLineEdit(self)
self.admin_pw_input.setEchoMode(QLineEdit.Password)
# 직원 ID 및 PW
self.user_id_label = QLabel("직원 ID:", self)
self.user_id_input = QLineEdit(self)
self.user_pw_label = QLabel("직원 PW:", self)
self.user_pw_input = QLineEdit(self)
self.user_pw_input.setEchoMode(QLineEdit.Password)
# 크롬 실행 버튼 및 번역 버튼
self.start_chrome_button = QPushButton('크롬 실행', self)
self.translate_button = QPushButton('번역 시작', self)
self.pause_button = QPushButton('일시정지', self)
self.cmb_button = QPushButton('크무비설정', self)
self.cmb_test_button = QPushButton('크무비테스트', self)
# 버튼 크기를 1.5배로 설정
button_height = int(self.start_chrome_button.sizeHint().height() * 1.5)
self.start_chrome_button.setFixedHeight(button_height)
self.translate_button.setFixedHeight(button_height)
self.pause_button.setFixedHeight(button_height)
self.cmb_button.setFixedHeight(button_height)
# 메인 레이아웃 설정
self.main_layout = QVBoxLayout()
# 관리자 토글 버튼 및 로그인 관련 필드 추가
self.admin_toggle_layout = QHBoxLayout()
self.admin_toggle_layout.addWidget(QLabel("관리자 여부:", self))
self.admin_toggle_layout.addWidget(self.admin_toggle)
self.main_layout.addLayout(self.admin_toggle_layout,1)
# 관리자 ID
self.main_layout.addWidget(self.admin_id_label)
self.main_layout.addWidget(self.admin_id_input)
# 관리자 PW
self.admin_layout = QVBoxLayout()
self.admin_layout.addWidget(self.admin_pw_label)
self.admin_layout.addWidget(self.admin_pw_input)
# 직원 ID/PW
self.user_layout = QVBoxLayout()
self.user_layout.addWidget(self.user_id_label)
self.user_layout.addWidget(self.user_id_input)
self.user_layout.addWidget(self.user_pw_label)
self.user_layout.addWidget(self.user_pw_input)
# 관리자와 직원 레이아웃을 메인 레이아웃에 추가
self.main_layout.addLayout(self.admin_layout,3)
self.main_layout.addLayout(self.user_layout,3)
# 크롬 및 번역 관련 버튼
self.button_layout = QHBoxLayout()
self.button_layout.addWidget(self.start_chrome_button)
self.button_layout.addWidget(self.translate_button)
self.button_layout.addWidget(self.pause_button)
self.button_layout.addWidget(self.cmb_button)
self.button_layout.addWidget(self.cmb_test_button)
# 로그 및 프로그레스바 레이아웃
self.log_layout = QVBoxLayout()
self.log_layout.addWidget(self.log)
self.log_layout.addWidget(self.total_progress_bar)
self.log_layout.addLayout(self.stageTimeline_layout)
self.log_layout.addWidget(self.detail_progress_bar)
# # 토글 레이아웃
# self.toggle_layout = QGridLayout()
# self.toggle_layout.addWidget(self.title_toggle,0,0)
# self.toggle_layout.addWidget(self.optionTrnas_toggle,1,0)
# self.toggle_layout.addWidget(self.optionIMGTrans_toggle,2,0)
# self.toggle_layout.addWidget(self.optionAutoSelect_toggle,3,0)
# self.toggle_layout.addWidget(self.price_toggle,0,1)
# self.toggle_layout.addWidget(self.tag_toggle,1,1)
# self.toggle_layout.addWidget(self.thumb_toggle,2,1)
# self.toggle_layout.addWidget(self.detail_Option_toggle,3,1)
# self.toggle_layout.addWidget(self.detail_IMGTrans_toggle,0,2)
# self.toggle_layout.addWidget(self.debug_toggle,1,2)
# 메인 레이아웃에 버튼 레이아웃과 로그 레이아웃 추가
# self.main_layout.addLayout(self.admin_toggle_layout,2)
self.main_layout.addLayout(self.toggle_layout,2)
self.main_layout.addLayout(self.button_layout,2)
self.main_layout.addLayout(self.log_layout,5)
self.setLayout(self.main_layout)
# 기본 상태 설정
self.on_admin_toggle_clicked(False)
# 버튼 이벤트 연결
# self.start_chrome_button.clicked.connect(self.start_browser)
self.start_chrome_button.clicked.connect(self.on_start_chrome_button_clicked)
# self.translate_button.clicked.connect(self.start_translation)
self.translate_button.clicked.connect(self.on_start_translation_button_clicked)
self.pause_button.clicked.connect(self.pause_translation)
# self.exit_button.clicked.connect(self.close)
self.cmb_button.clicked.connect(self.on_cmb_button_clicked)
self.cmb_test_button.clicked.connect(self.on_cmb_test_button_clicked)
async def run_async_tasks(self):
"""비동기 작업을 실행"""
while True:
await asyncio.sleep(0.1) # 비동기적으로 잠시 대기하여 응답성을 유지
def load_toggle_settings(self):
"""QSettings에서 토글 상태 불러오기"""
for key in self.toggle_states.keys():
self.toggle_states[key] = self.settings.value(f"toggle/{key}", False, type=bool)
self.update_toggle_ui(key)
def save_toggle_settings(self):
"""QSettings에 토글 상태 저장"""
for key, value in self.toggle_states.items():
self.settings.setValue(f"toggle/{key}", value)
def update_toggle_ui(self, key):
"""토글 상태에 따라 UI 업데이트"""
if hasattr(self, f"{key}_toggle"):
toggle_widget = getattr(self, f"{key}_toggle")
toggle_widget.setChecked(self.toggle_states[key])
def on_toggle_clicked_generic(self, key, is_checked):
"""토글 클릭 시 상태 업데이트 및 저장"""
self.toggle_states[key] = is_checked
if is_checked:
status_text = "활성화"
else:
status_text = "비활성화"
label_text = ""
# key에 따라 라벨 텍스트를 설정
if key == 'title':
label_text = self.title_toggle_label.text()
elif key == 'optionTrnas':
label_text = self.optionTrnas_toggle_label.text()
elif key == 'optionIMGTrans':
label_text = self.optionIMGTrans_toggle_label.text()
elif key == 'optionAutoSelect':
label_text = self.optionAutoSelect_toggle_label.text()
elif key == 'price':
label_text = self.price_toggle_label.text()
elif key == 'thumb':
label_text = self.thumb_toggle_label.text()
elif key == 'tag':
label_text = self.tag_toggle_label.text()
elif key == 'detail_Option':
label_text = self.detail_Option_toggle_label.text()
elif key == 'detail_IMGTrans':
label_text = self.detail_IMGTrans_toggle_label.text()
self.on_vd_mode_for_detail_imageTrans_clicked(is_checked)
elif key == 'debug_mode':
label_text = self.debug_toggle_label.text()
elif key == 'vd_mode':
label_text = self.vd_mode_toggle_label.text()
# 디버그 로그에 라벨의 텍스트를 출력
self.logger.debug(f"{label_text} 버튼 - {status_text} 선택")
self.save_toggle_settings()
# def on_title_toggle_clicked(self, is_checked):
# if is_checked:
# self.title_modify = True
# else:
# self.title_modify = False
# def on_optionTrnas_toggle_clicked(self, is_checked):
# if is_checked:
# self.optionTrnas_modify = True
# else:
# self.optionTrnas_modify = False
# def on_optionIMGTrans_toggle_clicked(self, is_checked):
# if is_checked:
# self.optionIMGTrans_modify = True
# else:
# self.optionIMGTrans_modify = False
# def on_optionAutoSelect_toggle_clicked(self, is_checked):
# if is_checked:
# self.optionAutoSelect_modify = True
# else:
# self.optionAutoSelect_modify = False
# def on_price_toggle_clicked(self, is_checked):
# if is_checked:
# self.price_modify = True
# else:
# self.price_modify = False
# def on_thumb_toggle_clicked(self, is_checked):
# if is_checked:
# self.thumb_modify = True
# else:
# self.thumb_modify = False
# def on_tag_toggle_clicked(self, is_checked):
# if is_checked:
# self.tag_modify = True
# else:
# self.tag_modify = False
# def on_detail_Option_toggle_clicked(self, is_checked):
# if is_checked:
# self.detail_Option_modify = True
# else:
# self.detail_Option_modify = False
# def on_detail_IMGTrans_toggle_clicked(self, is_checked):
# if is_checked:
# self.detail_IMGTrans_modify = True
# else:
# self.detail_IMGTrans_modify = False
# def on_debug_toggle_clicked(self, is_checked):
# if is_checked:
# self.debug_mode = True
# else:
# self.debug_mode = False
def on_admin_toggle_clicked(self, is_checked):
"""관리자 토글 상태에 따라 관리자와 직원 필드를 표시/숨김"""
if is_checked:
# 관리자 모드: 직원 레이아웃을 숨기고, 관리자 PW를 표시
self.set_layout_visibility(self.admin_layout, True)
self.set_layout_visibility(self.user_layout, False)
else:
# 직원 모드: 관리자 PW를 숨기고, 직원 레이아웃을 표시
self.set_layout_visibility(self.admin_layout, False)
self.set_layout_visibility(self.user_layout, True)
def on_vd_mode_for_detail_imageTrans_clicked(self, is_checked):
"""상페이미지 번역여부에 따라 VD 모드 선택 필드를 표시/숨김"""
if is_checked:
self.vd_mode_toggle.setVisible(True)
self.vd_mode_toggle_label.setVisible(True)
else:
self.vd_mode_toggle.setVisible(False)
self.vd_mode_toggle_label.setVisible(False)
def set_layout_visibility(self, changelayout, visible):
"""레이아웃에 포함된 모든 위젯의 가시성을 설정"""
for i in range(changelayout.count()):
widget = changelayout.itemAt(i).widget()
if widget:
widget.setVisible(visible)
def on_start_chrome_button_clicked(self):
"""크롬 실행 버튼 클릭 시 호출"""
self.logger.debug('크롬 실행 버튼 클릭됨')
self.logger.debug(f'self.browser_controller.page : {self.browser_controller.page}')
# 비동기 함수 실행을 위해 asyncio.create_task 사용
optionIMGTrans_status = self.toggle_states['optionIMGTrans']
detail_IMGTrans_status = self.toggle_states['detail_IMGTrans']
vd_mode_status = self.toggle_states['vd_mode']
if optionIMGTrans_status or detail_IMGTrans_status:
self.logger.debug(f"optionIMGTrans_status : {optionIMGTrans_status}, detail_IMGTrans_status : {detail_IMGTrans_status}")
self.whale_translator = WhaleTranslator(self.app, self.logger, secret_mode=True, vd_mode=vd_mode_status) # 모드 켜기
self.whale_translator.start_whale_browser()
asyncio.create_task(self.start_browser())
async def on_close_button_clicked(self):
"""크롬 실행 버튼 클릭 시 호출"""
self.logger.debug('크롬 실행 버튼 클릭됨')
# 비동기 함수 실행을 위해 asyncio.create_task 사용
task = asyncio.create_task(self.close())
await task # 작업이 완료될 때까지 대기
def on_cmb_test_button_clicked(self, test_cat):
"""크무비 설정 실행 버튼 클릭 시 호출"""
self.logger.debug('크무비 테스트 버튼 클릭됨')
text, ok = QInputDialog.getText(self, "카테고리 입력 테스트", "카테고리를 형식에 맞게 입력하세요:")
if ok and text: # 사용자가 확인 버튼을 누르고 텍스트를 입력한 경우
stage = self.cmb_diag.get_crmobi_stage(text)
self.logger.debug(f"{stage}")
def on_cmb_button_clicked(self):
"""크무비 설정 실행 버튼 클릭 시 호출"""
self.logger.debug('크무비 설정 버튼 클릭됨')
self.cmb_diag.show()
async def start_browser(self):
"""크롬 브라우저 실행 후 로그인"""
self.logger.debug('크롬 브라우저를 실행합니다...')
# await self.whale_translator.start_whale_browser()
await self.browser_controller.start_browser()
# 관리자 토글 상태에 따라 로그인
if self.admin_toggle.isChecked():
admin_id = self.admin_id_input.text()
admin_pw = self.admin_pw_input.text()
user_id = self.user_id_input.text()
user_pw = self.user_pw_input.text()
await self.browser_controller.login(admin_id, user_id, admin_pw, user_pw, is_admin=True)
else:
admin_id = self.admin_id_input.text()
admin_pw = self.admin_pw_input.text()
user_id = self.user_id_input.text()
user_pw = self.user_pw_input.text()
await self.browser_controller.login(admin_id, user_id, admin_pw, user_pw, is_admin=False)
# 로그인 정보 저장
self.save_settings()
# "신규 상품 등록" 페이지로 이동
self.logger.debug('신규 상품 등록 페이지로 이동 중...')
await self.browser_controller.go_to_new_product_page()
# 옵션핸들러에 초기화된 page 객체 전달.
self.optionHandler.update_page(self.browser_controller.page)
self.titleHandler.update_page(self.browser_controller.page)
self.priceHandler.update_page(self.browser_controller.page)
def save_settings(self):
"""QSettings에 사용자 정보 저장"""
self.settings.setValue("admin/id", self.admin_id_input.text())
self.settings.setValue("admin/pw", self.admin_pw_input.text())
self.settings.setValue("user/id", self.user_id_input.text())
self.settings.setValue("user/pw", self.user_pw_input.text())
self.settings.setValue("admin/toggle", self.admin_toggle.isChecked())
def load_settings(self):
"""QSettings에서 사용자 정보 불러오기"""
self.admin_id_input.setText(self.settings.value("admin/id", ""))
self.admin_pw_input.setText(self.settings.value("admin/pw", ""))
self.user_id_input.setText(self.settings.value("user/id", ""))
self.user_pw_input.setText(self.settings.value("user/pw", ""))
admin_toggle_state = self.settings.value("admin/toggle", "false") == "true"
self.admin_toggle.setChecked(admin_toggle_state)
self.on_admin_toggle_clicked(admin_toggle_state)
def update_total_progress(self, current_value, total_value):
if current_value == 0:
self.total_progress_bar.setValue(0)
self.total_progress_bar.setFormat("상품 수정 대기") # current_value가 0일 때 표시될 텍스트
else:
# 프로그레스바의 값과 텍스트를 설정
percentage = int((current_value / total_value) * 100)
self.total_progress_bar.setValue(percentage)
self.total_progress_bar.setFormat(f"상품 {current_value}/{total_value}개 완료 [{percentage}%]")
def update_detail_progress(self, current_value, total_value):
if current_value == 0:
self.detail_progress_bar.setValue(0)
self.detail_progress_bar.setFormat("수정 대기") # current_value가 0일 때 표시될 텍스트
else:
# 프로그레스바의 값과 텍스트를 설정
percentage = int((current_value / total_value) * 100)
self.detail_progress_bar.setValue(percentage)
self.detail_progress_bar.setFormat(f"{current_value}/{total_value}개 완료 [{percentage}%]")
def on_start_translation_button_clicked(self):
"""번역 작업 버튼 클릭 시 호출"""
self.logger.debug('번역 작업 버튼 클릭됨')
# 비동기 함수 실행을 위해 asyncio.create_task 사용
asyncio.create_task(self.start_translation())
async def start_translation(self):
self.logger.debug('번역 작업을 시작합니다...')
self.running = True # 번역 작업이 시작됨
try:
# # 1. "신규 상품 등록" 페이지로 이동
# self.logger.debug('신규 상품 등록 페이지로 이동 중...')
# await self.browser_controller.go_to_new_product_page()
# 2. 총 상품 수 수집
await self.browser_controller.scroll_page_to_bottom() # 동적 로딩을 위해 끝까지 스크롤
total_products = await self.browser_controller.get_total_product_count()
if total_products == 0:
self.logger.debug('수집할 상품이 없습니다. 작업을 종료합니다.')
return
self.total_progress_bar.setMaximum(total_products)
self.total_progress_bar.setValue(0)
completed_count = 0
self.update_total_progress(completed_count, total_products)
page_number = 1
# 3. 총 상품 수만큼 반복 작업 수행
while self.running and completed_count < total_products:
self.logger.debug(f'현재 페이지: {page_number}')
if not page_number == 1:
await self.browser_controller.scroll_page_to_top()
self.logger.debug(f'1페이지가 아니므로 동적로딩을 위해 휠 스크롤 업')
# 4. 현재 페이지의 모든 "세부사항 수정 및 업로드" 버튼 찾기
product_buttons = await self.browser_controller.get_product_edit_buttons_by_templete()
if not product_buttons:
self.logger.debug('수정할 상품이 없습니다. 작업을 종료합니다.')
break
# 5. 각 상품에 대해 번역 작업 수행
for index, button in enumerate(product_buttons, start=1):
if not self.running:
self.logger.debug('번역 작업이 중단되었습니다.')
return
self.logger.debug(f'{index}/{len(product_buttons)}: 세부사항 수정 작업 중...')
# # 상품명 수집 및 수집 오류 처리
# product_name = await self.browser_controller.get_product_name(index, 'css')
# if product_name == "수집 오류 발생":
# self.logger.debug('상품 수집 오류, 다음 상품으로 넘어갑니다.')
# continue
# 상품 수정 다이얼로그 열기
await self.browser_controller.open_product_edit_dialog(button)
# 상품명과 카테고리 수집
self.start_stage(0)
product_name = await self.titleHandler.get_original_product_name() # 원본상품명 가져오기
product_category = await self.titleHandler.get_category(market='ss') # 카테고리 가져오기
# await self.edit_title()
self.complete_stage(0)
if self.toggle_states['optionTrnas'] or self.toggle_states['optionIMGTrans'] or self.toggle_states['optionAutoSelect']:
self.logger.debug(f"옵션수정 : optionTrnas={self.toggle_states['optionTrnas']} + optionIMGTrans={self.toggle_states['optionIMGTrans']} + optionAutoSelect{self.toggle_states['optionAutoSelect']}")
# 옵션 수정
self.start_stage(0)
await self.edit_option(product_name)
self.complete_stage(0)
if self.toggle_states['price']:
self.logger.debug(f"가격수정 : {self.toggle_states['price']} ")
# 가격 수정
# self.start_stage(0)
await self.edit_price(product_category)
# self.complete_stage(0)
if self.toggle_states['thumb']:
pass
if self.toggle_states['tag']:
pass
if self.toggle_states['title']:
pass
if self.toggle_states['detail_Option'] or self.toggle_states['detail_IMGTrans']:
self.logger.debug(f"상세페이지 수정 : {self.toggle_states['detail_Option']} + {self.toggle_states['detail_IMGTrans']}")
# 상세페이지 수정
self.start_stage(1)
await self.detail_trans()
self.complete_stage(1)
# 수정 후 저장
self.logger.debug('상품 세부사항 저장 중...')
await self.browser_controller.save_and_ecs_product_edit()
completed_count += 1
self.update_total_progress(completed_count, total_products)
self.logger.debug(f'{completed_count}/[{total_products}]개 상품 수정 완료.')
if completed_count >= total_products:
self.logger.debug('모든 상품이 완료되었습니다.')
return
# 6. 다음 페이지로 이동 (있으면)
if not await self.browser_controller.go_to_next_page():
self.logger.debug('더 이상 페이지가 없습니다. 작업을 종료합니다.')
break
page_number += 1
if self.running:
self.logger.debug('모든 상품 번역 및 저장 완료.')
self.running = False # 작업 종료 후 상태를 False로 전환
except Exception as e:
self.logger.debug(f"번역 작업 중 오류 발생: {e}", exc_info=True)
self.running = False
def pause_translation(self):
self.logger.debug('번역 작업을 중단합니다...')
self.running = False # 번역 작업 중단
async def close(self):
self.logger.debug('프로그램을 종료합니다...')
self.save_settings()
await self.browser_controller.close_browser() # 브라우저 종료
if self.toggle_states['vd_mode']:
self.whale_translator.close_all_virtual_desktops()
super().close()
async def detail_trans(self):
# 상세페이지 탭 클릭
await self.browser_controller.click_detail_tab()
# await self.browser_controller.page.wait_for_load_state('networkidle', timeout=10000)
self.detail_progress_bar.setValue(0)
self.detail_progress_bar.setVisible(True)
# 이미지 URL 추출
# image_urls = self.browser_controller.extract_image_urls()
image_urls = await self.browser_controller.extract_image_urls(self.optionHandler, is_option_data=True) # 코루틴 실행
total_images = len(image_urls)
self.logger.debug(f"현재 상품의 총 이미지 수 : {total_images}")
self.detail_image_count += total_images
# 이미지 번역 작업 진행
for i, url in enumerate(image_urls):
current_image_count = i +1
if not self.running:
self.logger.debug('번역 작업이 중단되었습니다.')
break
self.logger.debug(f"웨일 브라우저를 활용한 이미지 번역 프로세스")
self.whale_translator.translate_image(url)
self.logger.debug(f"paste_image_in_chrome - 이미지 붙여넣기")
await self.browser_controller.paste_image_in_chrome(self.clipboardImageManager, url)
self.logger.debug(f"Progress Update")
self.update_detail_progress(i,total_images)
current_image_count += 1
# 수정 후 저장
self.logger.debug('상품 세부사항 저장 중...')
await self.browser_controller.save_product_edit()
self.detail_progress_bar.setVisible(False)
self.detail_progress_bar.setValue(0)
async def edit_option(self, product_name):
# 상세페이지 탭 클릭
await self.browser_controller.click_option_tab()
# await self.browser_controller.page.wait_for_load_state('networkidle', timeout=10000)
self.detail_progress_bar.setVisible(True)
# 옵션 최대선택갯수
max_option_count = 20
option_image_trans = False
await self.optionHandler.process_options(product_name, max_option_count, self.toggle_states)
# 수정 후 저장
# await self.optionHandler.save_option()
await self.browser_controller.save_product_edit()
self.detail_progress_bar.setVisible(False)
async def edit_price(self, product_category):
# 상세페이지 탭 클릭
await self.browser_controller.click_price_tab()
# await self.browser_controller.page.wait_for_load_state('networkidle', timeout=10000)
self.detail_progress_bar.setVisible(True)
# 가격 수정 프로세스
await self.priceHandler.process_price(category=product_category)
# 수정 후 저장
await self.browser_controller.save_product_edit()
self.detail_progress_bar.setVisible(False)