This commit is contained in:
恍兮惚兮 2024-09-13 20:38:34 +08:00
parent 22984f53ec
commit 1a394ccb7f
36 changed files with 594 additions and 141 deletions

View File

@ -248,14 +248,14 @@ class MAINUI:
return
else:
msgs = [
("<msg_info_not_refresh>", globalconfig["rawtextcolor"], False),
("<msg_info_refresh>", globalconfig["rawtextcolor"], True),
("<msg_error_not_refresh>", "red", False),
("<msg_error_refresh>", "red", True),
("<msg_info_not_refresh>", False, False),
("<msg_info_refresh>", False, True),
("<msg_error_not_refresh>", True, False),
("<msg_error_refresh>", True, True),
]
for msg, color, refresh in msgs:
if infotype == msg:
self.translation_ui.displaystatus.emit(text, color, refresh, False)
self.translation_ui.displaystatus.emit(text, color, refresh)
return
def maybeneedtranslateshowhidetranslate(self):
@ -300,7 +300,7 @@ class MAINUI:
self.settin_ui.showandsolvesig.emit(origin, text)
except Exception as e:
msg = str(type(e))[8:-2] + " " + str(e).replace("\n", "").replace("\r", "")
self.translation_ui.displaystatus.emit(msg, "red", True, True)
self.translation_ui.displaystatus.emit(msg, True, True)
return
if not text:
return
@ -501,10 +501,7 @@ class MAINUI:
if iserror:
if currentsignature == self.currentsignature:
self.translation_ui.displaystatus.emit(
globalconfig["fanyi"][classname]["name"] + " " + res,
"red",
False,
False,
globalconfig["fanyi"][classname]["name"] + " " + res, True, False
)
if len(usefultranslators) == 0:
safe_callback("")

View File

@ -1,6 +1,6 @@
from qtsymbols import *
import functools
import qtawesome, winsharedutils
import qtawesome, winsharedutils, threading
from myutils.config import globalconfig
from myutils.utils import get_time_stamp
from gui.usefulwidget import closeashidewindow
@ -21,7 +21,8 @@ class transhist(closeashidewindow):
self.hiderawflag = False
self.hideapiflag = False
self.hidetime = True
self.trace = []
self.lock = threading.Lock()
self.setWindowTitle("历史翻译")
def setupUi(self):
@ -46,7 +47,7 @@ class transhist(closeashidewindow):
baocun = LAction("保存")
copy = LAction("复制到剪贴板")
hideshowraw = LAction("显示原文" if self.hiderawflag else "不显示原文")
hideshowapi = LAction("显示api" if self.hideapiflag else "不显示api")
hideshowapi = LAction("显示翻译器名称" if self.hideapiflag else "不显示翻译器名称")
hidetime = LAction("显示时间" if self.hidetime else "不显示时间")
scrolltoend = LAction("滚动到最后")
menu.addAction(qingkong)
@ -71,32 +72,51 @@ class transhist(closeashidewindow):
with open(ff[0], "w", encoding="utf8") as ff:
ff.write(tb.toPlainText())
elif action == hideshowraw:
self.hiderawflag = not self.hiderawflag
self.refresh()
elif action == hidetime:
self.hidetime = not self.hidetime
self.refresh()
elif action == hideshowapi:
self.hideapiflag = not self.hideapiflag
self.refresh()
elif action == scrolltoend:
scrollbar = self.textOutput.verticalScrollBar()
scrollbar.setValue(scrollbar.maximum())
def getnewsentence(self, sentence):
def refresh(self):
with self.lock:
self.textOutput.clear()
for line in self.trace:
self.textOutput.appendPlainText(self.visline(line))
if self.hiderawflag:
sentence = ""
else:
def visline(self, line):
ii, line = line
if ii == 0:
tm, sentence = line
if self.hiderawflag:
sentence = ""
else:
if not self.hidetime:
sentence = tm + " " + sentence
sentence = "\n" + sentence
return sentence
elif ii == 1:
tm, api, sentence = line
if not self.hideapiflag:
sentence = api + " " + sentence
if not self.hidetime:
sentence = get_time_stamp() + " " + sentence
sentence = "\n" + sentence
self.textOutput.appendPlainText(sentence)
sentence = tm + " " + sentence
return sentence
def getnewsentence(self, sentence):
with self.lock:
tm = get_time_stamp()
self.trace.append((0, (tm, sentence)))
self.textOutput.appendPlainText(self.visline(self.trace[-1]))
def getnewtrans(self, api, sentence):
if not self.hideapiflag:
sentence = api + " " + sentence
if not self.hidetime:
sentence = get_time_stamp() + " " + sentence
self.textOutput.appendPlainText(sentence)
with self.lock:
tm = get_time_stamp()
self.trace.append((1, (tm, api, sentence)))
self.textOutput.appendPlainText(self.visline(self.trace[-1]))

View File

@ -230,7 +230,7 @@ class TranslatorWindow(resizableframeless):
displaymessagebox = pyqtSignal(str, str)
displayres = pyqtSignal(dict)
displayraw1 = pyqtSignal(dict)
displaystatus = pyqtSignal(str, str, bool, bool)
displaystatus = pyqtSignal(str, bool, bool)
showhideuisignal = pyqtSignal()
toolbarhidedelaysignal = pyqtSignal()
showsavegame_signal = pyqtSignal()
@ -328,14 +328,38 @@ class TranslatorWindow(resizableframeless):
color = kwargs.get("color")
clear = True
self.showline(clear=clear, text=text, color=color)
def showstatus(self, res, color, clear, origin):
self.showline(clear=clear, text=res, color=color, origin=origin)
hira = []
isshowhira = isshow_fenci = isfenciclick = False
text = self.cleartext(text)
isshowhira = globalconfig["isshowhira"]
isshow_fenci = globalconfig["show_fenci"]
isfenciclick = globalconfig["usesearchword"] or globalconfig["usecopyword"]
needhira = isshow_fenci or isshowhira or isfenciclick
if needhira:
hira = gobject.baseobject.parsehira(text)
self.showline(
clear=clear,
text=text,
color=color,
hira=hira,
flags=(isshowhira, isshow_fenci, isfenciclick),
)
def showstatus(self, res, isredorrawtextcolor, clear):
if isredorrawtextcolor:
color = "red"
else:
color = globalconfig["rawtextcolor"]
self.showline(clear=clear, text=res, color=color, origin=False)
def cleartext(self, text):
text = text.replace("\t", " ")
text = text.replace("\r", "\n")
text = text.replace("\u2028", "\n")
text = text.replace("\u2029", "\n")
lines = text.split("\n")
newlines = []
for line in lines:
@ -349,13 +373,14 @@ class TranslatorWindow(resizableframeless):
text = kwargs.get("text", None)
color = kwargs.get("color", "black")
iter_context = kwargs.get("iter_context", None)
hira = kwargs.get("hira", [])
flags = kwargs.get("flags", None)
if clear:
self.translate_text.clear()
if text is None:
return
text = self.cleartext(text)
atcenter = globalconfig["showatcenter"]
if iter_context:
@ -367,24 +392,12 @@ class TranslatorWindow(resizableframeless):
iter_context_class, origin, atcenter, text, color
)
else:
hira = []
isshowhira = isshow_fenci = isfenciclick = False
if origin:
isshowhira = globalconfig["isshowhira"]
isshow_fenci = globalconfig["show_fenci"]
isfenciclick = (
globalconfig["usesearchword"] or globalconfig["usecopyword"]
)
needhira = isshow_fenci or isshowhira or isfenciclick
if needhira:
hira = gobject.baseobject.parsehira(text)
self.translate_text.append(
origin,
atcenter,
text,
hira,
(isshowhira, isshow_fenci, isfenciclick),
flags,
color,
)
if globalconfig["autodisappear"]:

View File

@ -76,7 +76,7 @@ def grabwindow(app="PNG", callback_origin=None):
if not callback_origin:
gobject.baseobject.translation_ui.displaystatus.emit(
"saved to " + fname, "red", True, True
"saved to " + fname, False, True
)
@threader

View File

@ -201,22 +201,18 @@ def _4_f(line):
return line
def _6_fEX(line):
def _6_fEX(line: str):
srclang = getlangsrc()
white = getlanguagespace(srclang)
line = (
line.replace("\r ", " ")
.replace("\n ", " ")
.replace(" \n", " ")
.replace(" \r", " ")
.replace("\r", white)
.replace("\n", white)
)
return line
while True:
curr = line
for _ in "\r\n\u2928\u2029":
line = line.replace(_ + " ", " ").replace(" " + _, " ")
if line == curr:
break
line = re.sub(r"[\r\n\u2928\u2029]+", white, line)
def _6_f(line):
line = line.replace("\r", "").replace("\n", "")
return line
@ -369,7 +365,7 @@ def POSTSOLVE(line):
"_10": _10_f,
"_1": _1_f,
"_4": _4_f,
"_6": _6_f, # depracated
"_6": _6_fEX, # 废弃,重定向到新的实现
"_6EX": _6_fEX,
"_91": _91_f,
"_92": _92_f,

View File

@ -269,16 +269,15 @@ class TextBrowser(QWidget, dataget):
)
if self.checkskip(origin):
return
isshowhira, isshow_fenci, isfenciclick = flags
if len(tag):
isshowhira, isshow_fenci, isfenciclick = flags
font = self._createqfont(origin)
textlines, linetags = self._splitlinestags(font, tag, text)
text = "\n".join(textlines)
tag = self._join_tags(linetags, True)
self._textbrowser_append(
origin, atcenter, text, tag if isshowhira else [], color
)
if isshow_fenci or isfenciclick:
tag = tag if isshowhira else []
self._textbrowser_append(origin, atcenter, text, tag, color)
if len(tag) and (isshow_fenci or isfenciclick):
self.addsearchwordmask(isshow_fenci, isfenciclick, tag)
def _getqalignment(self, atcenter):

View File

@ -154,6 +154,10 @@
miaobian1: miaobian12_common,
}
function dispatch_text_style_line(style, styleargs, text, args) {
if (text == '') {
text = '<br>'
args.userawhtml = true
}
let ele = regist_style_imp[style](styleargs, text, args);
if (args.userawhtml) {
if (args.atcenter) {
@ -221,13 +225,11 @@
</style>
<script>
function _showhidetranslate(show) {
console.log(show)
let css = ['.lunatranslator_translate{ display: none; }', '.lunatranslator_translate{ display: block; }'][show]
document.getElementById('maybeshowtranslate').innerHTML = css;
safe_calllunaheightchange(document.getElementById(rootdivid).offsetHeight)
}
function _showhideorigin(show) {
console.log(show)
let css = ['.lunatranslator_origin{ display: none; }', '.lunatranslator_origin{ display: block; }'][show]
document.getElementById('maybeshoworigin').innerHTML = css;
safe_calllunaheightchange(document.getElementById(rootdivid).offsetHeight)
@ -238,7 +240,7 @@
if (1 == origin) {
div.classList.add('lunatranslator_origin')
}
else{
else {
div.classList.add('lunatranslator_translate')
}
document.getElementById(rootdivid).appendChild(div);

View File

@ -256,7 +256,6 @@ class TextBrowser(QWidget, dataget):
return currenttype
def _webview_append(self, _id, origin, atcenter, text: str, tag, flags, color):
fmori, fsori, boldori = self._getfontinfo(origin)
fmkana, fskana, boldkana = self._getfontinfo_kana()
kanacolor = self._getkanacolor()

View File

@ -0,0 +1,345 @@
from translator.basetranslator import basetrans
import hashlib, hmac, json
from datetime import datetime
from urllib.parse import quote, unquote
class SdkRequest: ...
text_type = str
binary_type = bytes
def ensure_binary(s, encoding="utf-8", errors="strict"):
"""Coerce **s** to six.binary_type.
For Python 2:
- `unicode` -> encoded to `str`
- `str` -> `str`
For Python 3:
- `str` -> encoded to `bytes`
- `bytes` -> `bytes`
"""
if isinstance(s, binary_type):
return s
if isinstance(s, text_type):
return s.encode(encoding, errors)
raise TypeError("not expecting type '%s'" % type(s))
class Signer(object):
_ENCODE_UTF8 = "utf-8"
_ENCODE_ISO_8859_1 = "iso-8859-1"
_BASIC_DATE_FORMAT = "%Y%m%dT%H%M%SZ"
_ALGORITHM = "SDK-HMAC-SHA256"
_HEADER_X_DATE = "X-Sdk-Date"
_HEADER_HOST = "Host"
_HEADER_AUTHORIZATION = "Authorization"
_HEADER_CONTENT = "X-Sdk-Content-Sha256"
_EMPTY_HASH = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
def __init__(self, credentials):
self._ak, self._sk = credentials
self._hash_func = hashlib.sha256
def _verify_required(self):
if not self._ak:
raise ValueError("ak is required in credentials")
if not self._sk:
raise ValueError("sk is required in credentials")
def sign(self, request):
# type: (SdkRequest) -> SdkRequest
self._verify_required()
if isinstance(request.body, text_type):
request.body = ensure_binary(request.body)
self._process_content_header(request)
t = self._process_header_time(request)
self._process_header_host(request)
signed_headers = self._process_signed_headers(request)
canonical_request = self._process_canonical_request(request, signed_headers)
string_to_sign = self._process_string_to_sign(canonical_request, t)
signature = self._sign_string_to_sign(string_to_sign, self._sk)
auth_value = self._process_auth_header_value(
signature, self._ak, signed_headers
)
request.header_params[self._HEADER_AUTHORIZATION] = auth_value
self.process_request_uri(request)
return request
@classmethod
def _process_content_header(cls, request):
# type: (SdkRequest) -> None
content_type = request.header_params.get("Content-Type")
if content_type and not content_type.startswith("application/json"):
request.header_params[cls._HEADER_CONTENT] = "UNSIGNED-PAYLOAD"
@classmethod
def process_request_uri(cls, request):
# type: (SdkRequest) -> None
canonical_query_string = cls._process_canonical_query_string(request)
request.uri = (
"%s?%s" % (request.resource_path, canonical_query_string)
if canonical_query_string != ""
else request.resource_path
)
@classmethod
def _process_header_time(cls, request):
# type: (SdkRequest) -> datetime
header_time = cls._get_header_ignore_case(request, cls._HEADER_X_DATE)
if header_time is None:
t = datetime.utcnow()
request.header_params[cls._HEADER_X_DATE] = datetime.strftime(
t, cls._BASIC_DATE_FORMAT
)
else:
t = datetime.strptime(header_time, cls._BASIC_DATE_FORMAT)
return t
@classmethod
def _process_header_host(cls, request):
# type: (SdkRequest) -> None
has_host_header = False
for key in request.header_params:
if key.lower() == "host":
has_host_header = True
break
if not has_host_header:
request.header_params["Host"] = request.host
def _hash_hex_string(self, data):
# type: (bytes) -> str
_hash = self._hash_func(data)
return _hash.hexdigest()
def _hmac(self, key, data):
# type: (bytes, bytes) -> bytes
return hmac.new(key, data, digestmod=self._hash_func).digest()
def _process_string_to_sign(self, canonical_request, time):
# type: (str, datetime) -> str
return "%s\n%s\n%s" % (
self._ALGORITHM,
datetime.strftime(time, self._BASIC_DATE_FORMAT),
self._hash_hex_string(ensure_binary(canonical_request)),
)
@classmethod
def _url_encode(cls, s):
# type: (str) -> str
return quote(s, safe="~")
@classmethod
def _get_header_ignore_case(cls, r, header):
# type: (SdkRequest, str) -> str|None
for k in r.header_params:
if k.lower() == header.lower():
return r.header_params[k]
return None
def _process_canonical_request(self, request, signed_headers):
# type: (SdkRequest, dict) -> str
"""
Build a CanonicalRequest from a regular request string
CanonicalRequest consists of several parts:
Part 1. HTTPRequestMethod
Part 2. CanonicalURI
Part 3. CanonicalQueryString
Part 4. CanonicalHeaders
Part 5 SignedHeaders
Part 6 HexEncode(Hash(RequestPayload))
"""
canonical_headers = self._process_canonical_headers(request, signed_headers)
hex_encode = self._process_hash_payload(request)
canonical_uri = self._process_canonical_uri(request)
canonical_query_string = self._process_canonical_query_string(request)
return "%s\n%s\n%s\n%s\n%s\n%s" % (
request.method.upper(),
canonical_uri,
canonical_query_string,
canonical_headers,
";".join(signed_headers),
hex_encode,
)
def _process_hash_payload(self, request):
# type: (SdkRequest) -> str
if not request.body:
return self._EMPTY_HASH
hex_encode = self._get_header_ignore_case(request, self._HEADER_CONTENT)
if hex_encode:
return hex_encode
return self._hash_hex_string(request.body)
def _process_canonical_uri(self, request):
# type: (SdkRequest) -> str
pattens = unquote(request.resource_path).split("/")
uri = []
for v in pattens:
uri.append(self._url_encode(v))
url_path = "/".join(uri)
if url_path[-1] != "/":
url_path = url_path + "/"
return url_path
@classmethod
def process_canonical_query_string(cls, request):
return cls._process_canonical_query_string(request)
@classmethod
def _process_canonical_query_string(cls, request):
# type: (SdkRequest) -> str
params = []
for param in request.query_params:
params.append(param)
params.sort()
canonical_query_param = []
for key, value in params:
k = cls._url_encode(key)
if isinstance(value, list):
value.sort()
for v in value:
kv = "%s=%s" % (k, cls._url_encode(str(v)))
canonical_query_param.append(kv)
elif isinstance(value, bool):
kv = "%s=%s" % (k, cls._url_encode(str(value).lower()))
canonical_query_param.append(kv)
else:
kv = "%s=%s" % (k, cls._url_encode(str(value)))
canonical_query_param.append(kv)
return "&".join(canonical_query_param)
def _process_canonical_headers(self, request, signed_headers):
# type: (SdkRequest, dict) -> str
canonical_headers = []
__headers = {}
for key in request.header_params:
key_encoded = key.lower()
value = request.header_params[key]
value_encoded = str(value).strip()
__headers[key_encoded] = value_encoded
if 1:
request.header_params[key] = value_encoded.encode(
self._ENCODE_UTF8
).decode("iso-8859-1")
for key in signed_headers:
canonical_headers.append(key + ":" + __headers.get(key))
return "\n".join(canonical_headers) + "\n"
@classmethod
def _process_signed_headers(cls, request):
# type: (SdkRequest) -> list
signed_headers = []
for key in request.header_params:
if "_" in key:
continue
signed_headers.append(key.lower())
signed_headers.sort()
return signed_headers
def _sign_string_to_sign(self, string_to_sign, key):
# type: (str, str) -> str
return self._hex(self._hmac(ensure_binary(key), ensure_binary(string_to_sign)))
def _process_auth_header_value(self, signature, app_key, signed_headers):
# type: (str, str, list) -> str
return "%s Access=%s, SignedHeaders=%s, Signature=%s" % (
self._ALGORITHM,
app_key,
";".join(signed_headers),
signature,
)
def _hex(self, data):
if 0:
return "".join("{:02x}".format(ord(c)) for c in ensure_binary(data))
return data.hex()
class Req:
def __init__(self) -> None:
self.header_params = {}
self.query_params = {}
self.method = ""
self.body = b""
self.resource_path = ""
self.host = ""
class TS(basetrans):
def inittranslator(self):
self.cacheproject = {}
def translate(self, query):
self.checkempty(["ak", "endpoint", "sk"])
ak, sk = self.multiapikeycurrent["ak"], self.multiapikeycurrent["sk"]
endpoint = self.multiapikeycurrent["endpoint"].strip()
ends = {"cn-north-4": "nlp-ext.cn-north-4.myhuaweicloud.com"}
end = ends.get(endpoint, ends["cn-north-4"])
if (end, ak, sk) not in self.cacheproject:
params = {
"name": "cn-north-4",
}
r = Req()
r.query_params = params.items()
r.host = "iam.myhuaweicloud.com"
r.resource_path = "/v3/projects"
r.method = "GET"
r = Signer((ak, sk)).sign(r)
response = self.proxysession.get(
"https://iam.myhuaweicloud.com/v3/projects",
params=params,
headers=r.header_params,
)
try:
project_id = response.json()["projects"][0]["id"]
except:
raise Exception(response.json())
self.cacheproject[(end, ak, sk)] = project_id
project_id = self.cacheproject.get((end, ak, sk))
url = f"https://{end}/v1/{project_id}/machine-translation/text-translation"
body = {
"text": query,
"from": self.srclang,
"to": self.tgtlang,
"scene": "common",
}
body = json.dumps(body).encode("utf8")
r = Req()
r.header_params = {
"Content-Type": "application/json",
"X-Project-Id": project_id,
"User-Agent": "huaweicloud-usdk-python/3.0",
}
r.host = end
r.resource_path = f"/v1/{project_id}/machine-translation/text-translation"
r.method = "POST"
r.body = body
r = Signer((ak, sk)).sign(r)
request = self.proxysession.post(url, headers=r.header_params, data=body)
response = request.json()
try:
return response["translated_text"]
except:
raise Exception(response)

View File

@ -1945,6 +1945,12 @@
"color": "blue",
"name": "有道api"
},
"hwcloud": {
"type": "api",
"use": false,
"color": "blue",
"name": "华为云"
},
"cohere": {
"type": "api",
"use": false,

View File

@ -209,6 +209,28 @@
}
}
},
"hwcloud": {
"args": {
"注册网址": "https://www.huaweicloud.com/product/nlpmt.html",
"ak": "",
"sk": "",
"endpoint": "cn-north-4",
"字数统计": "0",
"次数统计": "0"
},
"argstype": {
"注册网址": {
"type": "label",
"islink": true
},
"ak": {
"name": "Access Key Id"
},
"sk": {
"name": "Secret Access Key"
}
}
},
"txhunyuan": {
"args": {
"secret_id": "",

View File

@ -238,7 +238,6 @@
"手动设置代理(ip:port)": "تعيين الوكيل يدويا ( الملكية الفكرية : ميناء )",
"搜索特殊码": "البحث عن رمز خاص",
"文本源": "النص الأصلي",
"不显示api": "لا تظهر API",
"百度api": "بايدو API",
"希伯来语(CP1255)": "العبرية ( CP1255 )",
"确定": "أكّد",
@ -855,5 +854,7 @@
"设为图标": "تعيين رمز",
"还原图标": "استعادة الرموز",
"拉丁语": "اللاتينية",
"显示/隐藏翻译": "إظهار / إخفاء الترجمة"
"显示/隐藏翻译": "إظهار / إخفاء الترجمة",
"不显示翻译器名称": "لا يتم عرض اسم المترجم",
"华为云": "هوا وي يون"
}

View File

@ -221,7 +221,6 @@
"Moji辞书": "MOJi 辭書",
"清空": "清空",
"不显示原文": "不顯示原文",
"不显示api": "不顯示 API",
"字体": "字體",
"飞书": "飛書",
"编辑": "編輯",
@ -855,5 +854,7 @@
"设为图标": "設為圖標",
"还原图标": "還原圖標",
"拉丁语": "拉丁語",
"显示/隐藏翻译": "顯示/隱藏翻譯"
"显示/隐藏翻译": "顯示/隱藏翻譯",
"不显示翻译器名称": "不顯示翻譯器名稱",
"华为云": "華為雲"
}

View File

@ -291,7 +291,6 @@
"显示显示原文按钮": "Zobrazit tlačítko původního textu",
"去除花括号{}": "Odstraňte kudrnaté rovnátka.",
"保留原文": "Zachovat původní text",
"不显示api": "Nezobrazovat API",
"朗读原文": "Přečtěte si původní text nahlas",
"连接成功": "Připojení úspěšné",
"修改游戏字体": "Upravit písmo hry",
@ -855,5 +854,7 @@
"设为图标": "Nastavit jako ikona",
"还原图标": "obnovit ikony",
"拉丁语": "Latinský jazyk",
"显示/隐藏翻译": "Zobrazit/skrýt překlad"
"显示/隐藏翻译": "Zobrazit/skrýt překlad",
"不显示翻译器名称": "Nezobrazovat jméno překladatele",
"华为云": "Hua Weiyun."
}

View File

@ -291,7 +291,6 @@
"显示显示原文按钮": "Schaltfläche Originaltext anzeigen",
"去除花括号{}": "Lockige Klammern entfernen {}",
"保留原文": "Den Originaltext beibehalten",
"不显示api": "API nicht anzeigen",
"朗读原文": "Lesen Sie den Originaltext laut vor",
"连接成功": "Verbindung erfolgreich",
"修改游戏字体": "Spiel-Schriftart ändern",
@ -855,5 +854,7 @@
"设为图标": "Als Symbol festlegen",
"还原图标": "Symbole wiederherstellen",
"拉丁语": "Lateinische Sprache",
"显示/隐藏翻译": "Übersetzung ein-/ausblenden"
"显示/隐藏翻译": "Übersetzung ein-/ausblenden",
"不显示翻译器名称": "Übersetzername nicht anzeigen",
"华为云": "Hua Weiyun"
}

View File

@ -221,7 +221,6 @@
"Moji辞书": "Moji Dictionary",
"清空": "Clear",
"不显示原文": "Don't Display Original Text",
"不显示api": "Don't Display API",
"字体": "Font",
"飞书": "Feishu",
"编辑": "Edit",
@ -855,5 +854,7 @@
"设为图标": "Set as icon",
"还原图标": "restore icons",
"拉丁语": "Latin language",
"显示/隐藏翻译": "Show/Hide Translation"
"显示/隐藏翻译": "Show/Hide Translation",
"不显示翻译器名称": "Do not display translator name",
"华为云": "Hua Weiyun"
}

View File

@ -221,7 +221,6 @@
"Moji辞书": "Moji dict",
"清空": "Vaciado",
"不显示原文": "No muestra el texto original",
"不显示api": "No muestra APIS",
"字体": "Fuente",
"飞书": "Libro volador",
"编辑": "Edición",
@ -855,5 +854,7 @@
"设为图标": "Establecer como icono",
"还原图标": "Restaurar iconos",
"拉丁语": "Latín",
"显示/隐藏翻译": "Mostrar / ocultar traducción"
"显示/隐藏翻译": "Mostrar / ocultar traducción",
"不显示翻译器名称": "No se muestra el nombre del traductor",
"华为云": "Hua weiyun"
}

View File

@ -221,7 +221,6 @@
"Moji辞书": "Moji dict",
"清空": "Vider",
"不显示原文": "Ne pas afficher l'original",
"不显示api": "Ne pas afficher l'API",
"字体": "Les polices",
"飞书": "Le livre volant",
"编辑": "Modifier",
@ -855,5 +854,7 @@
"设为图标": "Faire une icône",
"还原图标": "Restaurer les icônes",
"拉丁语": "Latin",
"显示/隐藏翻译": "Afficher / masquer la traduction"
"显示/隐藏翻译": "Afficher / masquer la traduction",
"不显示翻译器名称": "Ne pas afficher le nom du traducteur",
"华为云": "Huawei Cloud"
}

View File

@ -217,7 +217,6 @@
"Moji辞书": "Dizionario Moji",
"清空": "vuoto",
"不显示原文": "Non visualizzare il testo originale",
"不显示api": "Non visualizzare API",
"字体": "font",
"飞书": "lettera anonima",
"编辑": "modifica",
@ -855,5 +854,7 @@
"设为图标": "Imposta come icona",
"还原图标": "ripristina icone",
"拉丁语": "Lingua latina",
"显示/隐藏翻译": "Mostra/Nascondi traduzione"
"显示/隐藏翻译": "Mostra/Nascondi traduzione",
"不显示翻译器名称": "Non visualizzare il nome del traduttore",
"华为云": "Hua Weiyun"
}

View File

@ -221,7 +221,6 @@
"Moji辞书": "Moji辞書",
"清空": "クリアランス",
"不显示原文": "テキストを表示しない",
"不显示api": "apiを表示しない",
"字体": "フォント",
"飞书": "飛書",
"编辑": "編集",
@ -855,5 +854,7 @@
"设为图标": "アイコンとして設定",
"还原图标": "リストアアイコン",
"拉丁语": "ラテン語",
"显示/隐藏翻译": "翻訳の表示/非表示"
"显示/隐藏翻译": "翻訳の表示/非表示",
"不显示翻译器名称": "翻訳者名を表示しない",
"华为云": "華を雲と為す"
}

View File

@ -221,7 +221,6 @@
"Moji辞书": "Moji dict",
"清空": "비우기",
"不显示原文": "원문을 나타내지 않다",
"不显示api": "api 표시 안 함",
"字体": "글꼴",
"飞书": "비서",
"编辑": "편집",
@ -855,5 +854,7 @@
"设为图标": "아이콘으로 설정",
"还原图标": "복원 아이콘",
"拉丁语": "라틴어",
"显示/隐藏翻译": "번역 표시 / 숨기기"
"显示/隐藏翻译": "번역 표시 / 숨기기",
"不显示翻译器名称": "번역기 이름이 표시되지 않음",
"华为云": "화위운"
}

View File

@ -291,7 +291,6 @@
"显示显示原文按钮": "Originele tekstknop weergeven",
"去除花括号{}": "Krullende beugels verwijderen.",
"保留原文": "De oorspronkelijke tekst behouden",
"不显示api": "API niet weergeven",
"朗读原文": "Lees de oorspronkelijke tekst hardop voor",
"连接成功": "Verbinding succesvol",
"修改游戏字体": "Spellettertype wijzigen",
@ -855,5 +854,7 @@
"设为图标": "Als pictogram instellen",
"还原图标": "pictogrammen herstellen",
"拉丁语": "Latijnse taal",
"显示/隐藏翻译": "Vertaling tonen/verbergen"
"显示/隐藏翻译": "Vertaling tonen/verbergen",
"不显示翻译器名称": "Toon de naam van de vertaler niet",
"华为云": "Hua Weiyun."
}

View File

@ -221,7 +221,6 @@
"Moji辞书": "Słownik Moji",
"清空": "pusty",
"不显示原文": "Nie wyświetlaj oryginalnego tekstu",
"不显示api": "Nie wyświetlaj interfejsu API",
"字体": "pisma",
"飞书": "list anonimowy",
"编辑": "edytuj",
@ -855,5 +854,7 @@
"设为图标": "Ustaw jako ikonę",
"还原图标": "przywróć ikony",
"拉丁语": "Język łaciński",
"显示/隐藏翻译": "Pokaż/ukryj tłumaczenie"
"显示/隐藏翻译": "Pokaż/ukryj tłumaczenie",
"不显示翻译器名称": "Nie wyświetlaj nazwy tłumacza",
"华为云": "Hua Weiyun."
}

View File

@ -291,7 +291,6 @@
"显示显示原文按钮": "Mostrar o botão do texto original",
"去除花括号{}": "Remover as chaves encaracoladas {}",
"保留原文": "Manter o texto original",
"不显示api": "Não mostrar a API",
"朗读原文": "Leia o texto original em voz alta",
"连接成功": "Ligação bem sucedida",
"修改游戏字体": "Modificar o tipo de letra do jogo",
@ -855,5 +854,7 @@
"设为图标": "Definir como ícone",
"还原图标": "restaurar ícones",
"拉丁语": "Língua latina",
"显示/隐藏翻译": "Mostrar/ Esconder a Tradução"
"显示/隐藏翻译": "Mostrar/ Esconder a Tradução",
"不显示翻译器名称": "Não mostrar o nome do tradutor",
"华为云": "Hua Weiyun"
}

View File

@ -221,7 +221,6 @@
"Moji辞书": "Moji dict",
"清空": "Очистить",
"不显示原文": "Не показывать оригинал",
"不显示api": "Не показывать API",
"字体": "Шрифт",
"飞书": "Летающая книга",
"编辑": "Редактирование",
@ -855,5 +854,7 @@
"设为图标": "Установить значок",
"还原图标": "Восстановить значок",
"拉丁语": "Латинский язык",
"显示/隐藏翻译": "Показать / скрыть перевод"
"显示/隐藏翻译": "Показать / скрыть перевод",
"不显示翻译器名称": "Не показывать имя переводчика",
"华为云": "Хуа как облако"
}

View File

@ -291,7 +291,6 @@
"显示显示原文按钮": "Visa originaltextknapp",
"去除花括号{}": "Ta bort lockiga hängslen",
"保留原文": "Behåll originaltexten",
"不显示api": "Visa inte API",
"朗读原文": "Läs originaltexten högt",
"连接成功": "Anslutning lyckad",
"修改游戏字体": "Ändra spelteckensnitt",
@ -855,5 +854,7 @@
"设为图标": "Ange som ikon",
"还原图标": "återställ ikoner",
"拉丁语": "Latinska språk",
"显示/隐藏翻译": "Visa/dölj översättning"
"显示/隐藏翻译": "Visa/dölj översättning",
"不显示翻译器名称": "Visa inte översättarens namn",
"华为云": "Hua Weiyun"
}

View File

@ -291,7 +291,6 @@
"显示显示原文按钮": "แสดงปุ่มแสดงข้อความต้นฉบับ",
"去除花括号{}": "ลบวงเล็บดอกไม้ {}",
"保留原文": "เก็บต้นฉบับไว้",
"不显示api": "ไม่แสดง api",
"朗读原文": "อ่านต้นฉบับ",
"连接成功": "เชื่อมต่อสำเร็จ",
"修改游戏字体": "แก้ไขเกม แบบอักษร",
@ -855,5 +854,7 @@
"设为图标": "ตั้งค่าเป็นไอคอน",
"还原图标": "เรียกคืนไอคอน",
"拉丁语": "ละติน",
"显示/隐藏翻译": "แสดง/ซ่อนการแปล"
"显示/隐藏翻译": "แสดง/ซ่อนการแปล",
"不显示翻译器名称": "ไม่แสดงชื่อแปล",
"华为云": "Huawei เมฆ"
}

View File

@ -221,7 +221,6 @@
"Moji辞书": "Moji Sözlük",
"清空": "boş",
"不显示原文": "Önce metini gösterme",
"不显示api": "api gösterme",
"字体": "typeface",
"飞书": "isimsiz mektup",
"编辑": "edit",
@ -855,5 +854,7 @@
"设为图标": "İşaretçi olarak ayarlayın",
"还原图标": "İşaretçikleri geri yükleyin",
"拉丁语": "Latin dili",
"显示/隐藏翻译": "Çeviri Göster/Gizle"
"显示/隐藏翻译": "Çeviri Göster/Gizle",
"不显示翻译器名称": "Tercüme ismini gösterme",
"华为云": "Hua Weiyun"
}

View File

@ -217,7 +217,6 @@
"Moji辞书": "Словник Moji",
"清空": "порожній",
"不显示原文": "Не показувати початковий текст",
"不显示api": "Не показувати API",
"字体": "тип",
"飞书": "анонімна літера",
"编辑": "редагувати",
@ -855,5 +854,7 @@
"设为图标": "Встановити як піктограму",
"还原图标": "відновити піктограми",
"拉丁语": "Латинська мова",
"显示/隐藏翻译": "Показувати/сховати переклад"
"显示/隐藏翻译": "Показувати/сховати переклад",
"不显示翻译器名称": "Не показувати назву перекладача",
"华为云": "Hua Weiyun"
}

View File

@ -221,7 +221,6 @@
"Moji辞书": "Từ điển Moji",
"清空": "Trống rỗng",
"不显示原文": "Không hiển thị bản gốc",
"不显示api": "Không hiển thị API",
"字体": "Phông chữ",
"飞书": "Sách bay",
"编辑": "Chỉnh sửa",
@ -855,5 +854,7 @@
"设为图标": "Đặt làm biểu tượng",
"还原图标": "Khôi phục biểu tượng",
"拉丁语": "Tiếng Việt",
"显示/隐藏翻译": "Hiện/ẩn bản dịch"
"显示/隐藏翻译": "Hiện/ẩn bản dịch",
"不显示翻译器名称": "Name",
"华为云": "Hoa Vi Vân"
}

View File

@ -291,7 +291,7 @@
"显示显示原文按钮": "",
"去除花括号{}": "",
"保留原文": "",
"不显示api": "",
"不显示翻译器名称": "",
"朗读原文": "",
"连接成功": "",
"修改游戏字体": "",
@ -855,5 +855,6 @@
"选取OCR范围时不透明度": "",
"设为图标": "",
"还原图标": "",
"拉丁语": ""
"拉丁语": "",
"华为云": ""
}

View File

@ -6,7 +6,7 @@
部署方法
1. [部署SakuraLLM到Google Colab](/zh/sakurallmcolab.md)
1. [部署SakuraLLM到在线GPU平台](/zh/sakurallmcolab.md)
2. 其他部署方法可参考 https://github.com/SakuraLLM/SakuraLLM/wiki

View File

@ -1,13 +1,11 @@
## 部署SakuraLLM到Google Colab
## 部署SakuraLLM到在线GPU平台
### 1. 设置内网穿透以将请求转发给llama.cpp服务
注册[ngrok](https://ngrok.com/),分别获取[NGROK_TOKEN](https://dashboard.ngrok.com/get-started/your-authtoken)和[NGROK_DOMAIN](https://dashboard.ngrok.com/cloud-edge/domains),以供后面使用。
也可以不注册**ngrok**,将**NGROK_TOKEN**置为空,则会使用**gradio-tunneling**的随机域名进行内网穿透。
对于**Google Colab**,也可以不注册**ngrok**,将**NGROK_TOKEN**置为空,则会使用**gradio-tunneling**的随机域名进行内网穿透。
若使用**ngrok**,并填写了**NGROK_DOMAIN**,则每次运行时将会使用固定的域名进行内网穿透,否则将会使用随机的域名。
@ -29,13 +27,58 @@
### 2. 部署到Google Colab
### 2. 部署到在线GPU平台
<!-- tabs:start -->
### **飞桨Ai Studio**
* 免费额度为每日登录领取4小时或可累加
<details>
<summary>1. 在<a href="https://aistudio.baidu.com/my/project/private" target="_blank">飞桨Ai Studio</a>中创建项目,注意<strong>项目框架</strong>必须为<strong>PaddlePaddle 3.0.0beta1</strong></summary>
<img src="https://image.lunatranslator.org/zh/sakurallm/paddle.png">
<img src="https://image.lunatranslator.org/zh/sakurallm/paddle2.png">
</details>
<details>
<summary>2. 点击<strong>启动环境</strong>,并选择<strong>V100 16GB</strong>。启动完毕后,进入环境</summary>
<img src="https://image.lunatranslator.org/zh/sakurallm/paddle3.png">
<img src="https://image.lunatranslator.org/zh/sakurallm/paddle4.png">
<img src="https://image.lunatranslator.org/zh/sakurallm/paddle5.png">
</details>
<details>
<summary>3. 下载<a href="https://lunatranslator.org/nginxfile/kaggle_sakurallm.ipynb" target="_blank">ipynb脚本</a>,拖拽到文件区中以上传脚本,双击打开脚本。</summary>
<img src="https://image.lunatranslator.org/zh/sakurallm/paddle8.png">
</details>
<details>
<summary>4. 设置ngrok密钥和域名以及使用的模型</summary>
将注册的ngrok的NGROK_TOKEN和NGROK_DOMAIN填入脚本中。
REPO和MODEL是<code>https://huggingface.co/REPO</code>下的MODEL模型文件名
<img src="https://image.lunatranslator.org/zh/sakurallm/paddle6.png">
</details>
<details>
<summary>5. 运行脚本,等待模型下载,并获取内网穿透地址</summary>
内网穿透地址在下面的log中可以看到。飞桨下载模型速度只有20MB/s大概需要等待5分钟。
<img src="https://image.lunatranslator.org/zh/sakurallm/paddle7.png">
</details>
<details>
<summary>6. 运行结束后,回到项目详情中,主动停止项目,以避免消耗积分。</summary>
再次启动环境时会保持之前的文件,直接从<strong>5</strong>继续开始即可,并且不需要再次下载模型。<br>
<img src="https://image.lunatranslator.org/zh/sakurallm/paddle9.png">
</details>
### **Google Colab**
* 免费时长约为每天四小时,具体时长根据账号历史用量波动
<details>
<summary>1. 在Google drive中安装<strong>Colaboratory</strong>应用</summary>

View File

@ -21,7 +21,7 @@
- [翻译源设置](/zh/guochandamoxing.redirect)
- [如何使用大模型API翻译](/zh/guochandamoxing.md)
- [如何使用大模型离线翻译](/zh/offlinellm.md)
- [如何部署SakuraLLM到Google Colab](/zh/sakurallmcolab.md)
- [如何部署SakuraLLM到在线GPU平台](/zh/sakurallmcolab.md)
- [如何使用调试浏览器翻译](/zh/tiaoshiliulanqi.md)
- [文本处理&翻译优化](/zh/textprocess.redirect)
- [各种文本处理方法的作用和用法](/zh/textprocess.md)

View File

@ -84,36 +84,23 @@
~~**17. 简单字符串替换**~~ 过时的,不再推荐使用,请改用**字符串替换**
~~不止是替换,主要也可以用来过滤。可以将固定的若干乱码字符、反复刷新的倒三角字符等通过替换成空白来进行过滤。~~
~~**18. 转义字符串替换**~~ 过时的,不再推荐使用,请改用**字符串替换**
~~主要是可以支持`\n`来表示换行符,从而实现可以过滤仅在换行符前后出现的字符。~~
~~**19. 正则表达式替换**~~ 过时的,不再推荐使用,请改用**字符串替换**
~~注:**这个输入的内容都是转义字符串**也就是说比如你在外面写python代码`re.sub(r"\n","")`来测试再填入,想把`\n`这两个字符替换掉,实际上这里会替换掉**换行符**,你想在外面测试的话请用`re.sub("\\n","")`这样来测试~~
**20. 去除重复行_ABCDBCDCDD->ABCD**
**17. 去除重复行_ABCDBCDCDD->ABCD**
这个也比较常见。这个出现的原因是有时HOOK的某个显示文本的函数其参数是显示的文本这个函数会再每显示一个字符时都会调用且每次会把参数的字符串指向下一个字符从而导致其实第一次调用其实就已经得到完整的文本了后续每次又输出了剩下的子串直到长度递减为0。例如`恵麻さんは再び液タブへ視線を落とす。麻さんは再び液タブへ視線を落とす。さんは再び液タブへ視線を落とす。んは再び液タブへ視線を落とす。は再び液タブへ視線を落とす。再び液タブへ
視線を落とす。び液タブへ視線を落とす。液タブへ視線を落とす。タブへ視線を落とす。ブへ視線を落とす。へ視線を落とす。視線を落とす。線を落とす。を落とす。落とす。とす。す。。` 经过分析将判断真实的文本应该是`恵麻さんは再び液タブへ視線を落とす。`
**21. 去除重复行_AABABCABCD->ABCD**
**18. 去除重复行_AABABCABCD->ABCD**
这个也比较常见,出现的原因是,每次绘制一个字符,然后绘制下一个字符时都会把前面的字符都再绘制一遍。例如`恵麻恵麻さ恵麻さん恵麻さんは恵麻さんは再恵麻さんは再び恵麻さんは再び液恵麻さんは再び液タ恵麻さんは再び液タブ恵麻さんは再び液タブへ恵麻さんは再び液タブへ視恵麻さんは再び液
タブへ視線恵麻さんは再び液タブへ視線を恵麻さんは再び液タブへ視線を落恵麻さんは再び液タブへ視線を落と恵麻さんは再び液タブへ視線を落とす恵麻さんは再び液タブへ視線を落とす。`经过分析将判断真实的文本应该是`恵麻さんは再び液タブへ視線を落とす。`
**22. 去除重复行_AABABCABCDEEFEFG->ABCDEFG**
**19. 去除重复行_AABABCABCDEEFEFG->ABCDEFG**
这个和上面的类似只不过当有多行文本时会每行单独按照上面的逻辑来重复从而带来了更多的复杂性。由于过于复杂这个处理经常难以正确处理如果遇到了建议写自定义python处理来解决
**23. 自定义python处理**
**20. 自定义python处理**
撰写一个python脚本来进行更加复杂的处理当处理脚本不存在时将自动在userconfig目录下生成`mypost.py`文件和以下模板:
@ -123,11 +110,15 @@ def POSTSOLVE(line):
return line
```
**25. 字符串替换**
**21. 字符串替换**
原`简单字符串替换` `转义字符串替换` `正则表达式替换`的整合,同时可设置`正则`和`转义`两个选项。
原正则表达式替换存在一定缺陷,输入的表达式是默认转义的,因此输入起来非常麻烦。
该处理添加时将默认使用简单替换,激活正则后将使用字符串字面量进行正则处理。仅激活转义后才使用转义字符串进行处理。
不止是替换,主要也可以用来过滤。例如可以将固定的若干乱码字符、反复刷新的倒三角字符等通过替换成空白来进行过滤。
可同时激活`正则`和`转义`两个选项,或仅选择其中一个,或均不激活。
均不激活时,将使用普通的字符串替换。
激活`转义`后,输入的内容都会被视为转义字符串,而非字符串字面量。例如可以使用`\n`来表示换行符,从而实现可以过滤仅在换行符前后出现的字符等。
激活`正则`后,将使用正则表达式替换。
`简单字符串替换` `转义字符串替换` `正则表达式替换`的处理词典在更新后首次运行将自动迁移到新的处理词典中。
`简单字符串替换` `转义字符串替换` `正则表达式替换`不再对新用户提供,但老用户仍然可以正常使用。

View File

@ -29,7 +29,7 @@ include(generate_product_version)
set(VERSION_MAJOR 5)
set(VERSION_MINOR 35)
set(VERSION_PATCH 3)
set(VERSION_PATCH 4)
add_library(pch pch.cpp)
target_precompile_headers(pch PUBLIC pch.h)