はじめに
今回は論文のAbstractを抽出し、要約・翻訳を施してSlackへ送るアプリをPythonで作成しました。Abstractは論文を要約していますが、チャットで共有するには少し長いですよね。これを使うことで論文共有がスムーズになるかと思います!
目次
- 構成図
- プログラム全体
- Pythonによる実装
- PDFからAbstractを抽出
- Transformersによる要約
- DeepL APIによる翻訳
- SlackへPOST
- 終わりに
- 参考文献
構成図
プログラム全体
import os
import requests
from pdfminer.high_level import extract_text
from transformers import pipeline
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
### EXTRACT INFO FROM PDF ###
# Extract Abstract
text = extract_text("test_paper1.pdf") # ローカルPCにある対象の論文
text = text.replace("\n", "")
text = text[text.find("Abstract"):text.find("Introduction")]
### SUMMARIZATION ###
summarizer = pipeline("summarization")
response = summarizer(text, max_length=100, min_length=30, do_sample=False)
summarized_text = response[0]["summary_text"]
### TRANSLATE TEXT ###
# Settings
post_url = "https://api-free.deepl.com/v2/translate" # エンドポイント
api_key = "ご自身のAPI Key"
source_lang = "EN"
target_lang = "JA"
# Content
content = {
"text":summarized_text,
"auth_key":api_key,
"source_lang":source_lang,
"target_lang":target_lang
}
request = requests.post(post_url, data=content)
translated_text = request.json()["translations"][0]["text"] # レスポンスから翻訳済みテキストを取り出す
# Make return text
result = "【論文紹介】\n・要約\n" + summarized_text + "\n" + "・和訳\n" + translated_text
### POST TO SLACK ###
client = WebClient(token=os.environ['SLACK_BOT_TOKEN']) # 環境変数のTokenを渡す
try:
filepath="test_paper1.pdf" # 自身のファイル
response = client.files_upload(channels='#test', file=filepath, initial_comment=result) # 自身のチャンネル
assert response["file"] # the uploaded file
except SlackApiError as e:
# You will get a SlackApiError if "ok" is False
assert e.response["ok"] is False
assert e.response["error"] # str like 'invalid_auth', 'channel_not_found'
print(f"Got an error: {e.response['error']}")
Pythonによる実装
では早速実装していきます。先に使用するライブラリをinstall/importしておきましょう。
import os
import requests
from pdfminer.high_level import extract_text
from transformers import pipeline
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
1. PDFからAbstractを抽出
まず、論文PDFからAbstractに該当する箇所を抽出していきましょう。
コードは以下の通りです。
### EXTRACT INFO FROM PDF ###
# Extract Abstract
text = extract_text("test_paper1.pdf") # ローカルPCにある対象の論文
text = text.replace("\n", "")
text = text[text.find("Abstract"):text.find("Introduction")]
まずpdfminerというライブラリのextract_textメソッドを使用することでPDF全体の文字データを取得します。次に、改行タグを削除しておきます。削除しておかないとその後のタスクで都合が悪いです。最後に、「Abstract」から「Introduction」までの文字列を抽出しています。
2. Transformersによる要約
次は抽出されたAbstractをさらに要約します。Hugging FaceのTransformersのパイプラインを使用して翻訳を行います。
### SUMMARIZATION ###
summarizer = pipeline("summarization")
response = summarizer(text, max_length=100, min_length=30, do_sample=False)
summarized_text = response[0]["summary_text"]
1~2行程度に要約してほしいので、30~100語の範囲を指定しました。
3. DeepL APIによる翻訳
翻訳にはDeepLのAPIを使用しました。アカウントを作成すれば、無料枠で月500,000文字まで翻訳可能です。Abstractだけを使えばそうそう使い切ることはないと思います。
### TRANSLATE TEXT ###
# Settings
post_url = "https://api-free.deepl.com/v2/translate" # エンドポイント
api_key = "ご自身のAPI Key"
source_lang = "EN"
target_lang = "JA"
# Content
content = {
"text":summarized_text,
"auth_key":api_key,
"source_lang":source_lang,
"target_lang":target_lang
}
request = requests.post(post_url, data=content)
translated_text = request.json()["translations"][0]["text"] # レスポンスから翻訳済みテキストを取り出す
# Make return text
result = "【論文紹介】\n・要約\n" + summarized_text + "\n" + "・和訳\n" + translated_text
アカウント登録するとご自身のAPI Keyが発行されますので、そちらを入力してください。
4. SlackへPOST
最後に要約・翻訳済みのAbstractをSlackへ投稿しましょう。まずは公式Documentに従い、投稿したいチャンネルにアプリを作成してください。途中環境変数の設定が必要になります。ファイルのアップロードのコードはGitHubのサンプルコードをそのまま真似しました。
### POST TO SLACK ###
client = WebClient(token=os.environ['SLACK_BOT_TOKEN']) # 環境変数のTokenを渡す
try:
filepath="test_paper1.pdf" # 自身のファイル
response = client.files_upload(channels='#test', file=filepath, initial_comment=result) # 自身のチャンネル
assert response["file"] # the uploaded file
except SlackApiError as e:
# You will get a SlackApiError if "ok" is False
assert e.response["ok"] is False
assert e.response["error"] # str like 'invalid_auth', 'channel_not_found'
print(f"Got an error: {e.response['error']}")
おわりに
以上で完成です!
今後の課題としては、
- 「Abstract」と「Introduction」に反応するようにしているため、「Summary」とかには対応できていない件
をどうにかしたいですね。