ChatGPT APIと検索APIを使ってBingGPTに似たシステムを作ってみる

こんにちは！逆瀬川 ( https://twitter.com/gyakuse )です！
今日はBingGPT Cloneを作ってみたいと思います。コードを以下で公開しているのでぜひ遊んでみてください。

https://colab.research.google.com/drive/1BbJSQMFZv2_pHDmi2RZ5fwqLc0SYJmdc?usp=sharing

## BingGPTについて

BingAIやBingChatとも呼ばれる、Bingのチャット機能です。

![今期のおすすめアニメを教えて下さい_-_Search.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958603/9994849e-4229-b879-5cf2-08e9223dbc9f.png)

特徴としては検索を行い、その結果に基づいて回答をしてくれることがあり、ChatGPTの弱みである最新情報を取得できないこと、事実に基づいて回答をできないこと(あくまで大規模なデータからトレーニングしている言語モデルであるため、嘘をつく)を解消してくれます。
ちなみに、ChatGPTに聞いてみると以下のように返答してくれました。

![Cursor_と_アニメおすすめ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2958603/c4b7cb34-7295-2ab5-a39b-687cab60782f.png)

あらためてChatGPTのzero-shot性能に驚かされます。ただ、嘘はついていませんが、最新の情報を回答してくれません。

このBingGPTはめっちゃ便利なのですが、waitlistで待たされている人も多く、またターン数制限などもあり悲しみがあります。
今回はこれを手元で動かせるように実装してみます。

## どのように実装するか考えてみる

昨日、事実をもとに要約してQAする仕組みについて記事を書きました。

https://qiita.com/sakasegawa/items/16714fa132e874cab069

基本的にはこの仕組みを用いて実装すればよさそうです。

### BingGPTはどのように実装しているか

検索ワードを出力する処理、検索する処理、検索を元に回答をする処理の3段階に分けて処理していそうな気がします。
検索ワードをどのように出しているのかは分かりませんが、単純に考えると以下の2パターンが考えられそうです

- ユーザーの入力をもとに既存の検索ワードを格納したVector Storeに対して近傍探索している
- ユーザーの入力を単純にGPT-3に渡して検索ワードを出力させている

今回はコストを抑えるためにできるだけChatGPT APIを使用します。

### 処理の流れ

いったん一番丁寧に行うパターンの実装を考えてみます。

- ユーザーが質問入力を行う
    - questionに格納する
- 検索クエリーを抽出する (今回はしません)
    - ChatGPT APIにquestionを渡し、queryを抽出します
    - 単純な実装ではこの工程は不要です
- 検索結果を取得する
    - Google Custom Search APIを使って検索結果を取得します
    - Bing APIなどでも行えます
- 検索結果のそれぞれのタイトルを渡し、情報ソースとして良さそうなサイトを選ぶ (今回はしません)
    - 単純な実装の場合、上位3サイト等を選べば良いだけです。
- それぞれのサイトをスクレイピングし、contentを抽出する
- 各サイトのcontentを要約する
    - それぞれ先頭2500文字抽出して500文字以内に要約します
    - 要約文をconcatします
- 結合された要約に対してQAを行う

## 実装

### 検索結果を取得する

Custom Search APIの取得などについては以下を参考にしてください。

https://www.system-exe.co.jp/kotohajime15/

```py
# ref: https://www.system-exe.co.jp/kotohajime15/
from googleapiclient.discovery import build
def get_search_results(query, num, start_index = 0):
    # Google Custom Search API
    service = build("customsearch",
                    "v1",	
                    cache_discovery=False,
                    developerKey=google_api_key)
    # CSEの検索結果を取得
    result = service.cse().list(q=query,
                                cx=google_cse_id,
                                num=num,
                                start=start_index).execute()
    # 検索結果(JSON形式)
    return result
```

### それぞれのサイトをスクレイピングし、contentを抽出する

contentをいい感じに抽出します。requestsとBeautifulSoupを使っても実現できますが、clearning処理が面倒です。今回はboilerpipeを使って抽出します。

https://qiita.com/hoto17296/items/c61c08dd21cc38e56437

```py
from boilerpipe.extract import Extractor

def get_contents(links):
    contents = []
    for link in links:
        extractor = Extractor(extractor='DefaultExtractor', url=link)
        contents.append(extractor.getText())
    return contents
```

### 各サイトのcontentを要約する

ChatGPT APIを使って要約します。
要約においては「質問と関連性の高い文章を抽出する」というタスクにし、必要な情報のみ取れるようにします。
また、boilerpipeでうまく抽出できない場合に備えて、500文字以上を対象にします。

```py
def summarize_contents(contents):
    extract_texts = ""
    for con in contents:
        if len(con) > 500:
            # print(con[:2500])
            try:
                m, _ = completion(f"{con[:2500]}\n\n上記の文章にかんして、{question}という質問に関連する文章を抽出してください", "", [])
                extract_texts += m
                print(m)
            except:
                print("error")
    return extract_texts[:2500]
```

### 結合された要約に対してQAを行う

ChatGPT APIを使ってQAを行います。

```py
def bing_gpt(question):
    search_result = get_search_results(question, 10)
    links = get_links(search_result)
    contents = get_contents(links)
    summary = summarize_contents(contents)
    m, _ = completion(f"{summary}\n\n上記の文章を参考に、{question}という質問に回答してください", "", [])
    return m
```

## 実際に動かしてみる

「今期のおすすめアニメを教えて下さい」という質問を行います。
検索APIで以下のサイトがヒットしました。

```
2023年冬アニメ人気ランキング【毎日更新】｜ニコニコのアニメ ... https://anime.nicovideo.jp/ranking/view-daily.html
2022秋アニメみんなが選んだ人気おすすめランキング・トップ20 ... https://www.animatetimes.com/news/details.php?id=1599950303
【投票結果 1~1909位】おすすめ神アニメランキング！面白いアニメ ... https://ranking.net/rankings/best-kamianimes
アニメ人気ランキングまとめ一覧 TOP100【2021年版】｜「今 ... https://www.animatetimes.com/tag/details.php?id=10357
【2022】神アニメ83選! 絶対観るべきオススメアニメ - アキバ総研 https://akiba-souken.com/anime/matome/kami_anime/
今期アニメ番組曜日別一覧 | アニメイトタイムズ https://www.animatetimes.com/tag/details.php?id=1392
#今期おすすめアニメ | TikTok https://www.tiktok.com/tag/%E4%BB%8A%E6%9C%9F%E3%81%8A%E3%81%99%E3%81%99%E3%82%81%E3%82%A2%E3%83%8B%E3%83%A1
【2023】ハマる神アニメのおすすめランキング56選｜今期・歴代の ... https://thebest-1.com/a10359/
【2023冬】今期の面白いアニメをまとめてみた【独断と偏見 ... https://kakaoblog.com/post-44515
【人気投票 1~74位】2023冬アニメ評価ランキング！今期アニメ一覧 ... https://ranking.net/rankings/best-2023-winter-animes2
```

テキストを抽出して要約したものが以下となります。

```
1月スタートの今期アニメ覇権争いの結果は？スリリングな作品が集結！

正直呪術廻戦は結構前から漫画屋さんとかでは表紙で見てましたが絵が好きではなくて見てませんでした。しかしアニメでは表紙と違ったタッチの絵の書き方で、綺麗で見やすく、アニメから漫画も読みましたが思った絵の感じといい意味で違ってすごく良かったです。

Jujutsu Kaisenはまだ終わりが近いですが、アニメと漫画の絵の違いに驚きました。

ヴァイオレット・エヴァーガーデンは毎話泣けるレベルなので、おすすめのエピソードを挙げるのはすごく難しいんですけど......。

岡部倫太郎は超かっこいいし、ラストも最高だぞ。

正直言って見る価値ないです。

呪術廻戦以外にも、今期のアニメが充実しているようですね。
「あなたが、「今」おすすめしたい「ハマっている」アニメ」を随時募集しており、その結果をラインキング形式で紹介します。ランキングは、「投稿数の多さ」や「投稿者の熱心さ」などにも注目した独自ランキングです。純粋にファンの方が選んだランキングであり、「今」観てほしいアニメランキングになっています。アニメ好きの方が選んだ、おすすめアニメ。」


「SPY×FAMILY」、「スーパーカブ」、「古見さんは、コミュ症です。」、「デカダンス」、「鬼滅の刃」、「星☆トゥインクルプリキュア」、「ひびき、たべものにまつわる冒険。」、「どろろ」が今期のおすすめアニメとして挙げられる。


『進撃の巨人 The Final Season』完結編（前編）
『東京卍リベンジャーズ』聖夜決戦編
『スパイ教室』
『ジョジョの奇妙な冒険 ストーンオーシャン』第25話～最終話
『NieR:Automata Ver1.1a』
『吸血鬼すぐ死ぬ２』
『文豪ストレイドッグス』第4シーズン
『ツルネ －つながりの一射－』
```

最終的なQAによって以下の回答が得られました。

```
今期のおすすめアニメは、以下の作品です。

1.「呪術廻戦」
2.「ヴァイオレット・エヴァーガーデン」
3.「岡部倫太郎と探偵の神隠し」
4.「SPY×FAMILY」
5.「スーパーカブ」
6.「古見さんは、コミュ症です。」
7.「デカダンス」
8.「鬼滅の刃」
9.「星☆トゥインクルプリキュア」
10.「ひびき、たべものにまつわる冒険。」

また、上記に加えて「進撃の巨人 The Final Season」完結編（前編）や、「東京卍リベンジャーズ」聖夜決戦編なども人気が高いです。
```

ひびき、たべものにまつわる冒険。、「岡部倫太郎と探偵の神隠し」は存在しないアニメです。
このなかでは「スーパーカブ」「「東京卍リベンジャーズ」聖夜決戦編」「進撃の巨人 The Final Season完結編（前編）」のみ期待した回答となっていました。

## 後記

- ファクトに基づいて回答させるシステムをしっかり作るのはわりと大変そうです
- プロンプトエンジニアリングをちゃんと行うことで、より精確な処理ができそうです
- ちなみに処理が大量にあるので処理時間がめっちゃ長いです