ページを自動要約するプラグインを作成してみる

Ruka Kanno
nextbeat-engineering
11 min readOct 26, 2023

こんにちは。ネクストビートでエンジニアをしている菅野です。
普段は”保育園・幼稚園の『タイヘン』を『カンタン』に”をテーマに保育士バンク!コネクトの開発をしています。

ChatGPTのAPIを使う練習として、開いているWebサイトを自動要約するChromeプラグインを作成してみたので、ご紹介致します。

使用する技術スタックは下記になります。

  • Node: v20.5.1
  • Python: 3.9.13
  • ChatGPT

流れとしては、下記になります。

Nodeで開いているページの情報を取得

Pythonに送り情報を加工

ChatGPTのAPIに送信

では実際に作っていきます!

Chromeプラグインを作成する準備

自作のChromeプラグインを実行できる環境を整えます。

プラグインの作成は非常に簡単で、2ステップで完了します。

はじめに、最小構成のプラグインに必要なファイルを作成します。
適当なディレクトリを作成して、manifest.jsonとmain.jsを作成します。

src
┣ manifest.json
┗ main.js

manifest.jsonには下記のように書いておきます。

{
"name": "AutoSummary",
"version": "1.0.0",
"manifest_version": 2,
"description": "自動要約",
"content_scripts": [{
"matches": ["https://*/*"],
"js": [
"main.js"
]
}]
}

main.jsの中身は適当で大丈夫です。

window.alert('Hello World')

次に、プラグインをChromeに登録していきます。
chrome://extensions にアクセスして、下記の手順で登録します。

右上にあるデベロッパーモードをonにします。

左上にある「パッケージ化されていない…」から先ほどのファイルが置いてあるディレクトリを指定します。

これだけで自作のプラグインを動かすことができます!

Pythonでローカルサーバーの準備

Nodeで取得したデータを受け取る先を用意します。
今回は簡易的に、PythonのBottleを使用してローカルサーバーを作成します。

Bottleは軽量Webフレームワークで、こういった小さいものを作る際に重宝します。

from bottle import *

@post('/')
def index():
return 'ok'

try:
run(host='0.0.0.0', port=8000, reloader=True)
except KeyboardInterrupt:
pass

curl -Xpost http://localhost:8000
などで疎通確認すると ok が返ってきます!

ChatGPTのAPIを使う準備

公式サイトを参考に、APIトークンの取得と、openai のインストールを完了しておきます。

APIに適当な文字列を送信して、疎通確認を行います。
下記のようにPythonで記述して、何かしらの返答がChatGPTから返ってきたら成功です!

import openai

# xxxxxxx に取得したAPIトークンを記載
openai.api_key = 'xxxxxxxxxxxxxxxxxx'

def message(role, text):
return { 'role': role, 'content': text }

system = message('system', """
適当なHTMLファイルから抜き出した文字列を渡すため、概要を抽出して簡潔に内容を日本語で説明をしてください。
""")

# ChatGPTにテキストを送信する
def gpt(text):
response = openai.ChatCompletion.create(
model='gpt-3.5-turbo',
messages=[system] + [message('user', text)]
)

return response['choices'][0]['message']['content']

print(gpt('このページはHTMLのサンプルです。'))

HTMLファイルの加工

適当なWebサイトからそのままダウンロードしたHTMLファイルには、scriptやstyleなどの余分な情報も含まれています。

そのため、それらを省くために、PythonのBeautifulSoupを使って、文字列のみに変換します。

BeautifulSoupは、HTMLやXMLの解析ライブラリです。
スクレイピングする際は重宝します。

from bs4 import BeautifulSoup

# 適当なHTMLファイルを読み込む 後でNodeから送られてきたデータと入れ替える
with open('sample.html', 'r') as f:
html = f.read()

def html_to_text(html):
soup = BeautifulSoup(html, 'html.parser')
return '/n'.join(soup.stripped_strings)

print(html_to_text(html))

タグ内の文字列を改行繋ぎに変換します。
非常にシンプルに行うことができます!

全てを繋げます!

ここまでで全ての準備が完了しました。
細かな修正を加えて、Chrome拡張を完成させましょう!

  • Chromeプラグインを整理

localhostにリクエストを投げる処理と、リクエストを送るためのボタンを追加します。

下記を追加した後、Chromeからプラグインの再読み込みを行なって、適当なページにアクセスすると左下に要約ボタンが表示されるかと思います。

const postHTML = async () => {
// ローカルホストにPOSTリクエストを送信
const res = await fetch('http://localhost:8000/', {
method: 'POST',
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({

// 開いているページのHTMLを送信
page: document.querySelector('html').innerHTML
})
});

data = await res.text()
return data;
}


// 毎回要約されると面倒なので、要約ボタンを作成
const button = createButton()
buddton.addEventListener('click', () => {
postHTML().then(ret => console.log(ret));
})
document.body.appendChild(button);

function createButton() {
const button = document.createElement('button')
button.textContent = '要約'

// 画面左下に固定
button.style.position = 'fixed'
button.style.bottom = '10px'
button.style.left = '10px'

// add style
button.style.zIndex = '100000'
button.style.bgcolor = 'white'
button.style.padding = '4px'
return button
}
  • Python側の処理を繋ぎこむ

indexの中身を下記のように修正します。
中で使用しているメソッドは、上記の準備で作成したものです。

@post('/')
def index():
page_text = html_to_text(request.json['page'])
description = gpt(page_text)
return description

CORSに対応するために、indexの上あたりに下記を追加します。

CORSの対応は下記を参考にさせていただきました。
https://qiita.com/rysk_lunch/items/d7cc7cd8ab5fa1714312

# --- CORSへの対応 https://qiita.com/rysk_lunch/items/d7cc7cd8ab5fa1714312

@hook('after_request')
def enable_cors():
response.headers['Access-Control-Allow-Origin'] = '*'
response.headers['Access-Control-Allow-Methods'] = '*'
response.headers['Access-Control-Allow-Headers'] = '*'

@route('/', method='OPTIONS')
def response_for_options(**kwargs):
return {}

# --- CORSへの対応ここまで

# index ...

ファイルの全体像は下記になります。

api = 'xxxxxxxxxxxxxx'

# *** 1. Pythonでローカルサーバーの準備

from bottle import *

# --- CORSへの対応 https://qiita.com/rysk_lunch/items/d7cc7cd8ab5fa1714312
# ...
# --- CORSへの対応ここまで

# index ...


# *** 2. ChatGPTのAPIを使う準備
# ...


# *** 3. HTMLファイルの加工
# ...

# run localhost
try:
run(host='0.0.0.0', port=8000, reloader=True)
except KeyboardInterrupt:
pass

完成版をまとめたものが下記GitHubになります。
https://github.com/RkKnn/AutoSummaryPlugin

完了したら python main.py でサーバーを起動させておきましょう。

サーバーの起動を完了した後、要約ボタンを押すと開発者ツールのコンソールログにページの要約が書き出されているかと思います!

お試しで、弊社が運営している保育士バンク!コネクトの職員アプリの機能紹介サイトを要約してみます。
https://kidsna-connect.com/site/feature/staffapp

以上で一連の流れが完了です!
Chromeプラグインを使うと色々できそうな予感が高まります!

最後まで読んでいただき、ありがとうございました。

We are hiring!

本記事をご覧いただき、ネクストビートの技術や組織についてもっと話を聞いてみたいと思われた方、カジュアルにお話しませんか?

・今後のキャリアについて悩んでいる
・記事だけでなく、より詳しい内容について知りたい
・実際に働いている人の声を聴いてみたい

など、まだ転職を決められていない方でも、ネクストビートに少しでもご興味をお持ちいただけましたら、ぜひカジュアルにお話しましょう!

🔽申し込みはこちら
https://hrmos.co/pages/nextbeat/jobs/1000008

また、ネクストビートについてはこちらもご覧ください。

🔽エントランスブック
https://note.nextbeat.co.jp/n/nd6f64ba9b8dc

--

--