FioneでPython連携

Fioneでh2o-3との連携にはREST APIを使っていたのだけど、データフレーム操作の細かいことをやろうとすると、謎が多いRapidsのエンドポイントを使う必要があり、データフレームの加工が厳しい状態だった。ということで、FioneからPythonを実行して、Python経由でh2o-3連携をすることにした。(基本的な操作は引き続きREST APIを使う予定) 汎用定期にしておきたいなー、と思い、ここにあるような感じで、Pythonファイルを置くことで、Fione(Java)からPythonコマンドを実行する。必要なパラメータ等はFioneがiniファイルを作成して、設定を渡すので、それに合わせて処理すればOK。一応、Fioneの画面上から実行したいので、画面上の入力項目はそのpyファイルを引数なしで実行してprint_module()のようなJSONを出力することで、Fioneの画面に入力欄が表示され、それがiniファイルとしてPythonの実行時に渡される感じ。なので、入力項目を含めてpyファイルに書いておけば、Fioneの画面上に表示されるので、Pythonファイルで任意の機能が追加できるようになる。

という感じで、拡張性が格段にました感じですが、今までFioneを本番環境での運用にどのように組み込んで利用すればよいか、という悩みがあったのですが、Python連携ができるようになったことで、本番環境のバッチ的なフローに関しては、このpythonファイルとiniファイルを取得できればh2o-3と直接やりとりができるので、問題が解決できる感じです。なので、Fioneで画面上でポチポチやって分析・開発して、運用環境へはpyとiniファイルを引き渡すことで、スムーズに一連の流れを進めることができるようになるはず。

もう少し手直ししたら、リリースしよう…。

Ubuntuで設定ファイルの残骸を消す

パッケージを–purgeを付けずにremoveしていたりすると、設定ファイルが残骸として残ってしまう。apt listとかでみると

gir1.2-gudev-1.0/focal 1:233-1 amd64 [residual-config]

みたいな感じで、パッケージはないけど、設定ファイルだけが残っている状態になる。residual-configは日本語だと、設定が残存となっている。そこで、一括で残骸を消すためには以下のコマンドを叩けば良い。

sudo apt-get purge $(dpkg -l | grep '^rc' | awk '{print $2}')

FastAPIで画像をアップロードしてダウンロードする

FastAPIを使って、画像をアップロードして、OpenCVで変換とかして、返却するというのをやりたかったのだが、イマイチな部分もある気はするけど、メモがてらに残しておく。一応、アップロードされたファイルは一旦、一時ファイルに保存している(保存しなくても良いかもしれないけど…)。そんで、process(img)の中で、画像のimgのnumpy arrayを何か変換して、戻した画像のimg_convertedのnumpy arrayを作る。あとは、img_convertedはオンメモリでcv2.imencodeで、png形式にして、Responseで返せば、画像がダウンロードされる。画像はマルチパートでアップロードする感じだけど、FastAPIのhttp://localhost:8000/docs/で送り方を確認すればよいはず。

from fastapi import FastAPI, UploadFile, File, HTTPException, Response
import cv2
import shutil
from pathlib import Path
from tempfile import NamedTemporaryFile

app = FastAPI()


@app.post("/convert/")
def convert(file: UploadFile = File(...)):
    filepath = save_upload_file_tmp(file)
    try:
        img = cv2.imread(str(filepath))
        img_converted = process(img) # OpenCVの変換処理とか
        _, img_enc = cv2.imencode('.png', img_converted)
        return Response(content=img_enc.tostring(), media_type='image/png')
    except Exception as e:
        raise HTTPException(status_code=500, detail='Failed to convert an image.')
    finally:
        filepath.unlink()


def save_upload_file_tmp(upload_file: UploadFile) -> Path:
    try:
        suffix = Path(upload_file.filename).suffix
        with NamedTemporaryFile(delete=False, suffix=suffix) as tmp:
            shutil.copyfileobj(upload_file.file, tmp)
        tmp_path = Path(tmp.name)
    finally:
        upload_file.file.close()
    return tmp_path

FastAPIでアップロードされたファイルの保存はこれを参考にした。