Argos Translateを用いたPythonによる外部APIに依存しない英語日本語相互翻訳の実行に関するメモ

# はじめに
- ネットワーク的に孤立した環境や、外部に通信ができなくなる環境で英語を日本語にする翻訳、あるいはその逆が使いたい場合の実現方法

# 前提
- Windows 11 Pro 22H2
- conda 23.1.0
- Python 3.10.9

# 全体の流れ
1. 仮想環境の作成
2. 前提モジュールの導入
3. argos-translateの基本的な使い方
4. 実装例
5. 補足

# 仮想環境の作成
- 今回はAnaconda環境で作成する
```
conda create -n argos-translate
```

# 前提モジュールの導入
- 記事作成時点(2023年2月11日)ではcondaでは"argos-translate"がインストールすることは"conda-forge"を含めてもできないのでpipでインストールする
 ```
conda activate argos-translate
pip install argostranslate
```

# argos-translateの基本的な使い方
- "argos-translate"はWindowsの場合、以下のパスに"index.json"を配置し、同じパスに"downloads"を持つ
- "index.json"は"argostranslate.package.update_package_index()"の実行でダウンロードされる。
```
\Users\<ユーザーの名前>\.local\cache\argos-translate
```
- 例えば、英語を日本語に翻訳するモデルは以下のパスとなる。
- "*.argosmodel"は"argostranslate.package.AvailablePackage.download()"の実行でダウンロードされる。
```
\Users\<ユーザーの名前>\.local\cache\argos-translate\downloads\translate-en_ja.argosmodel
```
- "argos-translate"は"argostranslate.package.install_from_path()"で上記のパス(型はpathlib.Pathで渡す)を指定してモデルを読み込む
- モデルを読み込み後"argostranslate.translate.translate()"で翻訳を実行する

# 実装例
- 以下をimport
    - argostranslate.package
    - argostranslate.translate
- クラス:ArgosTranslateInfoは翻訳するパターンとモデルのパスを格納
- 関数:do_download()はモデルのダウンロードとパスを上記クラスオブジェクトに保存
- 関数:do_translate()は翻訳の実行
- "index.json"とモデルのダウンロードは、以下で実行するので初回は必ず実行
    - "argostranslate.package.update_package_index()"
    - "do_download(pkg_info)"
- 2回目以降はモデルがダウンロードされてパスがわかっていれば、以下のみでO.K.
    - argostranslate.package.install_from_path(pkg_info.download_path)
    - "do_translate()"
```py
import argostranslate.package
import argostranslate.translate

class ArgosTranslateInfo:
    import pathlib

    def __init__(self, from_code: str = 'en', to_code: str = 'jp', download_path: pathlib.Path = None):
        self.from_code: str = from_code
        self.to_code: str = to_code
        self.download_path = download_path

    def do_download(self, install_package: argostranslate.package.AvailablePackage) -> None:
        # 今回使用するパッケージをダウンロードし、そのパスを保存しておく
        self.set_download_path(install_package.download())

    def set_download_path(self, download_path: pathlib.Path) -> None:
        self.download_path = download_path


def do_download(pkg_info: ArgosTranslateInfo) -> None:
    # 使用可能な翻訳パッケージ情報を取得
    available_pkgs: list = argostranslate.package.get_available_packages()

    # 今回使う翻訳パッケージ情報を取得
    install_package: argostranslate.package.AvailablePackage = next(
        filter(
            lambda x: x.from_code == pkg_info.from_code and x.to_code == pkg_info.to_code, available_pkgs
        )
    )

    # ダウンロード実施(パスも保存される)
    pkg_info.do_download(install_package)


def do_translate(text: str, from_code: str = 'en', to_code: str = 'ja') -> str:
    translatedText: str = argostranslate.translate.translate(
        text, from_code, to_code)
    print(text, '[', from_code, '->', to_code, ']', translatedText)
    return translatedText

# 以下が基本的な実行手順

# 翻訳したいパターンをlistで指定
pkg_infos: list = [
    ArgosTranslateInfo(from_code='en', to_code='ja'),
    ArgosTranslateInfo(from_code='ja', to_code='en'),
]

# Packageインデクス情報をダウンロード確認(アップデート確認)
argostranslate.package.update_package_index()

# 今回使用するパッケージ情報を取得し、パッケージをダウンロードし、そのパスを保存しておく
for pkg_info in pkg_infos:
    do_download(pkg_info)

# 2回目以降の実行では、pkg_infosのdownload_pathさえあれば、これ以降の手順のみで実行可能

# 今回使用するパッケージを読み込み
for pkg_info in pkg_infos:
    argostranslate.package.install_from_path(pkg_info.download_path)

# Translate
do_translate('hello world!')
do_translate('こんにちは、世界！', 'ja', 'en')
```

# 補足
- 今回は手抜きして1ファイルにまとめたが、実際はクラスをファイル分けしたり、初回実行分と翻訳実行分は分けた方がわかりやすいと思う。
- 特に目的のネットワークが外に通じていない環境での翻訳機能の実行には、実行範囲を考えないと正常に動作しなくなる。
- 今回はその辺は考慮せず、基本のみを調べた結果を自分用のメモとして記載した。

# 参考情報
- [Argos Translate](https://argos-translate.readthedocs.io/en/latest/index.html)
- [GitHub:Argos-Translate](https://github.com/argosopentech/argos-translate)
- [Pypi:argostranslate](https://pypi.org/project/argostranslate/1.4.0/#history)