文章を3行で要約するPythonライブラリ作ってみた（DockerとPyPIのメモ）

こういう物↓を作りました。

https://github.com/s2terminal/lex-rank-summarizer

[Docker Hubに上げた](https://hub.docker.com/r/s2terminal/lex-rank-summarizer)ので、Dockerがあればそのまま使えます。
こんな事ができます。

```sh
$ docker run --rm s2terminal/lex-rank-summarizer \
  'メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬ と決意した。メロスには政治がわからぬ。メロスは、村の牧人である。笛を吹き、羊と遊んで暮して来た。けれども邪悪に対しては、人一倍に敏感であっ た。きょう未明メロスは村を出発し、野を越え山越え、十里はなれた此のシラクスの市にやって来た。メロスには父も、母も無い。女房も無い。十六の、 内気な妹と二人暮しだ。この妹は、村の或る律気な一牧人を、近々、花婿として迎える事になっていた。結婚式も間近かなのである。メロスは、それゆえ 、花嫁の衣裳やら祝宴の御馳走やらを買いに、はるばる市にやって来たのだ。先ず、その品々を買い集め、それから都の大路をぶらぶら歩いた。'
```

この結果が↓このように3行になります。

```sh
メロスは激怒した。
メロスは、村の牧人である。
きょう未明メロスは村を出発し、野を越え山越え、十里はなれた此のシラクスの市にやって来た。
```

[PyPIにも上げました](https://pypi.org/project/s2terminal-lex-rank-summarizer/)ので、`$ pip install`しても使えます。

```sh
$ pip install s2terminal-lex-rank-summarizer
$ lex-rank-summarizer \
  'メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬ と決意した。メロスには政治がわからぬ。メロスは、村の牧人である。笛を吹き、羊と遊んで暮して来た。けれども邪悪に対しては、人一倍に敏感であっ た。きょう未明メロスは村を出発し、野を越え山越え、十里はなれた此のシラクスの市にやって来た。メロスには父も、母も無い。女房も無い。十六の、 内気な妹と二人暮しだ。この妹は、村の或る律気な一牧人を、近々、花婿として迎える事になっていた。結婚式も間近かなのである。メロスは、それゆえ 、花嫁の衣裳やら祝宴の御馳走やらを買いに、はるばる市にやって来たのだ。先ず、その品々を買い集め、それから都の大路をぶらぶら歩いた。'
```

要約の仕組み自体は、参考にさせていただいた下記の記事と同じで**LexRank**を使っています。

https://ohke.hateblo.jp/entry/2018/11/17/230000

LexRankによる要約をCLIツールとして一発で使いたかったので、Pythonライブラリとして公開できる状態にしました。本稿では、このようなPythonでのCLIライブラリの開発・配布したときの方法をメモしていきます。

## 環境
- ChromeOS Crostini (Linux) Debian 10.10
- Docker version 20.10.7

Dockerしか使わないのでPythonはホストコンピュータにインストールしていませんが、今回Python 3.9.5を使っています。環境構築については[こちらの拙稿](https://qiita.com/suzuki_sh/items/6bc15446965df20b6c5a)で紹介した方法で、Docker内で**Poetry**を使ってやっています。

今回使った`Dockerfile`と`docker-compose.yml`を貼っておきます。基本的に素のdockerコマンドは使わず`$ docker-compose`を使って開発しています。

```Dockerfile
FROM python:3.9.5-slim AS base
WORKDIR /app
ENV PYTHONPATH /app/src:$PYTHONPATH

RUN pip install poetry
COPY pyproject.toml ./
COPY poetry.lock ./
RUN poetry config virtualenvs.in-project true
RUN poetry install --no-dev

FROM base AS dev
RUN apt-get update && apt-get install -y \
    git \
    vim \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*
RUN poetry install
CMD /bin/sh -c "echo 'docker dev ready'; while sleep 1000; do :; done"
```

```docker-compose.yml
version: '3'
services:
  app:
    build:
      context: .
      target: dev
    volumes:
      - .:/app
```

## 開発
`$ poetry new --src`で初期化した環境で開発していきました。細かいソースコードはGitHubを読んでください。

Googleの公開している[python-fire](https://github.com/google/python-fire)を使って、CLI引数を受け取ったりできるようにします。

```python
from .summarize import generateSummary
import fire

def main():
    fire.Fire(generateSummary)
```

`tool.poetry.scripts`の設定を使って、CLIとして起動できるようにします。

```pyproject.toml
[tool.poetry.scripts]
lex-rank-summarizer = "s2terminal_lex_rank_summarizer.main:main"
```

これで`$ docker-compose run --rm app poetry run lex-rank-summarizer '要約したい文章'`でPythonプログラムを起動できるようになります。

### Docker
Docker Hubに公開してCLIツールとして利用できる事を目指します。
CLIツールとして起動した時に引数だけを受け取ればいいように、`ENTRYPOINT`を使って起動するようにしておきます。

```Dockerfile
ENTRYPOINT ["poetry", "run", "lex-rank-summarizer"]
```

動作するのを確認できたら、Docker Hubに公開します。`$ docker push`してもいいのですが、[Docker HubとGitHubを連携させて自動ビルド設定する](https://docs.docker.jp/docker-hub/github.html)のが楽ですし、READMEを自動で読み取ってDocker Hubのページにしてくれたりもします。

これでDocker Hubに登録されました。

https://hub.docker.com/r/s2terminal/lex-rank-summarizer

これだけで`$ docker run --rm s2terminal/lex-rank-summarizer "要約したい文章"`で使えるようになります。簡単ですね。

### PyPI
PyPIへ公開して、`$ pip install`して利用できる事を目指します。
こちらはPoetryがあれば楽です。参考にさせていただいた下記記事にほとんどすべて書いてあります。

https://kk6.hateblo.jp/entry/2018/12/20/124151

実際にPyPIへ公開される時のメタデータは`pyproject.toml`の中身を参考に埋め込まれるため、[Poetryのドキュメント](https://python-poetry.org/docs/pyproject/)を参考にある程度記載しておきます。

```pyproject.toml
license = "MIT"
readme = "README.md"
homepage = "https://github.com/s2terminal/lex-rank-summarizer"
repository = "https://github.com/s2terminal/lex-rank-summarizer"
```

ソースコードの準備ができたら公開の作業を進めていきます。まず[TestPyPI](https://test.pypi.org/)に公開することで事前にテストできます。私の場合、pyproject.ymlの設定に誤りがあって開発時は動作するのにpublishしたものを`pip install`して使うときだけ動かないという不具合があったのですが、そういった問題もTestPyPIを使うことで確認できます。

```sh
$ docker-compose run --rm app sh
# poetry build
# poetry config repositories.testpypi https://test.pypi.org/legacy/
# poetry publish -r testpypi
```

実際にTestPyPIから公開したライブラリをインストールして使ってみます。この開発環境のDockerを使ってもいいですし、適当に`$ docker run --rm -it python:3.9.5-slim bash`とかで別の環境を作って試しても良いと思います。

```sh
# pip install s2terminal-lex-rank-summarizer --extra-index-url https://test.pypi.org/simple
# lex-rank-summarizer "こんにちは。"
```

問題が無ければ、本番のPyPIの方へpublishします。

```sh
$ docker-compose run --rm app poetry build
$ docker-compose run --rm app poetry publish
```

これでPyPIに登録されました。

https://pypi.org/project/s2terminal-lex-rank-summarizer/

## まとめ
- CLIツールをDocker Hubで配布するのは簡単
- PyPIで配布するにはPoetryを使うと簡単

## 参考文献
- [Poetryを使ったPythonパッケージ開発からPyPI公開まで \- PYTHONIC BOOM BOOM HEAD](https://kk6.hateblo.jp/entry/2018/12/20/124151)
- [Python: LexRankで日本語の記事を要約する \- け日記](https://ohke.hateblo.jp/entry/2018/11/17/230000)
- [青空文庫 走れメロス](https://www.aozora.gr.jp/cards/000035/card1567.html)