快捷翻译脚本

通过快捷键将剪切板中的内容进行翻译,并将结果放到剪切板中。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
"""
通过监听快捷键快速实现指定功能。
监听快捷键 [Alt + O], 从剪切板拿到图片数据,通过调用腾讯AI的OCR接口,获得返回后的文本,将OCR的文本放入剪切板中。

Python Version: 3.12.2

依赖:
win10toast==0.9  -- 向操作系统发送通知
pywin32==223     -- Windons API 库
Pillow==10.4.0   -- PIL 图像处理库
keyboard==0.13.5 -- 使用这个小型Python库完全控制你的键盘。挂钩全局事件、注册热键、模拟按键等等。
requests==2.32.3 -- HTTP请求库

快速安装:
pip install win10toast==0.9 pywin32==223 Pillow==10.4.0 keyboard==0.13.5 requests==2.32.3

"""

import base64
import datetime
import io
import json
import logging
import random
import hashlib
import hmac
import time
import functools
from pathlib import Path
from urllib.parse import urlparse

import requests
import keyboard
import pyperclip
import win32clipboard as wc
from PIL import Image
from win10toast import ToastNotifier

logger = logging.getLogger("root")
FILE_DIR = Path(__file__).parent.absolute()
keys = json.loads(FILE_DIR.joinpath("self_config.json").read_text())
s_keys = keys["tencent_key"]


def send_notication(title, text, duration=3):
    ToastNotifier().show_toast(title=title, msg=text, duration=duration, threaded=True)


def get_image_from_clipboard():
    try:
        wc.OpenClipboard()
        if wc.IsClipboardFormatAvailable(wc.CF_DIB):
            # Get the device-independent bitmap (DIB) format data
            dib = wc.GetClipboardData(wc.CF_DIB)
            return Image.open(io.BytesIO(dib))
    except Exception as e:
        logger.error(f"Error reading image from clipboard: {e}")
        return 0
    finally:
        wc.CloseClipboard()


def most_english(text) -> bool:
    """字符串中大多数是英语"""
    if len(text) == 0:
        raise ValueError("空字符串.")
    ec_num = 0
    for c in text:
        if c.isalpha and "a" <= c.lower() <= "z":
            ec_num += 1
    if ec_num / len(text) > 0.5:
        return True
    return False


@functools.lru_cache(25)
def translate_api(text, from_lang="auto", to_lang="zh") -> list[dict[str, str]]:
    """翻译API,

    return  src, dst
    """
    url = "http://api.fanyi.baidu.com/api/trans/vip/translate"
    salt = random.randint(32768, 65536)
    appid, appkey = keys["baidu_translate"]
    sign = hashlib.md5((appid + text + str(salt) + appkey).encode("utf-8")).hexdigest()
    resp = requests.post(
        url=url,
        headers={"Content-Type": "application/x-www-form-urlencoded"},
        params={
            "appid": appid,
            "q": text,
            "from": from_lang,
            "to": to_lang,
            "salt": salt,
            "sign": sign,
        },
    )
    if resp.status_code != 200:
        raise Exception(resp.text())
    return resp.json().get("trans_result")


def translate_iamge(image_data: bytes, from_lang="auto", to_lang="zh") -> list:
    """"""
    url = "http://fanyi-api.baidu.com/api/trans/sdk/picture"
    salt = random.randint(32768, 65536)
    appid = "20240531002066479"
    appkey = "05IgcgzWKnf5J7hDKlyK"
    file_md5 = hashlib.md5(image_data).hexdigest()
    cuid, mac = "APICUID", "mac"
    sign = hashlib.md5(
        (appid + file_md5 + str(salt) + cuid + mac + appkey).encode()
    ).hexdigest()
    payload = {
        "from": from_lang,
        "to": to_lang,
        "appid": appid,
        "salt": salt,
        "sign": sign,
        "cuid": cuid,
        "mac": mac,
    }
    image = {"image": ("translate-iamge", image_data, "multipart/form-data")}
    resp = requests.post(url, params=payload, files=image)
    if resp.status_code != 200:
        raise Exception(resp.text())
    return resp.json().get("data", {}).get("content", [])



def translate():
    # 从剪贴板读取数据
    keyboard.send("ctrl+c")
    clipb_data = pyperclip.paste()
    if not clipb_data:
        logger.error("翻译失败: 未从剪切板获取到数据")
        send_notication("翻译失败", "未从剪切板获取到数据")
        return

    logger.debug("剪贴板内容: %s", clipb_data)

    # 处理剪贴板数据
    processed_data = translate_api(
        clipb_data,
        to_lang="zh" if most_english(clipb_data) else "en",
    )
    # processed_data = json.dumps(processed_data, ensure_ascii=False, indent=2)
    processed_data = "\n".join([l.get("dst") for l in processed_data])

    # 将处理后的数据放回剪贴板
    pyperclip.copy(processed_data)
    # keyboard.send("F3")
    send_notication("翻译结果已经放入剪切板", processed_data)
    logger.debug("处理后的数据已放回剪贴板: %s", processed_data)



if __name__ == "__main__":
    # 注册快捷键组合
    keyboard.add_hotkey("ctrl+alt+d", translate, suppress=False)

    print("""1. 监听快捷 [Ctrl+Alt+S], 从剪切板中得到拿到文本数据, 通过调用百度翻译的API接口翻译文本,将翻译后的数据放入剪切板中。
2. 监听快捷键 [Alt + O], 从剪切板拿到图片数据,通过调用腾讯AI的OCR接口,获得返回后的文本,将OCR的文本放入剪切板中。""")

    logging.basicConfig(level="DEBUG")

    # 保持程序运行,直到手动终止
    keyboard.wait()
使用 Hugo 构建
主题 StackJimmy 设计