-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
278 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.idea/ | ||
build/ | ||
dist/ | ||
venv/ | ||
modernmt.egg-info/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# ModernMT Python Library | ||
Provides convenient access to the ModernMT API. | ||
|
||
## Documentation | ||
See the official website [API docs](https://www.modernmt.com/api?lang=python). | ||
|
||
## Requirements | ||
Python 3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[build-system] | ||
requires = [ | ||
"setuptools>=42", | ||
"wheel" | ||
] | ||
build-backend = "setuptools.build_meta" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
requests | ||
build | ||
twine |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
[metadata] | ||
name = modernmt | ||
version = 1.0.0 | ||
author = ModernMT | ||
author_email = [email protected] | ||
description = ModernMT API wrapper | ||
long_description = file: README.md | ||
long_description_content_type = text/markdown | ||
url = https://github.com/modernmt/modernmt-python | ||
project_urls = | ||
Bug Tracker = https://github.com/modernmt/modernmt-python/issues | ||
classifiers = | ||
Programming Language :: Python :: 3 | ||
License :: OSI Approved :: MIT License | ||
Operating System :: OS Independent | ||
|
||
[options] | ||
package_dir = | ||
= src | ||
packages = find: | ||
python_requires = >=3 | ||
install_requires = | ||
requests | ||
|
||
[options.packages.find] | ||
where = src |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from .modernmt import ModernMTException | ||
from .modernmt import ModernMT | ||
from .modernmt import Translation | ||
from .modernmt import Memory | ||
from .modernmt import ImportJob |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
import requests | ||
|
||
|
||
class ModernMTException(Exception): | ||
def __init__(self, status, type, message) -> None: | ||
super().__init__("(%s) %s" % (type, message)) | ||
self.status = status | ||
self.type = type | ||
self.message = message | ||
|
||
|
||
class ModernMT(object): | ||
def __init__(self, license_key, platform="modernmt-python", platform_version="1.0.0") -> None: | ||
self.__base_url = "https://api.modernmt.com" | ||
self.__headers = { | ||
"MMT-ApiKey": license_key, | ||
"MMT-Platform": platform, | ||
"MMT-PlatformVersion": platform_version | ||
} | ||
|
||
self.memories = _MemoryServices(self.__headers, self.__send) | ||
|
||
def list_supported_languages(self): | ||
return self.__send("get", "/translate/languages") | ||
|
||
def translate(self, source, target, q, hints=None, context_vector=None, options=None): | ||
multiple_targets = isinstance(q, list) | ||
|
||
data = {"target": target, "q": q} | ||
if source is not None: | ||
data["source"] = source | ||
if context_vector is not None: | ||
data["context_vector"] = context_vector | ||
if hints is not None: | ||
data["hints"] = hints | ||
|
||
if options is not None: | ||
if "priority" in options: | ||
data["priority"] = options["priority"] | ||
if "project_id" in options: | ||
data["project_id"] = options["project_id"] | ||
if "multiline" in options: | ||
data["multiline"] = options["multiline"] | ||
if "timeout" in options: | ||
data["timeout"] = options["timeout"] | ||
|
||
res = self.__send("get", "/translate", data=data) | ||
|
||
if not multiple_targets: | ||
return Translation(res) | ||
|
||
translations = [] | ||
for el in res: | ||
translations.append(Translation(el)) | ||
|
||
return translations | ||
|
||
def get_context_vector(self, source, targets, text, hints=None, limit=None): | ||
multiple_targets = isinstance(targets, list) | ||
data = {"source": source, "text": text} | ||
|
||
if multiple_targets: | ||
data["targets"] = targets | ||
else: | ||
data["targets"] = [targets] | ||
|
||
if hints is not None: | ||
data["hints"] = hints | ||
if limit is not None: | ||
data["limit"] = limit | ||
|
||
res = self.__send("get", "/context-vector", data=data) | ||
|
||
if multiple_targets: | ||
return res["vectors"] | ||
else: | ||
if targets in res["vectors"]: | ||
return res["vectors"][targets] | ||
else: | ||
return None | ||
|
||
def get_context_vector_from_file(self, source, targets, file, hints=None, limit=None, compression=None): | ||
multiple_targets = isinstance(targets, list) | ||
|
||
if isinstance(file, str): | ||
file = open(file, "rb") | ||
|
||
data = {"source": source} | ||
if multiple_targets: | ||
data["targets"] = targets | ||
else: | ||
data["targets"] = [targets] | ||
|
||
if hints is not None: | ||
data["hints"] = hints | ||
if limit is not None: | ||
data["limit"] = limit | ||
if compression is not None: | ||
data["compression"] = compression | ||
|
||
res = self.__send("get", "/context-vector", data=data, files={"content": file}) | ||
|
||
if multiple_targets: | ||
return res["vectors"] | ||
else: | ||
if targets in res["vectors"]: | ||
return res["vectors"][targets] | ||
else: | ||
return None | ||
|
||
def __send(self, method, endpoint, data=None, files=None, cls=None): | ||
url = self.__base_url + endpoint | ||
|
||
headers = self.__headers | ||
headers["X-HTTP-Method-Override"] = method | ||
|
||
if files is None: | ||
r = requests.post(url, headers=headers, json=data) | ||
else: | ||
r = requests.post(url, headers=headers, data=data, files=files) | ||
|
||
json = r.json() | ||
if r.status_code != requests.codes.ok: | ||
ex_type = "UnknownException" | ||
ex_msg = r.text | ||
try: | ||
error = json["error"] | ||
ex_type, ex_msg = error["type"], error["message"] | ||
except KeyError: | ||
pass | ||
except ValueError: | ||
pass | ||
|
||
raise ModernMTException(r.status_code, ex_type, ex_msg) | ||
|
||
return json["data"] if cls is None else cls(json["data"]) | ||
|
||
|
||
class _MemoryServices(object): | ||
def __init__(self, headers, send) -> None: | ||
self.__headers = headers | ||
self.__send = send | ||
|
||
def list(self): | ||
res = self.__send("get", "/memories") | ||
|
||
memories = [] | ||
for el in res: | ||
memories.append(Memory(el)) | ||
|
||
return memories | ||
|
||
def get(self, id): | ||
return self.__send("get", "/memories/%s" % id, cls=Memory) | ||
|
||
def create(self, name, description=None, external_id=None): | ||
data = {"name": name} | ||
if description is not None: | ||
data["description"] = description | ||
if external_id is not None: | ||
data["external_id"] = external_id | ||
|
||
return self.__send("post", "/memories", data=data, cls=Memory) | ||
|
||
def edit(self, id, name=None, description=None): | ||
data = {} | ||
if name is not None: | ||
data["name"] = name | ||
if description is not None: | ||
data["description"] = description | ||
|
||
return self.__send("put", "/memories/%s" % id, data=data, cls=Memory) | ||
|
||
def delete(self, id): | ||
return self.__send("delete", "/memories/%s" % id, cls=Memory) | ||
|
||
def add(self, id, source, target, sentence, translation, tuid=None): | ||
data = {"source": source, "target": target, "sentence": sentence, "translation": translation} | ||
if tuid is not None: | ||
data["tuid"] = tuid | ||
|
||
return self.__send("post", "/memories/%s/content" % id, data=data, cls=ImportJob) | ||
|
||
def replace(self, id, tuid, source, target, sentence, translation): | ||
data = {"tuid": tuid, "source": source, "target": target, "sentence": sentence, "translation": translation} | ||
return self.__send("put", "/memories/%s/content" % id, data=data, cls=ImportJob) | ||
|
||
def import_tmx(self, id, tmx, compression=None): | ||
if isinstance(tmx, str): | ||
tmx = open(tmx, "rb") | ||
|
||
data = {} | ||
if compression is not None: | ||
data["compression"] = compression | ||
|
||
return self.__send("post", "/memories/%s/content" % id, data=data, files={"tmx": tmx}, cls=ImportJob) | ||
|
||
def get_import_status(self, uuid): | ||
return self.__send("get", "/import-jobs/%s" % uuid, cls=ImportJob) | ||
|
||
|
||
class _Model(object): | ||
def __init__(self, data, fields) -> None: | ||
self.__dict__ = {k: v for k, v in data.items() if k in fields} | ||
|
||
def __repr__(self): | ||
return str(self) | ||
|
||
def __str__(self): | ||
return str(vars(self)) | ||
|
||
|
||
class Translation(_Model): | ||
def __init__(self, data) -> None: | ||
super().__init__(data, ["translation", "contextVector", "characters", "billedCharacters", "detectedLanguage"]) | ||
|
||
|
||
class Memory(_Model): | ||
def __init__(self, data) -> None: | ||
super().__init__(data, ["id", "name", "description", "creationDate"]) | ||
|
||
|
||
class ImportJob(_Model): | ||
def __init__(self, data) -> None: | ||
super().__init__(data, ["id", "memory", "size", "progress"]) |