diff --git a/docs/images/banner.nocolor.png b/docs/images/banner.nocolor.png deleted file mode 100644 index 039f424f..00000000 Binary files a/docs/images/banner.nocolor.png and /dev/null differ diff --git a/docs/images/icon/setting-one.png b/docs/images/icon/setting-one.png deleted file mode 100644 index 6b15eae1..00000000 Binary files a/docs/images/icon/setting-one.png and /dev/null differ diff --git a/pdf2zh/gui.py b/pdf2zh/gui.py index 41019f40..81656c49 100644 --- a/pdf2zh/gui.py +++ b/pdf2zh/gui.py @@ -237,12 +237,12 @@ def translate( transition: background-color 0.2s ease-in; } - .progress-bar-wrap { - border-radius: 8px !important; - } - .progress-bar { - border-radius: 8px !important; - } +.progress-bar-wrap { + border-radius: 8px !important; +} +.progress-bar { + border-radius: 8px !important; +} # .input-file label { # color: #165DFF !important; @@ -257,7 +257,7 @@ def translate( # color: #165DFF !important; # } """, -) as demo1: +) as demo: gr.Markdown("# PDFMathTranslate") with gr.Row(): @@ -280,7 +280,7 @@ def translate( # lang_src = gr.Dropdown( # label="Source Language", # info="Which translation service to use. Some require keys", - # choices=["Google", "DeepL", "DeepLX", "Azure", "OpenAI", "Ollama"], + # choices=["Google", "DeepL", "DeepLX", "Ollama", "Azure"], # value="Google", # ) lang_to = gr.Dropdown( @@ -403,297 +403,6 @@ def on_select_service(value, evt: gr.EventData): ) -class EnvSync: - """Two-way synchronization between a variable and its system environment counterpart.""" - - def __init__(self, env_name: str, default_value: str = ""): - self._name = env_name - self._value = os.environ.get(env_name, default_value) - # Initialize the environment variable if it doesn't exist - if env_name not in os.environ: - os.environ[env_name] = default_value - - @property - def value(self) -> str: - """Get the current value, ensuring sync with system env.""" - sys_value = os.environ.get(self._name) - if sys_value != self._value: - self._value = sys_value - return self._value - - @value.setter - def value(self, new_value: str): - """Set the value and sync with system env.""" - self._value = new_value - os.environ[self._name] = new_value - - def __str__(self) -> str: - return self.value - - def __bool__(self) -> bool: - return bool(self.value) - - -# Global setup -with gr.Blocks( - title="PDFMathTranslate - PDF Translation with preserved formats", - theme=gr.themes.Default( - primary_hue=custom_blue, spacing_size="md", radius_size="lg" - ), - css=""" - # .secondary-text {color: #999 !important;} - footer {visibility: hidden} - .env-warning {color: #dd5500 !important;} - .env-success {color: #559900 !important;} - .logo {border: transparent;} - .logo label {display: none;} - .logo .top-panel {display: none;} - .title {text-align: center;} - .title h1 {color: #999999 !important;} - .question {text-align: center;} - .question h2 {color: #165DFF !important;} - .info-text {text-align: center; margin-top: -5px;} - .info-text p {color: #aaaaaa !important;} - """, -) as demo3: - gr.Markdown(" ", elem_classes=["title"]) - gr.Markdown(" ", elem_classes=["title"]) - gr.Markdown(" ", elem_classes=["title"]) - gr.Markdown(" ", elem_classes=["title"]) - gr.Image("./docs/images/banner.nocolor.png", elem_classes=["logo"], width=400) - gr.Markdown("# Configuration Guide

", elem_classes=["title"]) - gr.Markdown("## Use Google Translate?
", elem_classes=["question"]) - with gr.Row(): - gr.Markdown("") - use_google = gr.Button( - "Yes", - variant="primary", - elem_classes=["secondary-text"], - ) - use_other = gr.Button( - "No", - variant="secondary", - elem_classes=["secondary-text"], - ) - gr.Markdown("") - with gr.Row(): - gr.Markdown("") - gr.Markdown( - "Google Translate", - elem_classes=["info-text"], - ) - gr.Markdown( - "DeepL, OpenAI, and more", - elem_classes=["info-text"], - ) - gr.Markdown("") - # gr.Markdown( - # """- Properly configured.
- # - GitHub: Byaidu/PDFMathTranslate
- # - GUI by: Rongxin""" - # ) - -with gr.Blocks( - title="PDFMathTranslate - PDF Translation with preserved formats", - theme=gr.themes.Default( - primary_hue=custom_blue, spacing_size="md", radius_size="lg" - ), - css=""" - # .secondary-text {color: #999 !important;} - footer {visibility: hidden} - .env-warning {color: #dd5500 !important;} - .env-success {color: #559900 !important;} - .logo {border: transparent; - height: 10vh;} - .logo label {display: none;} - .logo .top-panel {display: none;} - .title {text-align: center; - height: 5vh;} - .title h1 {color: #999999 !important;} - .question {text-align: center;} - .question h2 {color: #165DFF !important;} - .info-text {text-align: center; margin-top: -5px;} - .info-text p {color: #aaaaaa !important;} - - @keyframes pulse-background { - 0% { background-color: #FFFFFF; } - 25% { background-color: #FFFFFF; } - 50% { background-color: #E8F3FF; } - 75% { background-color: #FFFFFF; } - 100% { background-color: #FFFFFF; } - } - - /* Add dashed border to input-file class */ - .input-file { - border: 1.2px dashed #165DFF !important; - border-radius: 6px !important; - # background-color: #ffffff !important; - animation: pulse-background 2s ease-in-out; - transition: background-color 0.4s ease-out; - width: 80vw; - height: 60vh; - margin: 0 auto; - } - - .input-file:hover { - border: 1.2px dashed #165DFF !important; - border-radius: 6px !important; - color: #165DFF !important; - background-color: #E8F3FF !important; - transition: background-color 0.2s ease-in; - box-shadow: 4px 4px 20px rgba(22, 93, 255, 0.1); - } - - - .input-file label { - color: #165DFF !important; - border: 1.2px dashed #165DFF !important; - border-left: none !important; - border-top: none !important; - } - .input-file .top-panel { - color: #165DFF !important; - border: 1.2px dashed #165DFF !important; - border-right: none !important; - border-top: none !important; - } - .input-file .filename { - color: #165DFF !important; - background-color: #FFFFFF !important; - } - .input-file .download { - color: #165DFF !important; - background-color: #FFFFFF !important; - } - .input-file .wrap { - color: #165DFF !important; - } - .input-file .or { - color: #165DFF !important; - } - - .progress-bar-wrap { - border-radius: 8px !important; - } - .progress-bar { - border-radius: 8px !important; - } - - .options-row { - align-items: center; - display: flex; - } - .options-row .wrap { - align-items: center; - justify-content: center; - flex-wrap: wrap; - gap: 1rem;} - - .options-row .form label { - color: #999;} - .options-row .form { - border: none !important; - align-items: center !important;} - .options-row [data-testid="block-info"] { - display: none !important;} - .logo-row { - align-items: center;} - .title-row { - align-items: center;} - .details-row { - align-items: center;} - .hide-frame { - border: none !important;} - .hide-frame .top-panel { - display: none !important;} - .hide-frame label { - display: none !important;} - .options-icon { - height: 2em; - width: 2em; - } - .options-btn { - line-height: var(--line-md); - background-color: #FFFFFF; - border: 1.2px solid var(--checkbox-label-border-color) !important; - border-radius: 6px !important; - # color: var(--checkbox-label-border-color) !important; - color: #999; - transition: background-color 0.2s ease-in; - } - .options-btn:hover { - background-color: #fafafa; - # border: 1.2px solid #fcfcfc !important; - } - """, -) as demo: - with gr.Row(elem_classes=["logo-row"]): - gr.Image("./docs/images/banner.nocolor.png", elem_classes=["logo"]) - with gr.Row(elem_classes=["title-row"]): - gr.Markdown("# PDFMathTranslate", elem_classes=["title"]) - with gr.Row(elem_classes=["input-file-row"]): - gr.File( - label="Upload PDF", - file_count="single", - file_types=[".pdf"], - interactive=True, - elem_classes=["input-file", "secondary-text"], - ) - with gr.Row(elem_classes=["options-row"]): - gr.Markdown("") - # gr.Dropdown( - # ["Google", "DeepL", "DeepLX", "Azure", "OpenAI", "Ollama"], - # value="Google", - # label="Translation Service", - # interactive=True, - # elem_classes=["secondary-text"], - # ) - # gr.Dropdown( - # [ - # "Chinese", - # "English", - # "French", - # "German", - # "Japanese", - # "Korean", - # "Russian", - # "Spanish", - # ], - # value="Chinese", - # label="To", - # interactive=True, - # elem_classes=["secondary-text"], - # scale=2, - # ) - gr.Radio( - ["All Pages", "First Page", "First 5 Pages"], - value="All Pages", - label="Pages", - interactive=True, - elem_classes=["secondary-text"], - scale=2, - ) - gr.Markdown("") - with gr.Row(elem_classes=["options-row"]): - gr.Markdown("") - gr.Markdown("") - # gr.Image( - # "./docs/images/icon/setting-one.png", - # elem_classes=["hide-frame", "options-icon"], - # scale=1, - # ) - # gr.Markdown("Advanced Settings", elem_classes=["secondary-text"]) - gr.Button( - "⚙️ Advanced Options", - variant="secondary", - elem_classes=["options-btn"], - ) - gr.Markdown("") - gr.Markdown("") - # with gr.Row(elem_classes=["details-row"]): - # gr.Markdown("Technical details", elem_classes=["info-text"]) - - def setup_gui(share=False): try: demo.launch(server_name="0.0.0.0", debug=True, inbrowser=True, share=share) diff --git a/pdf2zh/translator.py b/pdf2zh/translator.py index ff82055a..173bade0 100644 --- a/pdf2zh/translator.py +++ b/pdf2zh/translator.py @@ -11,10 +11,6 @@ from azure.ai.translation.text import TextTranslationClient from azure.core.credentials import AzureKeyCredential -import hmac -import hashlib -import time -from datetime import datetime,UTC class BaseTranslator: def __init__(self, service, lang_out, lang_in, model): @@ -62,96 +58,6 @@ def translate(self, text): result = html.unescape(re_result[0]) return result -class TencentTranslator(BaseTranslator): - def sign(self,key, msg): - return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest() - - def __init__(self, service, lang_out, lang_in, model): - lang_out = "zh" if lang_out == "auto" else lang_out - lang_in = "en" if lang_in == "auto" else lang_in - super().__init__(service, lang_out, lang_in, model) - try: - server_url = ( - "tmt.tencentcloudapi.com" - ) - self.secret_id = os.getenv("Tencent_SECRET_ID") - self.secret_key = os.getenv("Tencent_SECRET_KEY") - - except KeyError as e: - missing_var = e.args[0] - raise ValueError( - f"The environment variable '{missing_var}' is required but not set." - ) from e - - self.session = requests.Session() - self.base_link = f"{server_url}" - - def translate(self, text): - text = text[:5000] - data={ - "SourceText":text, - "Source":self.lang_in, - "Target":self.lang_out, - "ProjectId":0 - } - payloadx = dumps(data) - hashed_request_payload = hashlib.sha256(payloadx.encode("utf-8")).hexdigest() - canonical_request = ("POST" + "\n" + - "/" + "\n" + - "" + "\n" + - "content-type:application/json; charset=utf-8\nhost:tmt.tencentcloudapi.com\nx-tc-action:texttranslate\n" + "\n" + - "content-type;host;x-tc-action" + "\n" + - hashed_request_payload) - - timestamp = int(time.time()) - date = datetime.fromtimestamp(timestamp, UTC).strftime("%Y-%m-%d") - credential_scope = date + "/tmt/tc3_request" - hashed_canonical_request = hashlib.sha256(canonical_request.encode("utf-8")).hexdigest() - algorithm = "TC3-HMAC-SHA256" - string_to_sign = (algorithm + "\n" + - str(timestamp) + "\n" + - credential_scope + "\n" + - hashed_canonical_request) - secret_date = self.sign(("TC3" + self.secret_key).encode("utf-8"), date) - secret_service = self.sign(secret_date, "tmt") - secret_signing = self.sign(secret_service, "tc3_request") - signed_headers = "content-type;host;x-tc-action" - signature = hmac.new(secret_signing, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest() - authorization = (algorithm + " " + - "Credential=" + self.secret_id + "/" + credential_scope + ", " + - "SignedHeaders=" + signed_headers + ", " + - "Signature=" + signature) - self.headers = { - "Authorization": authorization, - "Content-Type": "application/json; charset=utf-8", - "Host": "tmt.tencentcloudapi.com", - "X-TC-Action": "TextTranslate", - "X-TC-Region":"ap-beijing", - "X-TC-Timestamp": str(timestamp), - "X-TC-Version": "2018-03-21" - } - - response = self.session.post( - "https://"+self.base_link, - json=data, - headers=self.headers, - ) - # 1. Status code test - if response.status_code == 200: - result = loads(response.text) - else: - raise ValueError("HTTP error: " + str(response.status_code)) - # 2. Result test - try: - result = result['Response']['TargetText'] - return result - except KeyError: - result = "" - raise ValueError("No valid key in Tencent's response") - # 3. Result length check - if len(result) == 0: - raise ValueError("Empty translation result") - return result class DeepLXTranslator(BaseTranslator): def __init__(self, service, lang_out, lang_in, model): @@ -172,11 +78,7 @@ def __init__(self, service, lang_out, lang_in, model): ) from e self.session = requests.Session() - server_url=server_url.rstrip('/') - if auth_key: - self.base_link = f"{server_url}/{auth_key}/translate" - else: - self.base_link = f"{server_url}/translate" + self.base_link = f"{server_url}/{auth_key}/translate" self.headers = { "User-Agent": "Mozilla/4.0 (compatible;MSIE 6.0;Windows NT 5.1;SV1;.NET CLR 1.1.4322;.NET CLR 2.0.50727;.NET CLR 3.0.04506.30)" } @@ -210,6 +112,7 @@ def translate(self, text): raise ValueError("Empty translation result") return result + class DeepLTranslator(BaseTranslator): def __init__(self, service, lang_out, lang_in, model): lang_out='ZH' if lang_out=='auto' else lang_out @@ -315,4 +218,3 @@ def translate(self, text) -> str: translated_text = response[0].translations[0].text return translated_text -