jwf-common-python 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jwf_common_python/__init__.py +14 -0
- jwf_common_python/db_utils/__init__.py +6 -0
- jwf_common_python/db_utils/clickhouse.py +124 -0
- jwf_common_python/db_utils/elasticsearch.py +196 -0
- jwf_common_python/db_utils/mysql.py +64 -0
- jwf_common_python/eudic/__init__.py +5 -0
- jwf_common_python/eudic/wordbook.py +211 -0
- jwf_common_python/file_storage/__init__.py +2 -0
- jwf_common_python/file_storage/file_interface.py +29 -0
- jwf_common_python/file_storage/local.py +50 -0
- jwf_common_python/file_storage/tencent_cos.py +65 -0
- jwf_common_python/geography/__init__.py +8 -0
- jwf_common_python/geography/district_amap.py +181 -0
- jwf_common_python/geography/search_amap.py +84 -0
- jwf_common_python/github/__init__.py +5 -0
- jwf_common_python/github/webhooks.py +87 -0
- jwf_common_python/language_utils/__init__.py +34 -0
- jwf_common_python/language_utils/core.py +203 -0
- jwf_common_python/language_utils/files.py +52 -0
- jwf_common_python/language_utils/web.py +117 -0
- jwf_common_python/llm/__init__.py +1 -0
- jwf_common_python/llm/aliyun_qwen.py +10 -0
- jwf_common_python/llm/azure_gpt.py +66 -0
- jwf_common_python/llm/baidu_ernie.py +112 -0
- jwf_common_python/message_queue/__init__.py +7 -0
- jwf_common_python/message_queue/interface.py +49 -0
- jwf_common_python/message_queue/kafka.py +145 -0
- jwf_common_python/message_queue/rabbitmq.py +113 -0
- jwf_common_python/oauth2/__init__.py +0 -0
- jwf_common_python/oauth2/google.py +158 -0
- jwf_common_python/parse_subtitle/__init__.py +6 -0
- jwf_common_python/parse_subtitle/aa.vtt +2364 -0
- jwf_common_python/parse_subtitle/parse_srt_file.py +60 -0
- jwf_common_python/pdf/__init__.py +0 -0
- jwf_common_python/pdf/aaa.py +38 -0
- jwf_common_python/pdf/local_parse.py +259 -0
- jwf_common_python/sms/__init__.py +1 -0
- jwf_common_python/sms/interface.py +7 -0
- jwf_common_python/sms/tencent_sms.py +117 -0
- jwf_common_python/translate/__init__.py +152 -0
- jwf_common_python/translate/_youdao.py +234 -0
- jwf_common_python/translate/microsoft.py +696 -0
- jwf_common_python/translate/tencent.py +194 -0
- jwf_common_python/tts/__init__.py +0 -0
- jwf_common_python/tts/microsoft.py +87 -0
- jwf_common_python/utils/__init__.py +0 -0
- jwf_common_python/utils/image_utils.py +18 -0
- jwf_common_python/utils/tencent_utils.py +51 -0
- jwf_common_python/utils/utils.py +46 -0
- jwf_common_python/video/__init__.py +5 -0
- jwf_common_python/video/merge.py +276 -0
- jwf_common_python/weather/__init__.py +0 -0
- jwf_common_python/weather/amap.py +127 -0
- jwf_common_python/weather/wanwei.py +58 -0
- jwf_common_python/youdao/__init__.py +13 -0
- jwf_common_python/youdao/wordbook.py +88 -0
- jwf_common_python-1.0.0.dist-info/METADATA +669 -0
- jwf_common_python-1.0.0.dist-info/RECORD +60 -0
- jwf_common_python-1.0.0.dist-info/WHEEL +4 -0
- jwf_common_python-1.0.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import logging
|
|
3
|
+
import random
|
|
4
|
+
import time
|
|
5
|
+
import uuid
|
|
6
|
+
from typing import Literal, get_args
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
import requests
|
|
10
|
+
except ImportError:
|
|
11
|
+
raise ImportError("Couldn't import requests. pip install --upgrade requests")
|
|
12
|
+
from requests.models import Response
|
|
13
|
+
|
|
14
|
+
from jwf_common_python.translate import SentenceInfo, Translate, WordInfo
|
|
15
|
+
|
|
16
|
+
LanguageCodeOfYoudao = Literal["zh-CHS", "zh-CHT", "en", "fr", "ja", "de", "es", "ko"]
|
|
17
|
+
LanguageCodeOfBackend = Literal["zh-CN", "zh-TW", "en", "fr", "ja", "de", "es", "ko"]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class YoudaoTranslate(Translate):
|
|
21
|
+
def __init__(self, **kwargs) -> None:
|
|
22
|
+
if not {"YOUDAO_URL", "APP_KEY", "APP_SECRET"}.issubset(kwargs.keys()):
|
|
23
|
+
raise Exception("you need to set YOUDAO_URL,APP_KEY,APP_SECRET")
|
|
24
|
+
self.YOUDAO_URL = kwargs["YOUDAO_URL"]
|
|
25
|
+
self.APP_KEY = kwargs["APP_KEY"]
|
|
26
|
+
self.APP_SECRET = kwargs["APP_SECRET"]
|
|
27
|
+
self._language_code_of_youdao = list(get_args(LanguageCodeOfYoudao))
|
|
28
|
+
|
|
29
|
+
def _encrypt(self, salt, current_time, word):
|
|
30
|
+
signStr = (
|
|
31
|
+
self.APP_KEY + self._truncate(word) + salt + current_time + self.APP_SECRET
|
|
32
|
+
)
|
|
33
|
+
hash_algorithm = hashlib.sha256()
|
|
34
|
+
hash_algorithm.update(signStr.encode("utf-8"))
|
|
35
|
+
return hash_algorithm.hexdigest()
|
|
36
|
+
|
|
37
|
+
def _truncate(self, q):
|
|
38
|
+
if q is None:
|
|
39
|
+
return None
|
|
40
|
+
size = len(q)
|
|
41
|
+
return q if size <= 20 else q[0:10] + str(size) + q[size - 10 : size]
|
|
42
|
+
|
|
43
|
+
def change_language_code(
|
|
44
|
+
self, language_code_of_backend: LanguageCodeOfBackend
|
|
45
|
+
) -> str:
|
|
46
|
+
"""转换语言代码,将language_backend后端的语言代码转换为youdao的语言代码"""
|
|
47
|
+
|
|
48
|
+
match language_code_of_backend:
|
|
49
|
+
case "zh-CN":
|
|
50
|
+
return "zh-CHS"
|
|
51
|
+
case "zh-TW":
|
|
52
|
+
return "zh-CHT"
|
|
53
|
+
case _:
|
|
54
|
+
return language_code_of_backend
|
|
55
|
+
|
|
56
|
+
def _send_request(
|
|
57
|
+
self,
|
|
58
|
+
word: str,
|
|
59
|
+
source_language_code: LanguageCodeOfBackend,
|
|
60
|
+
target_language_code: LanguageCodeOfBackend,
|
|
61
|
+
) -> dict:
|
|
62
|
+
"""_summary_
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
word (str): _description_
|
|
66
|
+
source_language_code (str): 待翻译文本的语言代码
|
|
67
|
+
target_language_code (str): 目标语言代码
|
|
68
|
+
|
|
69
|
+
Raises:
|
|
70
|
+
ValueError: _description_
|
|
71
|
+
ValueError: _description_
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
dict: _description_
|
|
75
|
+
"""
|
|
76
|
+
current_time = str(int(time.time()))
|
|
77
|
+
salt = str(uuid.uuid1())
|
|
78
|
+
sign = self._encrypt(salt=salt, current_time=current_time, word=word)
|
|
79
|
+
|
|
80
|
+
# 解决不同提供商对简体中文的表示问题
|
|
81
|
+
source_language_code = self.change_language_code(source_language_code)
|
|
82
|
+
target_language_code = self.change_language_code(target_language_code)
|
|
83
|
+
assert (
|
|
84
|
+
source_language_code in self._language_code_of_youdao
|
|
85
|
+
), f"youdao不支持 {source_language_code} 语言code"
|
|
86
|
+
assert (
|
|
87
|
+
target_language_code in self._language_code_of_youdao
|
|
88
|
+
), f"youdao不支持 {target_language_code} 语言code"
|
|
89
|
+
|
|
90
|
+
data = {
|
|
91
|
+
"from": source_language_code,
|
|
92
|
+
"to": target_language_code,
|
|
93
|
+
"signType": "v3",
|
|
94
|
+
"curtime": current_time,
|
|
95
|
+
"sign": sign,
|
|
96
|
+
"appKey": self.APP_KEY,
|
|
97
|
+
"salt": salt,
|
|
98
|
+
"q": word,
|
|
99
|
+
# 'vocabId':"您的用户词表ID"
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
response: Response = requests.post(
|
|
104
|
+
self.YOUDAO_URL,
|
|
105
|
+
data=data,
|
|
106
|
+
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
|
107
|
+
)
|
|
108
|
+
except Exception as e:
|
|
109
|
+
raise ValueError(f"youdao translate connect error: {e}")
|
|
110
|
+
if response.status_code != 200:
|
|
111
|
+
raise ValueError(f"youdao translate status error: {response.status_code}")
|
|
112
|
+
return response.json()
|
|
113
|
+
|
|
114
|
+
def translate(
|
|
115
|
+
self,
|
|
116
|
+
word: str,
|
|
117
|
+
source_language_code: LanguageCodeOfBackend,
|
|
118
|
+
target_language_code: LanguageCodeOfBackend,
|
|
119
|
+
) -> dict:
|
|
120
|
+
response: dict = self._send_request(
|
|
121
|
+
word=word,
|
|
122
|
+
source_language_code=source_language_code,
|
|
123
|
+
target_language_code=target_language_code,
|
|
124
|
+
)
|
|
125
|
+
# 频率过快时,自动重试
|
|
126
|
+
num = 1
|
|
127
|
+
while response["errorCode"] in ["411", "412", "2411", "3411", "4411", "11411"]:
|
|
128
|
+
sleep_time: float = round(random.uniform(1, 5), 2)
|
|
129
|
+
logging.warning(f"youdao请求速度过快,{sleep_time}秒后自动重试,进行第{num}次重试")
|
|
130
|
+
time.sleep(sleep_time)
|
|
131
|
+
response = self._send_request(
|
|
132
|
+
word=word,
|
|
133
|
+
source_language_code=source_language_code,
|
|
134
|
+
target_language_code=target_language_code,
|
|
135
|
+
)
|
|
136
|
+
num += 1
|
|
137
|
+
|
|
138
|
+
error_code: str = response["errorCode"]
|
|
139
|
+
if error_code != "0":
|
|
140
|
+
raise ValueError(f"youdao translate error: {word} {error_code=}")
|
|
141
|
+
return response
|
|
142
|
+
|
|
143
|
+
@classmethod
|
|
144
|
+
def format_word_response(cls, response: dict) -> WordInfo:
|
|
145
|
+
# only word
|
|
146
|
+
basic_direction: dict | None = response.get("basic")
|
|
147
|
+
|
|
148
|
+
word: str = response["query"]
|
|
149
|
+
|
|
150
|
+
translation_no_class: list[str] = response["translation"]
|
|
151
|
+
|
|
152
|
+
translation_have_class: list[str] | None = (
|
|
153
|
+
basic_direction.get("explains", []) if basic_direction else []
|
|
154
|
+
)
|
|
155
|
+
translation = {
|
|
156
|
+
"no_class": translation_no_class,
|
|
157
|
+
"have_class": translation_have_class,
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
translation_speak_url: str = response["tSpeakUrl"]
|
|
161
|
+
source_speak_url: str = response["speakUrl"]
|
|
162
|
+
source_speech_uk: str | None = (
|
|
163
|
+
basic_direction.get("uk-speech") if basic_direction else None
|
|
164
|
+
)
|
|
165
|
+
source_speech_us: str | None = (
|
|
166
|
+
basic_direction.get("us-speech") if basic_direction else None
|
|
167
|
+
)
|
|
168
|
+
speakUrl = {
|
|
169
|
+
"translation_speak_url": translation_speak_url,
|
|
170
|
+
"source_speak_url": source_speak_url,
|
|
171
|
+
"source_speech_uk": source_speech_uk,
|
|
172
|
+
"source_speech_us": source_speech_us,
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
phonetic_us: str | None = (
|
|
176
|
+
basic_direction.get("us-phonetic") if basic_direction else None
|
|
177
|
+
)
|
|
178
|
+
phonetic: str | None = (
|
|
179
|
+
basic_direction.get("phonetic") if basic_direction else None
|
|
180
|
+
)
|
|
181
|
+
phonetic_uk: str | None = (
|
|
182
|
+
basic_direction.get("uk-phonetic") if basic_direction else None
|
|
183
|
+
)
|
|
184
|
+
phonetic = {"us": phonetic_us, "uk": phonetic_uk, "default": phonetic}
|
|
185
|
+
|
|
186
|
+
word_type: list[str] | None = (
|
|
187
|
+
basic_direction.get("exam_type") if basic_direction else None
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
grammar_info: list[dict] | None = (
|
|
191
|
+
basic_direction.get("wfs") if basic_direction else None
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
extended_info: list[dict[str, list[str]]] | None = response.get("web")
|
|
195
|
+
|
|
196
|
+
format_response: WordInfo = {
|
|
197
|
+
"word": word,
|
|
198
|
+
"translation": translation,
|
|
199
|
+
"speak_url": speakUrl,
|
|
200
|
+
"phonetic": phonetic,
|
|
201
|
+
"word_type": word_type,
|
|
202
|
+
"grammar_info": grammar_info,
|
|
203
|
+
"extended_info": extended_info,
|
|
204
|
+
}
|
|
205
|
+
# import json
|
|
206
|
+
# print(json.dumps(res,indent=2,ensure_ascii=False))
|
|
207
|
+
return format_response
|
|
208
|
+
|
|
209
|
+
@classmethod
|
|
210
|
+
def format_sentence_response(cls, response: dict) -> SentenceInfo:
|
|
211
|
+
sentence: str = response["query"]
|
|
212
|
+
translation: list[str] = response["translation"]
|
|
213
|
+
|
|
214
|
+
source_speak_url: str = response["speakUrl"]
|
|
215
|
+
translation_speak_url: str = response["tSpeakUrl"]
|
|
216
|
+
|
|
217
|
+
response = {
|
|
218
|
+
"sentence": sentence,
|
|
219
|
+
"translation": translation,
|
|
220
|
+
"source_speak_url": source_speak_url,
|
|
221
|
+
"translation_speak_url": translation_speak_url,
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return response
|
|
225
|
+
|
|
226
|
+
@classmethod
|
|
227
|
+
def download_audio_file(self, url: str) -> bytes:
|
|
228
|
+
try:
|
|
229
|
+
response = requests.get(url=url)
|
|
230
|
+
except Exception as e:
|
|
231
|
+
raise ValueError(f"youdao translate download audio file error: {e}")
|
|
232
|
+
if response.status_code != 200:
|
|
233
|
+
raise ValueError("download audio file,status code error")
|
|
234
|
+
return response.content
|