옵션이미지 수정중

This commit is contained in:
R5600U_PC 2024-10-27 16:36:42 +09:00
parent f37edc088f
commit d758a11812
9 changed files with 3766 additions and 145 deletions

File diff suppressed because one or more lines are too long

View File

@ -680,12 +680,12 @@ class BrowserController:
self.logger.error(f"이미지 URL 추출 & 옵션데이터 입력 처리 중 오류: {e}", exc_info=True)
return image_urls if image_urls else []
def paste_image_in_chrome(self, clipboardImageManager, url, is_success_translated, toggle_states, is_watermark=False, watermark_text= "", opacity_percent=25):
def paste_image_in_chrome(self, clipboardImageManager, url, is_success_translated, toggle_states, is_watermark=False, watermark_text= ""):
"""크롬으로 포커스를 옮기고 클립보드의 이미지를 붙여넣고 엔터 입력"""
self.logger.debug("크롬으로 포커스를 옮기고 클립보드의 이미지를 붙여넣고 엔터 입력")
try:
self.switch_to_chrome() # 크롬으로 포커스 이동
clipboardImageManager.process_clipboard(original_url=url, is_success_translated=is_success_translated, toggle_states=toggle_states, opacity_percent=opacity_percent) # 클립보드 내용을 처리
clipboardImageManager.process_clipboard(original_url=url, is_success_translated=is_success_translated, toggle_states=toggle_states) # 클립보드 내용을 처리
# clipboard_content = pyperclip.paste()
if clipboardImageManager.is_clipboard_image():
pyautogui.hotkey('ctrl', 'v') # 클립보드 이미지 붙여넣기

View File

@ -81,7 +81,7 @@ class ClipboardImageManager:
if image:
# 이미지를 저장 경로에 저장
self.logger.info(f"이미지 저장 완료 : {path}")
image.save(path)
image.save(path, format='PNG')
return path
except Exception as e:
@ -204,7 +204,7 @@ class ClipboardImageManager:
self.logger.debug("이미지 다운로드 최대 재시도 횟수를 초과했습니다.")
return None
def process_clipboard(self, original_url, is_success_translated, toggle_states, opacity_percent, path=None):
def process_clipboard(self, original_url, is_success_translated, toggle_states, path=None):
"""클립보드의 내용을 처리하고, 필요한 경우 이미지 변환, 크롭 또는 클립보드 비우기"""
try:
@ -214,6 +214,9 @@ class ClipboardImageManager:
watermark_text = toggle_states['watermark_text']
self.logger.debug(f"watermark_text : {watermark_text}")
opacity_percent = toggle_states['opacity_percent']
self.logger.debug(f"opacity_percent : {opacity_percent}")
clipboard_data = self.get_clipboard_data()
self.logger.debug("clipboard_data")
@ -242,7 +245,7 @@ class ClipboardImageManager:
self.set_image_to_clipboard(cropped_image) # 클립보드에 저장
if path:
self.logger.debug("이미지 저장 시도...")
self.save_image_to_path(path)
self.save_image_to_path(cropped_image, path)
else:
self.logger.debug("이미지 가로 크기 200픽셀 이하: 클립보드 비움.")
self.clear_clipboard()
@ -270,7 +273,7 @@ class ClipboardImageManager:
self.set_image_to_clipboard(cropped_image) # 클립보드에 저장
if path:
self.logger.debug("이미지 저장 시도...")
self.save_image_to_path(path)
self.save_image_to_path(cropped_image, path)
else:
self.logger.debug("이미지 가로 크기 200픽셀 이하: 클립보드 비움.")
@ -293,7 +296,7 @@ class ClipboardImageManager:
self.set_image_to_clipboard(image) # 크롭 없이 저장
if path:
self.logger.debug("이미지 저장 시도...")
self.save_image_to_path(path)
self.save_image_to_path(image, path)
else:
self.logger.debug("원본 이미지 다운로드 실패.")
else:

View File

@ -30,10 +30,21 @@ checkbox_selector_template = '#productMainContentContainerId li:nth-child({index
image_selector_template = 'div#productMainContentContainerId li:nth-child({index}) > div > div:nth-child(1) > div > div:nth-child(2) > div > img'
; price_selector_template = '#productMainContentContainerId li:nth-child({index}) sup'
price_selector_template = '//*[@id="productMainContentContainerId"]/div[1]/div[2]/div/div/div[2]/div/div[1]/div/div/div[2]/div/div/div[5]/div[1]/div/div/ul/li[{index}]/div/div[1]/div/div[3]/div[1]/div[2]/button/span/sup'
delete_button_selector_template = '#productMainContentContainerId > div.sc-TOgAA.fZvEqY > div:nth-child(2) > div > div > div:nth-child(2) > div > div.sc-cFShuL.dbIeho > div > div > div.ant-collapse-content.ant-collapse-content-active > div > div > div.sc-fGdiLE.iyXMeU > div.ant-list.ant-list-split.css-1li46mu > div > div > ul > li:nth-child({index}) > div > div:nth-child(1) > div > div:nth-child(2) > div > div.ant-row.ant-row-no-wrap.ant-row-space-between.ant-row-middle.css-1li46mu > div:nth-child(1) > div'
confirm_delete_button_locator = 'body > div:nth-child(18) > div > div.ant-modal-wrap.ant-modal-confirm-centered.ant-modal-centered > div > div.sc-ddjGPC.jbwEYW > div > div > div > div.ant-modal-confirm-btns > button.ant-btn.css-1li46mu.ant-btn-primary.ant-btn-dangerous'
add_button_selector_template = '#productMainContentContainerId > div.sc-TOgAA.fZvEqY > div:nth-child(2) > div > div > div:nth-child(2) > div > div.sc-cFShuL.dbIeho > div > div > div.ant-collapse-content.ant-collapse-content-active > div > div > div.sc-fGdiLE.iyXMeU > div.ant-list.ant-list-split.css-1li46mu > div > div > ul > li:nth-child({index}) > div > div:nth-child(1) > div > div:nth-child(2) > div > div > img'
file_input_locator = 'input[type="file"]'
# 옵션 상자
option_box_selector = 'div#productMainContentContainerId div.lesrZh.sc-bYHUQc'
excluded_option_marker = 'div#productMainContentContainerId div.lesrZh.sc-bYHUQc:nth-child({index}) > .sc-dfauwV.bXsMpn'
delete_button_selector = 'div#productMainContentContainerId div.lesrZh.sc-bYHUQc:nth-child({index}) span:has-text("삭제")'
confirm_delete_button_selector = '.ant-modal.css-1li46mu.ant-modal-confirm.ant-modal-confirm-confirm button:has-text("삭제")'
; add_button_selector = 'div#productMainContentContainerId div.lesrZh.sc-bYHUQc:nth-child({index}) > .sc-dRGYJT.hmQUGb'
add_button_selector = 'div#productMainContentContainerId li:nth-child({index}) > div > div:nth-child(1) > div > div:nth-child(2) > div > div'
; add_button_selector = 'div#productMainContentContainerId div.lesrZh.sc-bYHUQc:nth-child({index}) > .sc-krITIZ.ckztYT'
; file_upload_button_selector = '.ant-modal-content button:has-text("클릭 or 드레그로 파일 업로드")'
file_upload_button_selector = 'div.ant-modal-body > span > div > span > div'
; confirm_upload_button_selector = '.ant-modal-content button:has-text("이미지 삽입")'
confirm_upload_button_selector = 'div.ant-modal-footer > button[type=\"button\"].ant-btn.css-1li46mu.ant-btn-primary'
low_order_button_locator = 'button:has-text("가격 낮은 순")'
AtoZ_button_locator = 'button:has-text("A-Z")'
one_to_nine_button_locator = 'button:has-text("1-99")'

14
gui.py
View File

@ -55,7 +55,7 @@ class TranslationApp(QWidget):
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, watermark_font_size=36, debug=self.debug)
self.optionHandler = OptionHandler(self.locator_manager, self.browser_controller, self.whale_translator, self.logger, self.vertexAI, self.debug)
self.optionHandler = OptionHandler(self.locator_manager, self.browser_controller, self.whale_translator, self.clipboardImageManager, self.logger, self.vertexAI, self.debug)
self.priceHandler = PriceHandler(self.locator_manager, self.browser_controller, self.logger, self.optionHandler, self.vertexAI, self.cmb_diag, self.debug)
self.titleHandler = TitleHandler(self.locator_manager, self.browser_controller, self.logger)
self.running = False
@ -93,7 +93,7 @@ class TranslationApp(QWidget):
'ed_mode': False, # 등록된 상품을 수정할때
'watermark': False, # 워터마크 토글 추가
'watermark_text': "WaterMark", # 워터마크 텍스트 저장
'opacity_percent': 35, # 워터마크 투명도
'opacity_percent': 25, # 워터마크 투명도
}
# 이전에 저장된 설정 불러오기
@ -689,8 +689,9 @@ class TranslationApp(QWidget):
self.logger.info('신규 상품 등록 페이지로 이동 중...')
await self.browser_controller.go_to_new_product_page()
# 옵션핸들러에 초기화된 page 객체 전달.
# 핸들러에 초기화된 page 객체 전달.
self.optionHandler.update_page(self.browser_controller.page)
self.optionHandler.update_whale(self.whale_translator)
self.titleHandler.update_page(self.browser_controller.page)
self.priceHandler.update_page(self.browser_controller.page)
@ -803,8 +804,8 @@ class TranslationApp(QWidget):
if not product_buttons:
self.logger.debug('수정할 상품이 없습니다. 작업을 종료합니다.')
break
deleted_imgs = self.browser_controller.deleted_img_urls_from_logs()
if self.toggle_states['recovery_mode']:
deleted_imgs = self.browser_controller.deleted_img_urls_from_logs()
# 5. 각 상품에 대해 번역 작업 수행
for index, button in enumerate(product_buttons, start=1):
@ -931,8 +932,7 @@ class TranslationApp(QWidget):
self.logger.debug(f"웨일 브라우저를 활용한 이미지 번역 프로세스")
is_success_translated = self.whale_translator.translate_image(url)
opacity_percent=35
is_paste_success = self.browser_controller.paste_image_in_chrome(self.clipboardImageManager, url, is_success_translated, self.toggle_states, opacity_percent=opacity_percent)
is_paste_success = self.browser_controller.paste_image_in_chrome(self.clipboardImageManager, url, is_success_translated, self.toggle_states)
if is_paste_success:
self.logger.debug(f"{url} gui 이미지 붙여넣기 성공")
else:

View File

@ -88,10 +88,13 @@ class LocatorManager:
'checkbox_selector_template': self.config.get('OptionLocators', 'checkbox_selector_template').strip("'"),
'image_selector_template': self.config.get('OptionLocators', 'image_selector_template').strip("'"),
'price_selector_template': self.config.get('OptionLocators', 'price_selector_template').strip("'"),
'delete_button_selector_template': self.config.get('OptionLocators', 'delete_button_selector_template').strip("'"),
'confirm_delete_button_locator': self.config.get('OptionLocators', 'confirm_delete_button_locator').strip("'"),
'add_button_selector_template': self.config.get('OptionLocators', 'add_button_selector_template').strip("'"),
'file_input_locator': self.config.get('OptionLocators', 'file_input_locator').strip("'"),
'option_box_selector': self.config.get('OptionLocators', 'option_box_selector').strip("'"),
'excluded_option_marker': self.config.get('OptionLocators', 'excluded_option_marker').strip("'"),
'delete_button_selector': self.config.get('OptionLocators', 'delete_button_selector').strip("'"),
'confirm_delete_button_selector': self.config.get('OptionLocators', 'confirm_delete_button_selector').strip("'"),
'add_button_selector': self.config.get('OptionLocators', 'add_button_selector').strip("'"),
'file_upload_button_selector': self.config.get('OptionLocators', 'file_upload_button_selector').strip("'"),
'confirm_upload_button_selector': self.config.get('OptionLocators', 'confirm_upload_button_selector').strip("'"),
'low_order_button_locator': self.config.get('OptionLocators', 'low_order_button_locator').strip("'"),
'AtoZ_button_locator': self.config.get('OptionLocators', 'AtoZ_button_locator').strip("'"),
'one_to_nine_button_locator': self.config.get('OptionLocators', 'one_to_nine_button_locator').strip("'"),

255
option.py
View File

@ -3,12 +3,14 @@ import pyautogui
from datetime import datetime
import numpy as np
import asyncio, time, math
import tempfile, os
class OptionHandler:
def __init__(self, locator_manager, browser_controller, whale_translator, logger, vertexAI, debug_flag=False):
def __init__(self, locator_manager, browser_controller, whale_translator, clipboardImageManager, logger, vertexAI, debug_flag=False):
self.locator_manager = locator_manager
self.browser_controller = browser_controller
self.page = self.browser_controller.page
self.clipboardImageManager = clipboardImageManager
self.logger = logger
self.debug_flag = debug_flag
self.vertexAItranslator = vertexAI
@ -30,10 +32,15 @@ class OptionHandler:
self.checkbox_selector_template = self.locator_manager.get_locator('OptionLocators', 'checkbox_selector_template')
self.image_selector_template = self.locator_manager.get_locator('OptionLocators', 'image_selector_template')
self.price_selector_template = self.locator_manager.get_locator('OptionLocators', 'price_selector_template')
self.delete_button_selector_template = self.locator_manager.get_locator('OptionLocators', 'delete_button_selector_template')
self.confirm_delete_button_locator = self.locator_manager.get_locator('OptionLocators', 'confirm_delete_button_locator')
self.add_button_selector_template = self.locator_manager.get_locator('OptionLocators', 'add_button_selector_template')
self.file_input_locator = self.locator_manager.get_locator('OptionLocators', 'file_input_locator')
self.option_box_selector = self.locator_manager.get_locator('OptionLocators', 'option_box_selector')
self.excluded_option_marker = self.locator_manager.get_locator('OptionLocators', 'excluded_option_marker')
self.delete_button_selector = self.locator_manager.get_locator('OptionLocators', 'delete_button_selector')
self.confirm_delete_button_selector = self.locator_manager.get_locator('OptionLocators', 'confirm_delete_button_selector')
self.add_button_selector = self.locator_manager.get_locator('OptionLocators', 'add_button_selector')
self.file_upload_button_selector = self.locator_manager.get_locator('OptionLocators', 'file_upload_button_selector')
self.confirm_upload_button_selector = self.locator_manager.get_locator('OptionLocators', 'confirm_upload_button_selector')
self.low_order_button_locator = self.locator_manager.get_locator('OptionLocators', 'low_order_button_locator')
self.AtoZ_button_locator = self.locator_manager.get_locator('OptionLocators', 'AtoZ_button_locator')
self.one_to_nine_button_locator = self.locator_manager.get_locator('OptionLocators', 'one_to_nine_button_locator')
@ -41,6 +48,9 @@ class OptionHandler:
def update_page(self, page1):
self.page = page1
self.logger.debug(f"page객체 업데이트 : {page1}")
def update_whale(self, whale1):
self.whale_translator = whale1
self.logger.debug(f"whale_translator 객체 업데이트 : {whale1}")
def init_option_info(self):
self.option_info = {
@ -198,57 +208,61 @@ class OptionHandler:
# 3. 가격 낮은 순 정렬 클릭
await self.low_order_click()
# 4. 옵션 정보 수집 및 번역
try:
if toggle_states['optionTrnas']:
self.logger.debug(f"옵션 AI번역 : {toggle_states['optionTrnas']}")
self.option_info = await self.collect_options_info()
self.logger.info(f"옵션 정보 수집")
self.option_info = await self.collect_options_info()
self.logger.debug(f"수집된 옵션 정보 : {self.option_info}")
except Exception as e:
# 옵션 처리 중 오류 발생 시 전체 로그 출력
self.logger.error(f"옵션 정보 수집 중 오류 발생: {e}", exc_info=True)
try:
# Vertex AI를 통한 번역 시도
translated_options = await self.vertexAItranslator.translate_options(self.option_info['original_names'], product_name)
self.logger.debug(f"번역된 옵션 입력")
await self.apply_translated_options(translated_options, self.option_info['edit_fields'])
# 4. 옵션 정보 수집 및 번역
self.is_vertext_success = True # 번역 성공
if toggle_states['optionTrnas']:
self.logger.debug(f"옵션 AI번역 : {toggle_states['optionTrnas']}")
except ValueError as ve:
# 안전 필터 예외 처리
if "SAFETY" in str(ve):
self.logger.error(f"안전 필터에 의해 번역 요청이 차단되었습니다. {ve}")
self.logger.debug("퍼센티 자체 AI번역 사용 시도")
await self.page.click(self.ai_option_btn_selector)
self.logger.debug("번역을 위한 5초간 대기")
await asyncio.sleep(5)
self.is_vertext_success = False
self.is_percenty_success = True
try:
# Vertex AI를 통한 번역 시도
translated_options = await self.vertexAItranslator.translate_options(self.option_info['original_names'], product_name)
self.logger.debug(f"번역된 옵션 입력")
await self.apply_translated_options(translated_options, self.option_info['edit_fields'])
# except google.api_core.exceptions.ResourceExhausted as re:
# # 할당량 초과 예외 처리
# self.logger.error(f"Vertex AI 할당량 초과: {re}")
# self.logger.debug("퍼센티 자체 AI번역 사용 시도")
# pyautogui.hotkey('alt', 'q')
# self.logger.debug("번역을 위한 5초간 대기")
# time.sleep(5)
# translation_success = False # 번역 실패
self.is_vertext_success = True # 번역 성공
except Exception as e:
# 기타 예외 처리
self.logger.error(f"번역 처리 중 알 수 없는 오류 발생: {e}", exc_info=True)
except ValueError as ve:
# 안전 필터 예외 처리
if "SAFETY" in str(ve):
self.logger.error(f"안전 필터에 의해 번역 요청이 차단되었습니다. {ve}")
self.logger.debug("퍼센티 자체 AI번역 사용 시도")
await self.page.click(self.ai_option_btn_selector)
self.logger.debug("번역을 위한 5초간 대기")
await asyncio.sleep(5)
self.is_vertext_success = False # 번역 실패
self.is_vertext_success = False
self.is_percenty_success = True
# 번역 성공 여부에 따른 로그
self.logger.debug(f"[{'VertexAI' if self.is_vertext_success else '퍼센티AI'}] 를 이용한 옵션번역 성공")
# except google.api_core.exceptions.ResourceExhausted as re:
# # 할당량 초과 예외 처리
# self.logger.error(f"Vertex AI 할당량 초과: {re}")
# self.logger.debug("퍼센티 자체 AI번역 사용 시도")
# pyautogui.hotkey('alt', 'q')
# self.logger.debug("번역을 위한 5초간 대기")
# time.sleep(5)
# translation_success = False # 번역 실패
except Exception as e:
# 기타 예외 처리
self.logger.error(f"번역 처리 중 알 수 없는 오류 발생: {e}", exc_info=True)
self.logger.debug("퍼센티 자체 AI번역 사용 시도")
await self.page.click(self.ai_option_btn_selector)
self.logger.debug("번역을 위한 5초간 대기")
await asyncio.sleep(5)
self.is_vertext_success = False # 번역 실패
self.is_percenty_success = True
# 번역 성공 여부에 따른 로그
self.logger.debug(f"[{'VertexAI' if self.is_vertext_success else '퍼센티AI'}] 를 이용한 옵션번역 성공")
except Exception as e:
# 옵션 처리 중 오류 발생 시 전체 로그 출력
self.logger.error(f"옵션 처리 중 오류 발생: {e}", exc_info=True)
# 5. 옵션 필터링 및 조정
if toggle_states['optionAutoSelect']:
@ -261,11 +275,9 @@ class OptionHandler:
await self.store_selected_options() # 페이지에서 실제 선택된 옵션을 수집하여 저장
# 7. 옵션 이미지 업데이트 (옵션 이미지가 있는 경우)
if toggle_states['optionIMGTrans']:
self.logger.debug(f"옵션 이미지번역(옵션 이미지가 있는 경우만) : {toggle_states['optionIMGTrans']}")
for index, option_image_url in enumerate(self.option_info.get('option_images', []), start=1):
option_name = translated_options.get(f'trans_option_{index}', f'옵션_{index}')
await self.update_option_image(index, option_image_url, product_name, option_name, self.debug_flag)
if toggle_states.get('optionIMGTrans'):
self.logger.debug(f"옵션 이미지 번역을 시작합니다.")
await self.update_option_image(toggle_states, debug_flag=self.debug_flag)
# 8. A-Z or 1-99 button 클릭
@ -654,92 +666,93 @@ class OptionHandler:
async def low_order_click(self):
self.logger.debug("가격 낮은 순 정렬을 클릭합니다.")
await self.page.click(self.low_order_button_locator)
async def update_option_image(self, index, option_image_url, product_name, option_name, debug_flag=False):
async def update_option_image(self, toggle_states, debug_flag=False):
"""
옵션 이미지가 존재할 경우, 기존 이미지를 삭제하고 번역된 이미지를 추가하는 메서드.
옵션 이미지가 존재할 경우, 제외된 옵션이 아닌 경우 번역하여 업데이트하는 메서드.
:param index: 옵션 인덱스.
:param option_image_url: 옵션 이미지 URL.
:param product_name: 상품명.
:param option_name: 옵션명.
:param debug: 디버그 모드일 경우 이미지를 삭제하지 않음 (기본값 False).
:param debug_flag: 디버그 모드일 경우 임시 이미지를 삭제하지 않음 (기본값 False).
"""
# main.py 실행 폴더의 tmp_images 폴더 경로 설정
base_dir = os.path.dirname(os.path.abspath(__file__)) # main.py 위치 확인
temp_dir = os.path.join(base_dir, "tmp_images") # tmp_images 폴더 경로 설정
os.makedirs(temp_dir, exist_ok=True) # 폴더가 없으면 생성
try:
# 이미지가 없을 경우 메서드 종료
if not option_image_url:
self.logger.debug(f"{index}번째 옵션의 이미지가 존재하지 않아 작업을 종료합니다.")
return
# 모든 옵션 상자 요소 가져오기
option_boxes = await self.page.query_selector_all(self.option_box_selector)
total_options = len(option_boxes)
self.logger.debug(f"{total_options}개의 옵션 이미지 번역을 시작합니다.")
self.logger.debug(f"{index}번째 옵션의 이미지를 업데이트합니다.")
# 각 옵션 상자를 인덱스로 순회
for index in range(1, total_options + 1):
# 선택자에서 인덱스를 반영해 동적 선택자를 생성
excluded_marker_selector = self.excluded_option_marker.format(index=index)
delete_button_selector = self.delete_button_selector.format(index=index)
add_button_selector = self.add_button_selector.format(index=index)
delete_button_selector = self.delete_button_selector_template.format(index=index)
confirm_delete_button_locator = self.confirm_delete_button_locator
add_button_selector = self.add_button_selector_template.format(index=index)
file_input_locator = self.file_input_locator
# 기존 이미지 삭제 (삭제 버튼이 존재할 경우)
delete_button = await self.page.query_selector(delete_button_selector)
# 제외된 옵션 확인
excluded_marker = await self.page.query_selector(excluded_marker_selector)
if excluded_marker:
self.logger.debug(f"{index}번째 옵션은 제외된 옵션입니다. 번역을 생략합니다.")
continue
if delete_button:
self.logger.debug(f"{index}번째 옵션의 기존 이미지를 삭제합니다.")
await delete_button.click()
# 옵션 이미지 URL 가져오기
option_image = await option_boxes[index - 1].query_selector("img")
if not option_image:
self.logger.debug(f"{index}번째 옵션에 이미지가 없습니다. 다음 옵션으로 이동합니다.")
continue
# 삭제 확인 버튼 클릭
confirm_delete_button = await self.page.query_selector(confirm_delete_button_locator)
if confirm_delete_button:
self.logger.debug(f"삭제 확인버튼 클릭")
await confirm_delete_button.click()
self.logger.debug(f"{index}번째 옵션의 이미지가 삭제되었습니다.")
else:
self.logger.debug(f"삭제 확인 버튼을 찾을 수 없습니다.")
option_image_url = await option_image.get_attribute("src")
self.logger.debug(f"{index}번째 옵션 이미지 URL: {option_image_url}")
# 이미지 번역 후 추가
# 이미지 번역 및 업로드
translated_image_path = os.path.join(temp_dir, f"translated_option_{index}.png") # 이미지 저장 경로 설정
# 디렉토리가 존재하지 않으면 생성
self.logger.debug("이미지 저장 경로 설정")
translated_image_path = f"tmp_image/{product_name}-{option_name}-{index}.png"
if not os.path.exists('tmp_image'):
os.makedirs('tmp_image')
self.logger.debug("이미지 임시저장폴더가 존재하지 않아 생성.")
self.logger.debug(f"옵션 이미지 번역")
await self.whale_translator.translate_image(option_image_url)
self.clipboardImageManager.process_clipboard(option_image_url, translated_image_path)
try:
# 이미지 번역
self.logger.debug(f"{index}번째 옵션의 이미지 번역 시도")
is_success_translated = self.whale_translator.translate_image(option_image_url)
self.clipboardImageManager.process_clipboard(option_image_url, is_success_translated, toggle_states, translated_image_path)
self.logger.debug(f"{index}번째 옵션의 번역 이미지 저장 완료: {translated_image_path}")
# 이미지 업로드 버튼 클릭 (옵션 이미지가 없는 경우)
add_button = await self.page.query_selector(add_button_selector)
if is_success_translated and os.path.exists(translated_image_path):
# 삭제 버튼 클릭
delete_button = await self.page.query_selector(delete_button_selector)
self.logger.debug(f"{index}번째 옵션의 이미지 삭제 버튼 가져오기")
if add_button:
await add_button.click()
if delete_button:
await delete_button.click()
self.logger.debug(f"{index}번째 옵션의 이미지 삭제 버튼 클릭")
confirm_delete_button = await self.page.wait_for_selector(self.confirm_delete_button_selector)
self.logger.debug(f"{index}번째 옵션의 이미지 삭제확인 버튼 가져오기")
if confirm_delete_button:
await confirm_delete_button.click()
self.logger.debug(f"{index}번째 옵션의 기존 이미지가 삭제되었습니다.")
# '+ 버튼' 클릭 후 파일 업로드
self.logger.debug(f"{index}번째 옵션의 이미지추가 버튼 가져오기")
add_button = await self.page.query_selector(add_button_selector)
self.logger.debug(f"{index}번째 옵션의 이미지추가 버튼 : {add_button}")
if add_button:
await add_button.click()
self.logger.debug(f"{index}번째 옵션의 이미지 추가 버튼 클릭")
file_upload_button = await self.page.wait_for_selector(self.file_upload_button_selector)
self.logger.debug(f"{index}번째 옵션의 파일업로드 버튼 가져오기")
await file_upload_button.set_input_files(translated_image_path)
self.logger.debug(f"{index}번째 옵션의 파일 업로드")
# 파일 선택 다이얼로그에서 번역된 이미지 파일 입력
file_input = await self.page.wait_for_selector(file_input_locator, timeout=5000)
await file_input.set_input_files(translated_image_path)
self.logger.debug(f"{index}번째 옵션에 번역된 이미지가 추가되었습니다.")
# 디버그 모드가 아닐 경우, 성공적으로 업로드 후 임시 파일 삭제
if not debug_flag:
import os
if os.path.exists(translated_image_path):
# '이미지 삽입' 버튼 클릭
confirm_upload_button = await self.page.wait_for_selector(self.confirm_upload_button_selector)
await confirm_upload_button.click()
self.logger.debug(f"{index}번째 옵션에 이미지가 업로드되었습니다.")
finally:
# 파일 사용 후 0.5초 대기하여 접근 완료 보장
time.sleep(0.5)
# 디버그 모드가 아닐 경우 임시 파일 삭제
if not debug_flag and os.path.exists(translated_image_path):
os.remove(translated_image_path)
self.logger.debug(f"번역된 이미지 파일이 삭제되었습니다: {translated_image_path}")
self.logger.debug(f"{index}번째 옵션의 임시 번역 이미지 파일 삭제 완료: {translated_image_path}")
except Exception as e:
self.logger.error(f"{index}번째 옵션 이미지 업데이트 중 오류 발생: {e}", exc_info=True)
self.logger.debug(f"원본이미지를 다시 넣습니다")
# 이미지 번역이 실패하면 원본 이미지를 다시 다운로드하여 PIL 이미지로 변환
original_image = await self.download_image_from_url(option_image_url)
if original_image:
# original_image를 로컬에 저장
original_image_path = f"tmp_image/{product_name}-original-{index}.png"
original_image.save(original_image_path)
# 저장된 원본 이미지를 다시 업로드
file_input = await self.page.wait_for_selector(file_input_locator, timeout=5000)
await file_input.set_input_files(original_image_path)
self.logger.debug(f"{index}번째 옵션에 원본 이미지가 업로드되었습니다.")
else:
self.logger.error(f"원본 이미지를 다운로드하는 데 실패했습니다: {option_image_url}")
self.logger.error(f"옵션 이미지 업데이트 중 오류 발생: {e}", exc_info=True)

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

View File

@ -354,8 +354,18 @@ class WhaleTranslator:
# 경로를 인자로 받을경우 해당경로에 파일 저장
if path:
pass # 클립보드의 이미지를 path의 파일로 저장하고 저장경로를 리턴하는 메서드
# path에는 현재 폴더의 tmp_img폴더에 상품명-옵션명 형태로 제공됨
try:
# 클립보드에서 이미지 가져오기
clipboard_image = ImageGrab.grabclipboard()
if clipboard_image:
clipboard_image.save(path, format='PNG')
self.logger.info(f"번역된 이미지가 {path}에 저장되었습니다.")
else:
self.logger.error("클립보드에 이미지가 존재하지 않아 파일로 저장할 수 없습니다.")
return False
except Exception as e:
self.logger.error(f"이미지 저장 중 오류 발생: {e}", exc_info=True)
return False
return True if self.translation_success_flag else False