This commit is contained in:
R5600U_PC 2024-10-11 15:28:28 +09:00
parent 1cbb39be05
commit 4b3a146aa6
19 changed files with 69545 additions and 2 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

58
build.py Normal file
View File

@ -0,0 +1,58 @@
import os
import shutil
from cx_Freeze import setup, Executable
import sys
# 기존 build 폴더 삭제
build_dir = "build"
if os.path.exists(build_dir):
print(f"[DEBUG] Deleting existing build directory: {build_dir}")
shutil.rmtree(build_dir)
print(f"[DEBUG] Build directory {build_dir} deleted successfully.")
else:
print(f"[DEBUG] No existing build directory found at: {build_dir}")
# 파이썬 애플리케이션을 패키징하기 위한 setup.py 파일
# base 설정 (윈도우 환경에서만 "Win32GUI" 사용)
base = None
if sys.platform == "win32":
base = "Win32GUI"
print(f"[DEBUG] Platform is Windows. Setting base to: {base}")
else:
print(f"[DEBUG] Platform is not Windows. Base set to: {base}")
# 빌드 옵션 설정
build_exe_options = {
"packages": [
"os", "ctypes", "PyQt5.QtWidgets", "PyQt5.QtCore", "PyQt5.QtGui",
"pyautogui", "pyperclip", "bs4", "requests", "vertexai", "pyvda", "cv2", "numpy", "PIL",
"playwright.sync_api", "re", "time", "win32gui", "win32con"
],
"include_files": ["leensoo1nt.json", "prompt.json"], # 추가 파일 포함 (필요한 리소스 파일 지정)
"excludes": [
"tkinter", "_tkinter", "Tkconstants", "Tcl", "AppKit", "Quartz", "Xlib", "IPython", "matplotlib"
], # 불필요한 모듈 제외
}
print(f"[DEBUG] Build options set: {build_exe_options}")
# 실행 파일 설정
executables = [
Executable(
script="main.py",
base=base,
target_name="AutoTrans1.exe",
icon=None # 아이콘 파일 경로가 있다면 지정 가능
)
]
print(f"[DEBUG] Executable configuration set: {executables}")
# setup 함수 호출
setup(
name="AutoTrans1",
version="1.0",
description="Python Application for Image Translation",
options={"build_exe": build_exe_options},
executables=executables
)
print("[DEBUG] Setup process complete.")

Binary file not shown.

View File

@ -0,0 +1,63 @@
## Why this file is included
This program has been frozen with cx_Freeze. The freezing process
resulted in certain components from the cx_Freeze software being included
in the frozen application, in particular bootstrap code for launching
the frozen python script. The cx_Freeze software is subject to the
license set out below.
# Licensing
- Copyright © 2020-2024, Marcelo Duarte.
- Copyright © 2007-2019, Anthony Tuininga.
- Copyright © 2001-2006, Computronix (Canada) Ltd., Edmonton, Alberta,
Canada.
- All rights reserved.
NOTE: This license is derived from the Python Software Foundation
License which can be found at
<https://docs.python.org/3/license.html#psf-license-agreement-for-python-release>
## License for cx_Freeze
1. This LICENSE AGREEMENT is between the copyright holders and the
Individual or Organization ("Licensee") accessing and otherwise
using cx_Freeze software in source or binary form and its associated
documentation.
2. Subject to the terms and conditions of this License Agreement, the
copyright holders hereby grant Licensee a nonexclusive,
royalty-free, world-wide license to reproduce, analyze, test,
perform and/or display publicly, prepare derivative works,
distribute, and otherwise use cx_Freeze alone or in any derivative
version, provided, however, that this License Agreement and this
notice of copyright are retained in cx_Freeze alone or in any
derivative version prepared by Licensee.
3. In the event Licensee prepares a derivative work that is based on or
incorporates cx_Freeze or any part thereof, and wants to make the
derivative work available to others as provided herein, then
Licensee hereby agrees to include in any such work a brief summary
of the changes made to cx_Freeze.
4. The copyright holders are making cx_Freeze available to Licensee on
an "AS IS" basis. THE COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT
LIMITATION, THE COPYRIGHT HOLDERS MAKE NO AND DISCLAIM ANY
REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY
PARTICULAR PURPOSE OR THAT THE USE OF CX_FREEZE WILL NOT INFRINGE
ANY THIRD PARTY RIGHTS.
5. THE COPYRIGHT HOLDERS SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER
USERS OF CX_FREEZE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL
DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE
USING CX_FREEZE, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE
POSSIBILITY THEREOF.
6. This License Agreement will automatically terminate upon a material
breach of its terms and conditions.
7. Nothing in this License Agreement shall be deemed to create any
relationship of agency, partnership, or joint venture between the
copyright holders and Licensee. This License Agreement does not
grant permission to use copyright holder's trademarks or trade name
in a trademark sense to endorse or promote products or services of
Licensee, or any third party.
8. By copying, installing or otherwise using cx_Freeze, Licensee agrees
to be bound by the terms and conditions of this License Agreement.
Computronix® is a registered trademark of Computronix (Canada) Ltd.

View File

@ -0,0 +1,13 @@
{
"type": "service_account",
"project_id": "igneous-primacy-409723",
"private_key_id": "9a9816ba7d7bcde45bc1f0f0f984586ad753022d",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCzx0uJieV+r8PU\ntdVrWrbpbMOXR0SIhCVKkM1GWEOF+p6c5Hd3WZz09ALdBWtIQkGNIodzwO4nKh3h\n9F0dNviY6zB86co6UkpdivOm+w6EOBA0qQSF5dCQsvsJ6FyWqZgNPBfZonlk96Hy\nCNtNbkUqxTEPXJQ751WiH0Ke9e6jhPQ9g2ORmDrW1ANNGD4r1dz9GUEegWkFouGE\nsjPgwXEO62i3cFxUuRNMFEE/bvIB/VNLYMqbo4osGfTXopl9N+lW0MJ0sINVnZaI\nImnU6I6F9NMRb1PjkXD/FsLl6lbE82dbZDTdq11rjA7KQqBNXne58DVwE3/dmowi\n3NaGdqkjAgMBAAECggEAAZbnNTXPeaBoxR5kKBbUFyw93Cv4kEoj82g/w8wGQ6og\nKE5hYATCz6MK8ScHrzhv4snX75hYgrAiWlvtltNkc9o75vEcgJwSyfWBr7BBsb4k\nAffBKDJ6P9+MFl3EIYMpxiHlT4Pag3sob/Wq8Y6ZK6sQXkOLR2VzD80G9AxEBZTt\n1Asa9lBXSnK5NCYLsRRX765YysrsQXd8tk6oqsLmcigWCr75nKgbELxiszOTKtLT\npb50y8cb0kDfMUXOltWojGIkhOKetbzmWA3EgXIIa75s9z8tUVE+vO6kSq3TuQXH\nwL+IwatWRlrco3G1LGsHtw2nPR2mljcCVZjvT/Z0gQKBgQDmOJIeobqku/bVDxcq\neLYrMV1/X7zTihox33C7w+ruVXB/edJxR+gROWVO9ufTIgfPTzkDkxZYvTiHA9hC\nz56vu1b2RNLgiGT9ASOvfR00xRSCE/FfaaN5VlWzGskuFUyWDthkbld78wEFLf19\nutsaV/9+RCGZNoGtRjjw4symSQKBgQDH6MI+wXejhAJyZrr2S5jvIlSKtY12QdU6\n+JhD+3OEBl+OndyfucD5HgjSJnMjnzRMML+mPFlcwqU1VmDeeTqSE/mmvyRAr9rm\nG6Xdh+dOngpqwpq9OGsqc+JZ8JF0bdn6V/g26LjkQgNnRCIFnARQ2UHBDoS2/wHn\n72ShlP9kCwKBgGlinADJp9ag9Gyza7dVao57GoGkIZv0K+mIjuJk3LYdBlJUQbD5\naZH45Bcxjw1nFowfh8nLGv+kHqwvZl+vCsUGzNgOyTlfNltamitK6oOtc6XX2zYB\n9YMlsjU6nb0qotROF2Bh4korAtyMIO3dC08T2TDDn12zRck7y/T43RWBAoGALEEO\nny3c+knC8OhlAxkBJg8HgB1oz4ELXx6hNot3qwZuKPgxWvqYCY3ojf0NCBm6ThOM\nmZRKhApi4Efa8eUMXkIlxhASSm+jmcUNFtl7DyBVVgT2lGTk9GTq+tYSnR+kXZMT\n07P5Gi6y6i1fCrbbDbrKn55DKu+Q0HNiZ5LAZrkCgYAp7Aa1rlbXbyoSXNWTA4Nc\nTZIRKj9Ra2hD2Y2EKjLWqLa9RVK+D9a9I/v1gW59PeRpUY9w674IEZXqOq5jx0D9\nFmwL00Omtfv96q+syq7pqSUmI7hDSd1CfLDaxCGHzGykI98GkjQDz6xPEgTAKRIL\njcB1KaEd55AuovwONS3qKA==\n-----END PRIVATE KEY-----\n",
"client_email": "service-account@igneous-primacy-409723.iam.gserviceaccount.com",
"client_id": "102875157826238718143",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/service-account%40igneous-primacy-409723.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}

View File

@ -0,0 +1,16 @@
{
"option_prompt_template": "질문은 아래와 같아.\n\n가공방법\n1. 특수문자가 있을 경우 제거해줘.\n2. 원본 상품명을 참고해서, 각 옵션의 이름을 최대한 간결하게, 각 옵션의 특징(제품의 스펙을 나타내는 크기,무게,용량,전압,전류,상품코드등)만 남겨줘.\n3. 간결하게 만들어진 각 옵션명을 한국어로 일관되게 번역해줘.\n4. 번역된 옵션 이름 중 같은 이름의 옵션이 있을 경우, 해당옵션들만 원본옵션명에서 특징들을 다시 추출해서 추가해줘.\n5. 가격문의, 문의사항, 견적, 견적문의, 예약금, 선결제, 고객센터 연락 등 옵션명을 바로 알려주지 않고 고객에게 연락을 유도하는 옵션명은 삭제해야 해.\n6. 번역된 옵션명들은 'trans_option_1': '', 'trans_option_2': '', 'trans_option_3': '', 'trans_option_4': '' 와 같은 형식(json)으로 반환해줘.\n\n원본 데이터\n{options}",
"detail_page_prompt_template": "상세 페이지 번역 요청: {detail_page}",
"title_prompt_template": "제목 번역 요청: {title}",
"price_prompt_template": "가격 가공 요청: {price}",
"allowed_special_chars": "!$~()._-=+/",
"special_char_replacements":{
"*" : "X",
"【" : "(",
"】" : ")",
"[" : "(",
"]" : ")",
"," : "."
}
}

Binary file not shown.

Binary file not shown.

BIN
libs/cx_Logging.lib Normal file

Binary file not shown.

58
setup.py Normal file
View File

@ -0,0 +1,58 @@
import os
import shutil
from cx_Freeze import setup, Executable
import sys
# 기존 build 폴더 삭제
build_dir = "build"
if os.path.exists(build_dir):
print(f"[DEBUG] Deleting existing build directory: {build_dir}")
shutil.rmtree(build_dir)
print(f"[DEBUG] Build directory {build_dir} deleted successfully.")
else:
print(f"[DEBUG] No existing build directory found at: {build_dir}")
# 파이썬 애플리케이션을 패키징하기 위한 setup.py 파일
# base 설정 (윈도우 환경에서만 "Win32GUI" 사용)
base = None
if sys.platform == "win32":
base = "Win32GUI"
print(f"[DEBUG] Platform is Windows. Setting base to: {base}")
else:
print(f"[DEBUG] Platform is not Windows. Base set to: {base}")
# 빌드 옵션 설정
build_exe_options = {
"packages": [
"os", "ctypes", "PyQt5.QtWidgets", "PyQt5.QtCore", "PyQt5.QtGui",
"pyautogui", "pyperclip", "bs4", "requests", "vertexai", "pyvda", "cv2", "numpy", "PIL",
"playwright.sync_api", "re", "time", "win32gui", "win32con"
],
"include_files": ["leensoo1nt.json", "prompt.json"], # 추가 파일 포함 (필요한 리소스 파일 지정)
"excludes": [
"tkinter", "_tkinter", "Tkconstants", "Tcl", "AppKit", "Quartz", "Xlib", "IPython", "matplotlib"
], # 불필요한 모듈 제외
}
print(f"[DEBUG] Build options set: {build_exe_options}")
# 실행 파일 설정
executables = [
Executable(
script="main.py",
base=base,
target_name="AutoTrans1.exe",
icon=None # 아이콘 파일 경로가 있다면 지정 가능
)
]
print(f"[DEBUG] Executable configuration set: {executables}")
# setup 함수 호출
setup(
name="AutoTrans1",
version="1.0",
description="Python Application for Image Translation",
options={"build_exe": build_exe_options},
executables=executables
)
print("[DEBUG] Setup process complete.")

146
test/ele_test.py Normal file
View File

@ -0,0 +1,146 @@
import asyncio
from playwright.async_api import async_playwright
from PySide6.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget, QMessageBox
from qasync import QEventLoop
import sys
class CategoryHandler:
def __init__(self, page):
self.page = page
async def handle_category_action(self):
# #productMainContentContainerId 내부에서 클래스 이름 "ant-select ant-select-outlined css-1li46mu ant-select-single ant-select-show-arrow"를 포함한 요소 중 두 번째 요소 찾기
print("[DEBUG] handle_category_action: Locating category container element...")
category_locator = "div#productMainContentContainerId div.ant-select.ant-select-outlined.css-1li46mu.ant-select-single.ant-select-show-arrow >> nth=1"
try:
await self.page.wait_for_selector(category_locator, timeout=5000)
except Exception as e:
print(f"[ERROR] handle_category_action: Timed out waiting for category container element. Error: {e}")
QMessageBox.information(None, "결과", f"카테고리 컨테이너 요소를 찾는 데 실패했습니다: {e}")
return
category_element = self.page.locator(category_locator)
count = await category_element.count()
print(f"[DEBUG] handle_category_action: Number of elements found with locator '{category_locator}': {count}")
if count == 0:
print(f"[ERROR] handle_category_action: Category container element not found using locator '{category_locator}'!")
QMessageBox.information(None, "결과", "카테고리 컨테이너 요소를 찾을 수 없습니다.")
return
# "인증필요"와 카테고리 텍스트 추출
print("[DEBUG] handle_category_action: Extracting '인증필요' and category text...")
certification_text = ""
category_text = ""
try:
cert_needed_locator = category_element.locator("div.ant-col.css-1li46mu:nth-child(1)")
certification_text = await cert_needed_locator.inner_text()
print(f"[DEBUG] handle_category_action: Certification text found - '{certification_text}'")
if "인증필요" in certification_text:
# 인증필요가 있는 경우 두 번째 요소가 카테고리 텍스트
category_text_locator = category_element.locator("div.ant-col.css-1li46mu:nth-child(2)")
category_text = await category_text_locator.inner_text()
else:
# 인증필요가 없는 경우 첫 번째 요소가 카테고리 텍스트
category_text = certification_text
certification_text = "" # 인증필요가 없으므로 초기화
except Exception:
# 인증필요가 없는 경우 첫 번째 요소가 카테고리 텍스트
print("[DEBUG] handle_category_action: Certification text not found. Assuming first element is category text.")
category_text_locator = category_element.locator("div.ant-col.css-1li46mu:nth-child(1)")
category_text = await category_text_locator.inner_text()
full_text = f"{certification_text} {category_text}".strip()
print(f"[DEBUG] handle_category_action: Full text - '{full_text}'")
QMessageBox.information(None, "검색 결과", f"카테고리 텍스트: {full_text}")
# 카테고리 텍스트에 '인증'이라는 단어가 포함되어 있는지 검사
if "인증" in full_text:
print("[INFO] 인증 필요 카테고리입니다. 인증 절차를 진행합니다.")
# 인증이 필요한 경우 수행할 작업
await self.perform_certification_action()
else:
print("[INFO] 인증이 필요하지 않은 카테고리입니다.")
# 인증이 필요하지 않은 경우 수행할 작업
await self.perform_standard_action()
async def perform_certification_action(self):
# 인증 절차를 진행하는 코드 작성
print("[DEBUG] perform_certification_action: Starting certification process...")
# 예시: 특정 버튼 클릭하기
await self.page.click("button:has-text('인증 시작')")
print("[INFO] perform_certification_action: Certification process completed.")
async def perform_standard_action(self):
# 인증이 필요하지 않은 경우의 일반적인 작업 코드 작성
print("[DEBUG] perform_standard_action: Performing standard action...")
# 예시: 다음 단계로 이동
await self.page.click("button:has-text('다음 단계')")
print("[INFO] perform_standard_action: Standard action completed.")
async def run_playwright():
print("[DEBUG] run_playwright: Launching Playwright...")
playwright = await async_playwright().start()
browser = await playwright.chromium.launch(headless=False)
page = await browser.new_page()
print("[DEBUG] run_playwright: Navigating to https://www.percenty.co.kr...")
await page.goto("https://www.percenty.co.kr") # 실제 페이지 URL로 변경하세요
print("[INFO] run_playwright: Page loaded successfully.")
return page, browser, playwright
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Playwright 테스트")
self.setGeometry(100, 100, 400, 300)
self.page = None
self.browser = None
self.playwright = None
# 버튼 생성
self.init_button = QPushButton("Playwright 실행")
self.init_button.clicked.connect(self.run_playwright_button)
self.check_button = QPushButton("요소 검사 및 메시지 출력")
self.check_button.clicked.connect(self.check_category_button)
self.check_button.setEnabled(False)
# 레이아웃 설정
layout = QVBoxLayout()
layout.addWidget(self.init_button)
layout.addWidget(self.check_button)
self.setLayout(layout)
def run_playwright_button(self):
print("[DEBUG] run_playwright_button: Playwright 실행 버튼 클릭됨.")
asyncio.create_task(self.init_playwright())
async def init_playwright(self):
print("[DEBUG] init_playwright: Initializing Playwright...")
self.page, self.browser, self.playwright = await run_playwright()
self.check_button.setEnabled(True)
print("[INFO] init_playwright: Playwright initialized and check button enabled.")
def check_category_button(self):
if self.page:
print("[DEBUG] check_category_button: 요소 검사 버튼 클릭됨.")
asyncio.create_task(self.handle_category_action())
async def handle_category_action(self):
print("[DEBUG] handle_category_action: Handling category action...")
handler = CategoryHandler(self.page)
await handler.handle_category_action()
print("[INFO] handle_category_action: Category check completed.")
if __name__ == "__main__":
print("[DEBUG] Main: Starting application...")
app = QApplication(sys.argv)
loop = QEventLoop(app)
asyncio.set_event_loop(loop)
window = MainWindow()
window.show()
with loop:
sys.exit(loop.run_forever())

View File

@ -1,4 +1,4 @@
import os
import os, sys
import json
from vertexai.generative_models import GenerativeModel
@ -31,7 +31,18 @@ class VertexAITranslator:
:return: 파싱된 JSON 데이터.
"""
try:
prompt_path = os.path.join(os.path.dirname(__file__), 'prompt.json')
# prompt_path = os.path.dirname(sys.executable) if getattr(sys, 'frozen', False) else os.path.dirname(__file__)
# prompt_path = os.path.join(os.path.dirname(__file__), 'prompt.json')
if getattr(sys, 'frozen', False):
# 빌드된 실행 파일일 경우 실행 파일 위치를 기반으로 경로 설정
bundle_dir = sys._MEIPASS
else:
# 개발 환경일 경우 현재 파일의 경로를 사용
bundle_dir = os.path.dirname(os.path.abspath(__file__))
prompt_path = os.path.join(bundle_dir, "prompt.json")
self.logger.debug(f"프롬프트 파일 경로: {prompt_path}")
with open(prompt_path, 'r', encoding='utf-8') as file:
prompt_data = json.load(file)