harry commited on
Commit
d01fa51
·
1 Parent(s): 5d13bbd

add tencent translator

Browse files
deep_translator/__init__.py CHANGED
@@ -13,6 +13,7 @@ from deep_translator.mymemory import MyMemoryTranslator
13
  from deep_translator.papago import PapagoTranslator
14
  from deep_translator.pons import PonsTranslator
15
  from deep_translator.qcri import QcriTranslator
 
16
  from deep_translator.yandex import YandexTranslator
17
 
18
  __author__ = """Nidhal Baccouri"""
@@ -31,6 +32,7 @@ __all__ = [
31
  "LibreTranslator",
32
  "PapagoTranslator",
33
  "ChatGptTranslator",
 
34
  "single_detection",
35
  "batch_detection",
36
  ]
 
13
  from deep_translator.papago import PapagoTranslator
14
  from deep_translator.pons import PonsTranslator
15
  from deep_translator.qcri import QcriTranslator
16
+ from deep_translator.tencent import TencentTranslator
17
  from deep_translator.yandex import YandexTranslator
18
 
19
  __author__ = """Nidhal Baccouri"""
 
32
  "LibreTranslator",
33
  "PapagoTranslator",
34
  "ChatGptTranslator",
35
+ "TencentTranslator",
36
  "single_detection",
37
  "batch_detection",
38
  ]
deep_translator/constants.py CHANGED
@@ -7,6 +7,8 @@ LIBRE_ENV_VAR = "LIBRE_API_KEY"
7
  MSFT_ENV_VAR = "MICROSOFT_API_KEY"
8
  QCRI_ENV_VAR = "QCRI_API_KEY"
9
  YANDEX_ENV_VAR = "YANDEX_API_KEY"
 
 
10
 
11
 
12
  BASE_URLS = {
@@ -23,6 +25,7 @@ BASE_URLS = {
23
  "PAPAGO_API": "https://openapi.naver.com/v1/papago/n2mt",
24
  "LIBRE": "https://libretranslate.com/",
25
  "LIBRE_FREE": "https://libretranslate.de/",
 
26
  }
27
 
28
  GOOGLE_LANGUAGES_TO_CODES = {
@@ -280,3 +283,23 @@ LIBRE_LANGUAGES_TO_CODES = {
280
  "Turkish": "tr",
281
  "Vietnamese": "vi",
282
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  MSFT_ENV_VAR = "MICROSOFT_API_KEY"
8
  QCRI_ENV_VAR = "QCRI_API_KEY"
9
  YANDEX_ENV_VAR = "YANDEX_API_KEY"
10
+ TENCENT_ID_VAR = "TENCENT_ID"
11
+ TENCENT_KEY_VAR = "TENCENT_KEY"
12
 
13
 
14
  BASE_URLS = {
 
25
  "PAPAGO_API": "https://openapi.naver.com/v1/papago/n2mt",
26
  "LIBRE": "https://libretranslate.com/",
27
  "LIBRE_FREE": "https://libretranslate.de/",
28
+ "TENENT": "https://tmt.tencentcloudapi.com",
29
  }
30
 
31
  GOOGLE_LANGUAGES_TO_CODES = {
 
283
  "Turkish": "tr",
284
  "Vietnamese": "vi",
285
  }
286
+
287
+ TENCENT_LANGUAGE_TO_CODE = {
288
+ "arabic": "ar",
289
+ "chinese (simplified)": "zh",
290
+ "chinese (traditional)": "zh-TW",
291
+ "english": "en",
292
+ "french": "fr",
293
+ "german": "de",
294
+ "hindi": "hi",
295
+ "indonesian": "id",
296
+ "japanese": "ja",
297
+ "korean": "ko",
298
+ "malay": "ms",
299
+ "portuguese": "pt",
300
+ "russian": "ru",
301
+ "spanish": "es",
302
+ "thai": "th",
303
+ "turkish": "tr",
304
+ "vietnamese": "vi",
305
+ }
deep_translator/exceptions.py CHANGED
@@ -180,3 +180,16 @@ class AuthorizationException(Exception):
180
  def __init__(self, api_key, *args):
181
  msg = "Unauthorized access with the api key " + api_key
182
  super().__init__(msg, *args)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  def __init__(self, api_key, *args):
181
  msg = "Unauthorized access with the api key " + api_key
182
  super().__init__(msg, *args)
183
+
184
+
185
+ class TencentAPIerror(Exception):
186
+ """
187
+ exception thrown if Tencent API returns one of its errors
188
+ """
189
+
190
+ def __init__(self, api_message):
191
+ self.api_message = str(api_message)
192
+ self.message = "Tencent API returned the following error"
193
+
194
+ def __str__(self):
195
+ return "{}: {}".format(self.message, self.api_message)
deep_translator/tencent.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ tencent translator API
3
+ """
4
+
5
+ __copyright__ = "Copyright (C) 2020 Nidhal Baccouri"
6
+
7
+ import base64
8
+ import hashlib
9
+ import hmac
10
+ import os
11
+ import time
12
+ from typing import List, Optional
13
+
14
+ import requests
15
+
16
+ from deep_translator.base import BaseTranslator
17
+ from deep_translator.constants import (
18
+ BASE_URLS,
19
+ TENCENT_ID_VAR,
20
+ TENCENT_KEY_VAR,
21
+ TENCENT_LANGUAGE_TO_CODE,
22
+ )
23
+ from deep_translator.exceptions import (
24
+ ApiKeyException,
25
+ AuthorizationException,
26
+ ServerException,
27
+ TencentAPIerror,
28
+ TranslationNotFound,
29
+ )
30
+ from deep_translator.validate import is_empty, is_input_valid
31
+
32
+
33
+ class TencentTranslator(BaseTranslator):
34
+ """
35
+ class that wraps functions, which use the TentCentTranslator translator
36
+ under the hood to translate word(s)
37
+ """
38
+
39
+ def __init__(
40
+ self,
41
+ source: str = "en",
42
+ target: str = "zh",
43
+ secret_id: Optional[str] = os.getenv(TENCENT_ID_VAR, None),
44
+ secret_key: Optional[str] = os.getenv(TENCENT_KEY_VAR, None),
45
+ **kwargs
46
+ ):
47
+ """
48
+ @param secret_id: your tencent cloud api secret id.
49
+ Get one here: https://console.cloud.tencent.com/capi
50
+ @param secret_key: your tencent cloud api secret key.
51
+ @param source: source language
52
+ @param target: target language
53
+ """
54
+ if not secret_id:
55
+ raise ApiKeyException(env_var=TENCENT_ID_VAR)
56
+
57
+ if not secret_key:
58
+ raise ApiKeyException(env_var=TENCENT_KEY_VAR)
59
+
60
+ self.secret_id = secret_id
61
+ self.secret_key = secret_key
62
+ url = BASE_URLS.get("TENENT")
63
+ super().__init__(
64
+ base_url=url,
65
+ source=source,
66
+ target=target,
67
+ languages=TENCENT_LANGUAGE_TO_CODE,
68
+ **kwargs
69
+ )
70
+
71
+ def translate(self, text: str, **kwargs) -> str:
72
+ """
73
+ @param text: text to translate
74
+ @return: translated text
75
+ """
76
+ if is_input_valid(text):
77
+ if self._same_source_target() or is_empty(text):
78
+ return text
79
+
80
+ # Create the request parameters.
81
+ translate_endpoint = "tmt.tencentcloudapi.com"
82
+ params = {
83
+ "Action": "TextTranslate",
84
+ "Nonce": 11886,
85
+ "ProjectId": 0,
86
+ "Region": "ap-guangzhou",
87
+ "SecretId": self.secret_id,
88
+ "Source": self.source,
89
+ "SourceText": text,
90
+ "Target": self.target,
91
+ "Timestamp": int(time.time()), # int(time.time())
92
+ "Version": "2018-03-21",
93
+ }
94
+ s = "GET" + translate_endpoint + "/?"
95
+ query_str = "&".join(
96
+ "%s=%s" % (k, params[k]) for k in sorted(params)
97
+ )
98
+ hmac_str = hmac.new(
99
+ self.secret_key.encode("utf8"),
100
+ (s + query_str).encode("utf8"),
101
+ hashlib.sha1,
102
+ ).digest()
103
+ params["Signature"] = base64.b64encode(hmac_str)
104
+
105
+ # Do the request and check the connection.
106
+ try:
107
+ response = requests.get(self._base_url, params=params)
108
+ except ConnectionError:
109
+ raise ServerException(503)
110
+ # If the answer is not success, raise server exception.
111
+ if response.status_code == 403:
112
+ raise AuthorizationException(self.secret_id)
113
+ elif response.status_code != 200:
114
+ raise ServerException(response.status_code)
115
+ # Get the response and check is not empty.
116
+ res = response.json()
117
+ if not res:
118
+ raise TranslationNotFound(text)
119
+ # Process and return the response.
120
+ if "Error" in res["Response"]:
121
+ raise TencentAPIerror(res["Response"]["Error"]["Code"])
122
+ return res["Response"]["TargetText"]
123
+
124
+ def translate_file(self, path: str, **kwargs) -> str:
125
+ return self._translate_file(path, **kwargs)
126
+
127
+ def translate_batch(self, batch: List[str], **kwargs) -> List[str]:
128
+ """
129
+ @param batch: list of texts to translate
130
+ @return: list of translations
131
+ """
132
+ return self._translate_batch(batch, **kwargs)
133
+
134
+
135
+ if __name__ == "__main__":
136
+ d = TencentTranslator(
137
+ target="zh", secret_id="some-id", secret_key="some-key"
138
+ )
139
+ t = d.translate("Ich habe keine ahnung")
140
+ print("text: ", t)
tests/test_tencent.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from unittest.mock import Mock, patch
2
+
3
+ import pytest
4
+
5
+ from deep_translator import TencentTranslator
6
+ from deep_translator.exceptions import AuthorizationException
7
+
8
+
9
+ @patch("deep_translator.tencent.requests")
10
+ def test_simple_translation(mock_requests):
11
+ translator = TencentTranslator(
12
+ secret_id="this-is-an-valid-api-id",
13
+ source="en",
14
+ target="zh",
15
+ secret_key="this-is-an-valid-api-key",
16
+ )
17
+ # Set the request response mock.
18
+ mock_response = Mock()
19
+ mock_response.status_code = 200
20
+ mock_response.json.return_value = {"translations": [{"text": "hola"}]}
21
+ mock_requests.get.return_value = mock_response
22
+ translation = translator.translate("hello")
23
+ assert translation == "你好"
24
+
25
+
26
+ @patch("deep_translator.tencent.requests.get")
27
+ def test_wrong_api_key(mock_requests):
28
+ translator = TencentTranslator(
29
+ secret_id="this-is-a-wrong-api-id",
30
+ source="en",
31
+ target="zh",
32
+ secret_key="this-is-a-wrong-api-key",
33
+ )
34
+ # Set the response status_code only.
35
+ mock_requests.return_value = Mock(status_code=403)
36
+ with pytest.raises(AuthorizationException):
37
+ translator.translate("Hello")