mirror of https://github.com/jumpserver/jumpserver
feat: gpt translate
parent
fdaec3c959
commit
f0dfff0625
|
@ -0,0 +1,3 @@
|
|||
import os
|
||||
|
||||
LOCALE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
@ -0,0 +1,57 @@
|
|||
import asyncio
|
||||
import os
|
||||
|
||||
from apps.locale.translate import LOCALE_DIR
|
||||
from apps.locale.translate.manager import OtherTranslateManager, CoreTranslateManager
|
||||
from apps.locale.translate.utils import OpenAITranslate
|
||||
|
||||
|
||||
class Translate:
|
||||
IGNORE_TRANSLATE_DIRS = ('translate',)
|
||||
|
||||
def __init__(self, oai_trans_instance):
|
||||
self.oai_trans = oai_trans_instance
|
||||
|
||||
def get_dir_names(self):
|
||||
dir_names = []
|
||||
for name in os.listdir(LOCALE_DIR):
|
||||
_path = os.path.join(LOCALE_DIR, name)
|
||||
if not os.path.isdir(_path) or name in self.IGNORE_TRANSLATE_DIRS:
|
||||
continue
|
||||
dir_names.append(name)
|
||||
return dir_names
|
||||
|
||||
async def core_trans(self, dir_name):
|
||||
_dir = os.path.join(LOCALE_DIR, dir_name)
|
||||
zh_file = os.path.join(_dir, 'zh', 'LC_MESSAGES', 'django.po')
|
||||
if not os.path.exists(zh_file):
|
||||
print(f'File: {zh_file} not exists.')
|
||||
return
|
||||
|
||||
await CoreTranslateManager(_dir, self.oai_trans).run()
|
||||
|
||||
async def other_trans(self, dir_name):
|
||||
_dir = os.path.join(LOCALE_DIR, dir_name)
|
||||
zh_file = os.path.join(_dir, 'zh.json')
|
||||
if not os.path.exists(zh_file):
|
||||
print(f'File: {zh_file} not exists.')
|
||||
return
|
||||
|
||||
await OtherTranslateManager(_dir, self.oai_trans).run()
|
||||
|
||||
async def run(self):
|
||||
dir_names = self.get_dir_names()
|
||||
if not dir_names:
|
||||
return
|
||||
|
||||
for dir_name in dir_names:
|
||||
if hasattr(self, f'{dir_name}_trans'):
|
||||
await getattr(self, f'{dir_name}_trans')(dir_name)
|
||||
else:
|
||||
await self.other_trans(dir_name)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
oai_trans = OpenAITranslate()
|
||||
manager = Translate(oai_trans)
|
||||
asyncio.run(manager.run())
|
|
@ -0,0 +1,2 @@
|
|||
from .core import *
|
||||
from .other import *
|
|
@ -0,0 +1,52 @@
|
|||
import asyncio
|
||||
import os
|
||||
|
||||
|
||||
class BaseTranslateManager:
|
||||
bulk_size = 30
|
||||
SEPARATOR = "<SEP>"
|
||||
LANG_MAPPER = {
|
||||
'ja': 'Japanese',
|
||||
}
|
||||
|
||||
def __init__(self, dir_path, oai_trans_instance):
|
||||
self.oai_trans = oai_trans_instance
|
||||
self._dir = dir_path
|
||||
if not os.path.exists(self._dir):
|
||||
os.makedirs(self._dir)
|
||||
|
||||
@staticmethod
|
||||
def split_dict_into_chunks(input_dict, chunk_size=20):
|
||||
temp = {}
|
||||
result = []
|
||||
|
||||
for i, (k, v) in enumerate(input_dict.items()):
|
||||
temp[k] = v
|
||||
if (i + 1) % chunk_size == 0 or i == len(input_dict) - 1:
|
||||
result.append(temp)
|
||||
temp = {}
|
||||
|
||||
return result
|
||||
|
||||
async def create_translate_task(self, data, target_lang):
|
||||
try:
|
||||
keys = list(data.keys())
|
||||
values = list(data.values())
|
||||
combined_text = self.SEPARATOR.join(values)
|
||||
translated_text = await self.oai_trans.translate_text(combined_text, target_lang)
|
||||
translated_texts = translated_text.split(self.SEPARATOR)
|
||||
return dict(zip(keys, translated_texts))
|
||||
except Exception as e:
|
||||
print(f"Error during translation task: {e}")
|
||||
return {}
|
||||
|
||||
async def bulk_translate(self, need_trans_dict, target_lang):
|
||||
split_data = self.split_dict_into_chunks(need_trans_dict, self.bulk_size)
|
||||
|
||||
tasks = [self.create_translate_task(batch, target_lang) for batch in split_data]
|
||||
translated_results = await asyncio.gather(*tasks)
|
||||
translated_dict = {}
|
||||
for result in translated_results:
|
||||
translated_dict.update(result)
|
||||
|
||||
return translated_dict
|
|
@ -0,0 +1,47 @@
|
|||
import os
|
||||
|
||||
import polib
|
||||
|
||||
from .base import BaseTranslateManager
|
||||
|
||||
|
||||
class CoreTranslateManager(BaseTranslateManager):
|
||||
|
||||
@staticmethod
|
||||
def get_need_trans_dict(zh_dict, trans_po):
|
||||
need_trans_dict = {
|
||||
entry.msgid: zh_dict[entry.msgid]
|
||||
for entry in trans_po.untranslated_entries() + trans_po.fuzzy_entries()
|
||||
if entry.msgid in zh_dict
|
||||
}
|
||||
return need_trans_dict
|
||||
|
||||
@staticmethod
|
||||
def save_translations_to_po(data, trans_po):
|
||||
try:
|
||||
for entry in trans_po.untranslated_entries() + trans_po.fuzzy_entries():
|
||||
if entry.msgid not in data:
|
||||
print(f'msgid: {entry.msgid} not in data.')
|
||||
continue
|
||||
entry.flags = []
|
||||
entry.previous_msgid = None
|
||||
entry.msgstr = data[entry.msgid]
|
||||
trans_po.save()
|
||||
except Exception as e:
|
||||
print(f'File save error: {e}')
|
||||
|
||||
async def run(self):
|
||||
po_file_path = os.path.join(self._dir, 'zh', 'LC_MESSAGES', 'django.po')
|
||||
po = polib.pofile(po_file_path)
|
||||
zh_dict = {entry.msgid: entry.msgstr for entry in po.translated_entries()}
|
||||
|
||||
for file_prefix, target_lang in self.LANG_MAPPER.items():
|
||||
po_file_path = os.path.join(self._dir, file_prefix, 'LC_MESSAGES', 'django.po')
|
||||
trans_po = polib.pofile(po_file_path)
|
||||
need_trans_dict = self.get_need_trans_dict(zh_dict, trans_po)
|
||||
print(f'File: {file_prefix}.json need to translate: {len(need_trans_dict)}')
|
||||
if not need_trans_dict:
|
||||
print(f'File: {file_prefix}.json is already translated.')
|
||||
continue
|
||||
translated_dict = await self.bulk_translate(need_trans_dict, target_lang)
|
||||
self.save_translations_to_po(translated_dict, trans_po)
|
|
@ -0,0 +1,46 @@
|
|||
import json
|
||||
import os
|
||||
|
||||
from .base import BaseTranslateManager
|
||||
|
||||
|
||||
class OtherTranslateManager(BaseTranslateManager):
|
||||
|
||||
@staticmethod
|
||||
def get_need_trans_dict(zh_dict, other_dict):
|
||||
diff_keys = set(zh_dict.keys()) - set(other_dict.keys())
|
||||
need_trans_dict = {k: zh_dict[k] for k in diff_keys if k}
|
||||
return need_trans_dict
|
||||
|
||||
def load_json_as_dict(self, file_prefix='zh'):
|
||||
file_path = os.path.join(self._dir, f'{file_prefix}.json')
|
||||
if not os.path.exists(file_path):
|
||||
return {}
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
print(f'File: {file_path} load error: {e}')
|
||||
return {}
|
||||
|
||||
def save_dict_as_json(self, data, file_prefix='ja'):
|
||||
file_path = os.path.join(self._dir, f'{file_prefix}.json')
|
||||
try:
|
||||
with open(file_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, ensure_ascii=False, sort_keys=True, indent=4)
|
||||
except Exception as e:
|
||||
print(f'File: {file_path} save error: {e}')
|
||||
|
||||
async def run(self):
|
||||
zh_dict = self.load_json_as_dict()
|
||||
|
||||
for file_prefix, target_lang in self.LANG_MAPPER.items():
|
||||
other_dict = self.load_json_as_dict(file_prefix)
|
||||
need_trans_dict = self.get_need_trans_dict(zh_dict, other_dict)
|
||||
print(f'File: {file_prefix}.json need to translate: {len(need_trans_dict)}')
|
||||
if not need_trans_dict:
|
||||
print(f'File: {file_prefix}.json is already translated.')
|
||||
continue
|
||||
translated_dict = await self.bulk_translate(need_trans_dict, target_lang)
|
||||
other_dict.update(translated_dict)
|
||||
self.save_dict_as_json(other_dict, file_prefix)
|
|
@ -0,0 +1,31 @@
|
|||
from openai import AsyncOpenAI
|
||||
|
||||
|
||||
class OpenAITranslate:
|
||||
def __init__(self, key: str | None = None):
|
||||
self.client = AsyncOpenAI(api_key=key)
|
||||
|
||||
async def translate_text(self, text, target_lang="English") -> str | None:
|
||||
try:
|
||||
response = await self.client.chat.completions.create(
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": f"Now I ask you to be the translator. "
|
||||
f"Your goal is to understand the Chinese "
|
||||
f"I provided you and translate it into {target_lang}. "
|
||||
f"Please do not use a translation accent when translating, "
|
||||
f"but translate naturally, smoothly and authentically, "
|
||||
f"using beautiful and elegant words. way of expression.",
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": text,
|
||||
},
|
||||
],
|
||||
model="gpt-4",
|
||||
)
|
||||
except Exception as e:
|
||||
print("Open AI Error: ", e)
|
||||
return
|
||||
return response.choices[0].message.content.strip()
|
|
@ -1,4 +1,4 @@
|
|||
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "adal"
|
||||
|
@ -2424,17 +2424,6 @@ files = [
|
|||
{file = "ephem-4.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8f9b27117e7a82f7f70db9cb23b5cc36d37b166a2f73c55e14d7225d0ab95afa"},
|
||||
{file = "ephem-4.1.4-cp311-cp311-win32.whl", hash = "sha256:9bb21c0b117c9122c0141b0a71ee6fbbb087ed2aab4a7ab60f009e95e9f4a521"},
|
||||
{file = "ephem-4.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:55d7fb5c34b2e453e01fa4ca7ee375b19b438c9401ae8c4099ae4a3a37656972"},
|
||||
{file = "ephem-4.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f9e24aeea560dfcece3c2e313eb94e6be3e84888091455e541fa88f3a44da584"},
|
||||
{file = "ephem-4.1.4-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:653d99386932e5f78bb9cfc4495030ad9f3345eb4c2b32dca55547da8f1f0332"},
|
||||
{file = "ephem-4.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53786461a6d5799d5fffe76622ad51444b264d1c7263b92a6dfcac640c3da93a"},
|
||||
{file = "ephem-4.1.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:268f57f8768ccb0abbdf4cefb4781c7db812950019868f687b407b428513ee53"},
|
||||
{file = "ephem-4.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d630aa287255ea9fba6962f351e4e0729bb620570684d52fbfcc31b11527f09e"},
|
||||
{file = "ephem-4.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b5f229bbf62ecb4cd6bb3374b15d0f8ff7b3d970c2936fccd89bdf9d693907a2"},
|
||||
{file = "ephem-4.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d60d56f182de54bd84fadd6ea2dd8e8ef6fdef6a698c7cafd404ecb6eeefa598"},
|
||||
{file = "ephem-4.1.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:404500c8d0030d75ec15bb6b98eee78ad163fd5252102c962ae6fb39c9488198"},
|
||||
{file = "ephem-4.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fb020d6cc5ab1ad1cd9d3da4a6e2506beebb41d1b337d79cc20cc0a17f550f1"},
|
||||
{file = "ephem-4.1.4-cp312-cp312-win32.whl", hash = "sha256:29e71636ee4719419d03184abc85085f76989c79a61844f5e60acbf2513d2b42"},
|
||||
{file = "ephem-4.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:549654f63d88e0ab6248ae25ac2939131474ab9f3a91bee6b68ca6f214747c2a"},
|
||||
{file = "ephem-4.1.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:40067fc050c946c8d4c2d779805b61f063471a091e6124cbabcf61ac538011b2"},
|
||||
{file = "ephem-4.1.4-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e2abe97aa2b091090012768b4d94793213cc01f0bf040dcc311a380ab08df69"},
|
||||
{file = "ephem-4.1.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2677d3a5b42aedc578de10b0eecdba6a50731f159cb28f7ad38c5f62143494"},
|
||||
|
@ -2777,8 +2766,14 @@ files = [
|
|||
[package.dependencies]
|
||||
google-auth = ">=2.14.1,<3.0.dev0"
|
||||
googleapis-common-protos = ">=1.56.2,<2.0.dev0"
|
||||
grpcio = {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}
|
||||
grpcio-status = {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""}
|
||||
grpcio = [
|
||||
{version = ">=1.33.2,<2.0dev", optional = true, markers = "extra == \"grpc\""},
|
||||
{version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""},
|
||||
]
|
||||
grpcio-status = [
|
||||
{version = ">=1.33.2,<2.0.dev0", optional = true, markers = "extra == \"grpc\""},
|
||||
{version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""},
|
||||
]
|
||||
protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0"
|
||||
requests = ">=2.18.0,<3.0.0.dev0"
|
||||
|
||||
|
@ -3781,7 +3776,41 @@ files = [
|
|||
{file = "lxml-5.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7188495c1bf71bfda87d78ed50601e72d252119ce11710d6e71ff36e35fea5a0"},
|
||||
{file = "lxml-5.0.0-cp37-cp37m-win32.whl", hash = "sha256:6a2de85deabf939b0af89e2e1ea46bfb1239545e2da6f8ac96522755a388025f"},
|
||||
{file = "lxml-5.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ea56825c1e23c9c8ea385a191dac75f9160477057285b88c88736d9305e6118f"},
|
||||
{file = "lxml-5.0.0.tar.gz", hash = "sha256:9165c82bcccf0249feff82cd1fba202e4ce26c25dc69040a0d2c2d0e49cbeba3"},
|
||||
{file = "lxml-5.0.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:3f908afd0477cace17f941d1b9cfa10b769fe1464770abe4cfb3d9f35378d0f8"},
|
||||
{file = "lxml-5.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52a9ab31853d3808e7cf0183b3a5f7e8ffd622ea4aee1deb5252dbeaefd5b40d"},
|
||||
{file = "lxml-5.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c7fe19abb3d3c55a9e65d289b12ad73b3a31a3f0bda3c539a890329ae9973bd6"},
|
||||
{file = "lxml-5.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:1ef0793e1e2dd221fce7c142177008725680f7b9e4a184ab108d90d5d3ab69b7"},
|
||||
{file = "lxml-5.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:581a78f299a9f5448b2c3aea904bfcd17c59bf83016d221d7f93f83633bb2ab2"},
|
||||
{file = "lxml-5.0.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:affdd833f82334fdb10fc9a1c7b35cdb5a86d0b672b4e14dd542e1fe7bcea894"},
|
||||
{file = "lxml-5.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6bba06d8982be0f0f6432d289a8d104417a0ab9ed04114446c4ceb6d4a40c65d"},
|
||||
{file = "lxml-5.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:80209b31dd3908bc5b014f540fd192c97ea52ab179713a730456c5baf7ce80c1"},
|
||||
{file = "lxml-5.0.0-cp38-cp38-win32.whl", hash = "sha256:dac2733fe4e159b0aae0439db6813b7b1d23ff96d0b34c0107b87faf79208c4e"},
|
||||
{file = "lxml-5.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:ee60f33456ff34b2dd1d048a740a2572798356208e4c494301c931de3a0ab3a2"},
|
||||
{file = "lxml-5.0.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:5eff173f0ff408bfa578cbdafd35a7e0ca94d1a9ffe09a8a48e0572d0904d486"},
|
||||
{file = "lxml-5.0.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:78d6d8e5b54ed89dc0f0901eaaa579c384ad8d59fa43cc7fb06e9bb89115f8f4"},
|
||||
{file = "lxml-5.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:71a7cee869578bc17b18050532bb2f0bc682a7b97dda77041741a1bd2febe6c7"},
|
||||
{file = "lxml-5.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7df433d08d4587dc3932f7fcfc3194519a6824824104854e76441fd3bc000d29"},
|
||||
{file = "lxml-5.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:793be9b4945c2dfd69828fb5948d7d9569b78e0599e4a2e88d92affeb0ff3aa3"},
|
||||
{file = "lxml-5.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c7cfb6af73602c8d288581df8a225989d7e9d5aab0a174be0e19fcfa800b6797"},
|
||||
{file = "lxml-5.0.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bfdc4668ac56687a89ca3eca44231144a2e9d02ba3b877558db74ba20e2bd9fa"},
|
||||
{file = "lxml-5.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2992591e2294bb07faf7f5f6d5cb60710c046404f4bfce09fb488b85d2a8f58f"},
|
||||
{file = "lxml-5.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4786b0af7511ea614fd86407a52a7bc161aa5772d311d97df2591ed2351de768"},
|
||||
{file = "lxml-5.0.0-cp39-cp39-win32.whl", hash = "sha256:016de3b29a262655fc3d2075dc1b2611f84f4c3d97a71d579c883d45e201eee4"},
|
||||
{file = "lxml-5.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:52c0acc2f29b0a204efc11a5ed911a74f50a25eb7d7d5069c2b1fd3b3346ce11"},
|
||||
{file = "lxml-5.0.0-pp310-pypy310_pp73-macosx_11_0_x86_64.whl", hash = "sha256:96095bfc0c02072fc89afa67626013a253596ea5118b8a7f4daaae049dafa096"},
|
||||
{file = "lxml-5.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:992029258ed719f130d5a9c443d142c32843046f1263f2c492862b2a853be570"},
|
||||
{file = "lxml-5.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:db40e85cffd22f7d65dcce30e85af565a66401a6ed22fc0c56ed342cfa4ffc43"},
|
||||
{file = "lxml-5.0.0-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:cfa8a4cdc3765574b7fd0c7cfa5fbd1e2108014c9dfd299c679e5152bea9a55e"},
|
||||
{file = "lxml-5.0.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:049fef98d02513c34f5babd07569fc1cf1ed14c0f2fbff18fe72597f977ef3c2"},
|
||||
{file = "lxml-5.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a85136d0ee18a41c91cc3e2844c683be0e72e6dda4cb58da9e15fcaef3726af7"},
|
||||
{file = "lxml-5.0.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:766868f729f3ab84125350f1a0ea2594d8b1628a608a574542a5aff7355b9941"},
|
||||
{file = "lxml-5.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:99cad5c912f359e59e921689c04e54662cdd80835d80eeaa931e22612f515df7"},
|
||||
{file = "lxml-5.0.0-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:c90c593aa8dd57d5dab0ef6d7d64af894008971d98e6a41b320fdd75258fbc6e"},
|
||||
{file = "lxml-5.0.0-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8134d5441d1ed6a682e3de3d7a98717a328dce619ee9c4c8b3b91f0cb0eb3e28"},
|
||||
{file = "lxml-5.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f298ac9149037d6a3d5c74991bded39ac46292520b9c7c182cb102486cc87677"},
|
||||
{file = "lxml-5.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:894c5f71186b410679aaab5774543fcb9cbabe8893f0b31d11cf28a0740e80be"},
|
||||
{file = "lxml-5.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9cd3d6c2c67d4fdcd795e4945e2ba5434909c96640b4cc09453bd0dc7e8e1bac"},
|
||||
{file = "lxml-5.0.0.zip", hash = "sha256:2219cbf790e701acf9a21a31ead75f983e73daf0eceb9da6990212e4d20ebefe"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
@ -4813,6 +4842,22 @@ type = "legacy"
|
|||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "tsinghua"
|
||||
|
||||
[[package]]
|
||||
name = "polib"
|
||||
version = "1.2.0"
|
||||
description = "A library to manipulate gettext files (po and mo files)."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "polib-1.2.0-py2.py3-none-any.whl", hash = "sha256:1c77ee1b81feb31df9bca258cbc58db1bbb32d10214b173882452c73af06d62d"},
|
||||
{file = "polib-1.2.0.tar.gz", hash = "sha256:f3ef94aefed6e183e342a8a269ae1fc4742ba193186ad76f175938621dbfc26b"},
|
||||
]
|
||||
|
||||
[package.source]
|
||||
type = "legacy"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple"
|
||||
reference = "tsinghua"
|
||||
|
||||
[[package]]
|
||||
name = "portalocker"
|
||||
version = "2.8.2"
|
||||
|
@ -5490,6 +5535,8 @@ files = [
|
|||
{file = "pyfreerdp-0.0.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:881003ce2853d9a290c47a04c165941a5a0addd7ad360d033f275dec3eead192"},
|
||||
{file = "pyfreerdp-0.0.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:a54ae7c62b3c92e4dba082e328e0bb190f83f45eb84cf59eabb894dfe24a07f7"},
|
||||
{file = "pyfreerdp-0.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:33c3e14664e306c31c2a792cb8dfdd6a381e35f79583a271dd20be25b14ad73d"},
|
||||
{file = "pyfreerdp-0.0.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c7df63da48b67a31d76b62ee70f5f0ffc964b79b34c4e6c610f67a24fba2aee1"},
|
||||
{file = "pyfreerdp-0.0.2-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:df62184ef7fd8bc76f9efd172387e6e7cef9f3777a57bb14f3551b2972f55ef3"},
|
||||
{file = "pyfreerdp-0.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cfd97b8da87b1439407b40e7eda998f0df44332211353b0f4217e91d233bc53"},
|
||||
{file = "pyfreerdp-0.0.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9ce1a906e861335864bb8c976612a5b1d0595955b0cde35e3697eed7812c8b6"},
|
||||
{file = "pyfreerdp-0.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9b630f604300323b3e1fe6b27d442636f9b0d247eba3cc4340a39721c6d85273"},
|
||||
|
@ -5513,6 +5560,7 @@ files = [
|
|||
{file = "pyfreerdp-0.0.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb31b620013859a7142a391d9ce57c195f26c3c9991883f87bc5ef1703cf806f"},
|
||||
{file = "pyfreerdp-0.0.2-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c839d3ed9c0cc4021129e26c06d3bc45982bdaba8a2a115051ad43c5f6108d11"},
|
||||
{file = "pyfreerdp-0.0.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3c2a23db4a56903dfff9ac5e8b2b7aa713af694dce5a4f3905ef7703b4f9dcd"},
|
||||
{file = "pyfreerdp-0.0.2.tar.gz", hash = "sha256:caf4b422eb32a327095b548bb1a22a22b926b6e15819c9a83b6461050b11870d"},
|
||||
]
|
||||
|
||||
[package.source]
|
||||
|
@ -7779,4 +7827,4 @@ reference = "tsinghua"
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.11"
|
||||
content-hash = "f3a3ef297a045ff896b54897f8ac3593e0f0894637339c7de139453991278139"
|
||||
content-hash = "86fd825091e6032ad4a48f595a627555822618f8a1a0ed1f314f024e54d190d0"
|
||||
|
|
|
@ -146,6 +146,7 @@ django-cors-headers = "^4.3.0"
|
|||
mistune = "2.0.3"
|
||||
openai = "^1.3.7"
|
||||
xlsxwriter = "^3.1.9"
|
||||
polib = "^1.2.0"
|
||||
|
||||
|
||||
[tool.poetry.group.xpack.dependencies]
|
||||
|
|
Loading…
Reference in New Issue