ChatGPTで挑戦！週刊AWSを再現したら、AWSさんが涙目になりそうな件

# 1.はじめに

先日投稿した、以下ChatGPTにサーバレスAPIを作成させた記事は色々反響があり、その続編です。

https://qiita.com/takuma818t/items/ff89ed5ba7c41ae7f2e5


## 週刊AWSの再現に挑戦

### 週刊AWSとは

AWSは、日々サービスのアップデートが行われていて、AWSエンジニアのみなさんは、最新情報のキャッチアップが大変かと思います。
そんなAWSエンジニアの皆さん向けて、AWSソリューションアーキテクトの下佐粉さん・小林さんが毎週AWSのアップデート情報を週刊AWSという形でまとめられていて、ブログ掲載されています。

https://aws.amazon.com/jp/blogs/news/tag/%E9%80%B1%E5%88%8Aaws/

主要なアップデートをわかりやすく、コンパクトにまとめて頂いていて、この記事を中心に最新情報のキャッチアップしている人も多いのでは無いでしょうか？自分も大変お世話になっています。


ChatGPTの活用の一つとして、文章の要約に向いているという事をよく耳にしますが、もしかして週刊AWSも再現できるのでは？と思ってやってみました。


# GPT(OpenAIのAPI）を利用たAWSアップデートの要約と週刊AWS再現

## 今回の構成
今回AWSのLambdaを利用して以下構成で実装してみました。

![週刊AWS.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918922/9dd1cef1-1c80-969a-2cfa-d9f77f542797.png)

- EventBridgeでスケジューリングしLambdaを起動
- [What's New with AWS?](https://aws.amazon.com/new/)の[RSS feed](https://aws.amazon.com/about-aws/whats-new/recent/feed/)から直近１週間の記事を取得
- リンク先の記事をOpenAIのAPIを使って要約
- 要約記事を[QiitaのAPI](https://qiita.com/api/v2/docs#%E6%8A%95%E7%A8%BF)を使って自動で記事投稿

## 実装してみての工夫した点・課題
### 記事の冒頭の挨拶
単にAWSアップデートだけ書くと、機械感満載でした。
週刊AWSを参考に、アップデート情報のまとめの冒頭に気の利いた挨拶を入れてもらいました。プロンプトをもう少し工夫したらもう少し面白い事を書いてくれるかもしれません。
ChatGPTです！とか○○です。と名乗る事もあったので、勝手に「ジピちゃん」という名前をつけて名乗らせています。
※もっといい名前があると思うので、いい名前が思い浮かんだ方は、名付けてあげて欲しいです。

### URLから記事の取得と日本語化もGPTに任せる

ChatGPTに「以下URLの記事の要約をお願いします」と依頼しても、
> 私は現在のWebサイトを閲覧できないAIモデルです。

とWebサイトを閲覧できないモデルと返答があります。

今回利用したAPI版のGPTのモデルだとURLを伝えると読み込める様でした。
日本語での要約までに
「Webスクレイピング」→「日本語化」→「GPTで要約」というような３ステップが必要かもと思いましたが、記事のURLを与えるだけで３ステップすべてやってくれました。

### OpenAIのAPI応答時間
ChatGPTは有料版を契約しているので、GPT-3.5のレスポンスは同じぐらいレスポンス早いと思ったのですが、APIはそれとは別な様でプロンプト入力からのレスポンスが結構時間がかかりました。

Lambdaで実装しましたが、記事数が多いと制限時間15分を超えてしまいました。
今回暫定的な回避策として、実行時間が残り１分になったら、記事投稿処理に遷移させるようにしました。
実運用する場合は、制限時間が無いECSなどで実装する必要がありそうです。

### 主要な記事のピックアップ
AWSさんは、主要な記事に絞って掲載頂いています。

今回の生成記事は、期間内のすべての記事を要約する形になりましたが、主要な記事をどうピックアップして、受け取り処理するかは今後検討する必要があります。
「json形式で返して」と依頼すれば、返してくれる様な気もしますが。

## 実装方法
公開の構成は以下で実装しました。

### Lambdaのソースコード

```lambda_function.py
import os
import feedparser
import openai
import boto3
from datetime import datetime, timedelta
import requests
import json
from dateutil.parser import parse

openai.api_key = os.environ["OPENAI_API_KEY"]

#RSSから直近１週間のエントリーを取得
def get_weekly_updates(rss_url):
    now = datetime.now()
    week_ago = now - timedelta(days=7)
    feed = feedparser.parse(rss_url)
    entries = []

    for entry in feed.entries:
        entry_date = datetime(*entry.published_parsed[:6])
        if entry_date >= week_ago:
            entries.append(entry)

    return entries

#OpenAIのAPIでリンク先の記事を日本語で要約
def summarize(link):
    prompt = (
        f"あなたは、AWSのソリューションアーキテクトです。"
        f"以下URLのAWS関連の記事を日本語で200字程度で簡潔に要約してください: ¥n {link}"
        )
        
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "user", "content": prompt},
        ],
    )

    summary = response.choices[0]["message"]["content"].strip()
    return summary

#記事冒頭の挨拶をOpenAIのAPIで生成
def pre_article():
    
    prompt = (
        f"あなたは、AWSソリューションアーキテクトのジピちゃんです。"
        f"AWS技術者に対して、週刊で最新のアップデート情報を配信しています。"
        f"記事の冒頭のAWSの技術情報を交えた挨拶を300字程度で書いて下さい。"
    )
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "user", "content": prompt},
        ],
    )

    return response.choices[0]["message"]["content"].strip()

#Qiitaに限定公開でPOST
def post_qiita_article(title, body):
    api_key = os.environ["QIITA_API_KEY"]
    url = "https://qiita.com/api/v2/items"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }
    data = {
        "title": title,
        "body": body,
        "tags": [{"name": "AWS"},{"name": "ChatGPT"}],
        "private": True,
    }
    response = requests.post(url, headers=headers, data=json.dumps(data))

    return response.status_code

def lambda_handler(event, context):
    rss_url = os.environ["RSS_URL"]
    updates = get_weekly_updates(rss_url)
    summaries = []
    now = datetime.now()
    week_ago = now - timedelta(days=7)
    
    #冒頭の挨拶
    summaries.append(f"# はじめに")
    summaries.append(f"{pre_article()}")
    
    summaries.append(f"## {week_ago.year}年{week_ago.month}月{week_ago.day}日の週の主要なアップデート")

    last_date = None
    for update in updates:
        # 日付が変わったらh3見出しをつける
        datetime_object = parse(update.published)
        date_object = datetime_object.date()
        if last_date is None or last_date != date_object:
            summaries.append(f"### {date_object}\n\n")
            last_date = date_object
            
        #アップデート情報と記事のリンクを生成
        summaries.append(f"#### [{update.title}]({update.link})")
        
        #記事の要約を生成
        summary = summarize(update.link)
        summaries.append(f"{summary}")
        
        #OpenAIのAPIが時間がかかるので、Lambdaの実行時間が残り１分になったらブレイク
        if context.get_remaining_time_in_millis() < 60000 : 
            break
        
    summaries.append("")
    summaries.append("")
    summaries.append("それでは、また来週！")
    
    #Qiitaの記事投稿
    message = "\n".join(summaries)
    title = f"GPTによる週刊AWSの再現 {week_ago.year}年{week_ago.month}月{week_ago.day}日週"
    post_qiita_article(title, message)

    return {
        "statusCode": 200,
        "body": message,
    }
```
### 外部ライブラリの組み込み
今回feedparser openai requestsの外部ライブラリを利用しています。
今回以下ライブラリを圧縮しLambda Layerに登録し組み込みました。
```
mkdir ./python/ 
pip install feedparser openai requests urllib3==1.26.17 -t ./python/ 
zip -r OpenAI_library.zip ./python/*
```
### 環境変数の設定
Lamnbdaに以下を環境変数として設定しました。

#### OPENAI_API_KEY
OpenAIのAPIを利用する時のAPIキーです。以下から発行可能です。
https://platform.openai.com/account/api-keys

#### QIITA_API_KEY
Qiitaの記事投稿に利用するAPIキーで、以下から発行可能です。
https://qiita.com/settings/applications

#### RSS_URL
[What's New with AWS?](https://aws.amazon.com/new/)のRSS feedです。
英語版の最新情報の以下を登録しています。
https://aws.amazon.com/about-aws/whats-new/recent/feed/

#### 注意事項
今回は、検証目的のため、環境変数にAPIキー登録していますが、本来はシークレットマネージャなどへの登録し利用してください。

# GPTによる週刊AWS再現の結果

## GPTで自動生成された記事
こちらが、実際に自動生成され、Qiita自動投稿された記事です。
まったく、編集、修正していません。

https://qiita.com/takuma818t/private/2f783a545c20db29cf61

※自動生成された記事の投稿について意見が分かれると思いますので、限定公開としています。

## 感想
現在GPT-4のAPIは、ウェイトリスト待ちなので、GPT-3.5のモデルで生成された記事になりますが、割と近い形で再現できてるのでは無いでしょうか？

インターネットには膨大な情報があふれており、全てに目を通すのは難しいです。そのため、要点を抽出し、分かりやすく伝えることが求められています。現時点においては、このようなニーズがあるので多くのサイトや記事でまとめや要約が行われています。

今回の週刊AWSの再現してみることによって、前回の記事に書いたエンジニアの在り方役割だけでなく、記事の著者の役割や在り方も大きく変わってくるのでは？と実感しました。

# 最後に
ここまで読んで頂いてありがとうございます。これを読んで頂いているあなたにとって一つでも参考になる情報があれば幸いです。

もし参考になったら「いいね」や「ストック」やSNSでシェアしてもらえたら励みになりますのでよろしくお願いします。