LoginSignup
11
4

「AWSのWhat's Newを解説くん」」をBedrockで作りました。

Posted at

皆様、Bedrockを使うとこんな素敵なことができるようです!(すごい)

これに触発され、AWSのWhat's Newをわかりやすく解説できるアプリをStreamlitで作ってみました。

解説

処理1:What's NewのRSSを取得する

AWSのWhat's NewはRSSが公開されているので、こいつを取得します。RSSの取得はrss-parserを使用します。

requestsで取得したHTTPレスポンスをrss-parserに渡すとパースしてくれます。

rss_url = "https://aws.amazon.com/about-aws/whats-new/recent/feed/"
response = requests.get(rss_url)

rss = RSSParser.parse(response.text)
items = rss.channel.items

for item in items:
    print(item.title.content) # タイトル
    print(item.pub_date.content) # pub_date
    print(item.link.content) # Link

処理2:What's Newの本文を取得する

RSSで取得したURLから、What's Newの本文を取得します。本文の取得はBeautifulSoup4を使用します。

What's NewのHTMLを解析したところ、sectionタグ内のテキストを取得するといい感じであることがわかりました。

link = "https://*****" # What's NewのURL
response = requests.get(link) # requestsでHTMLを取得
soup = BeautifulSoup(response.text, features="html.parser")
contents = soup.section.get_text() # <section>タグ内のテキストを取得

処理3:Claude 3で会話形式の解説を生成する

試行錯誤の結果、以下のようなプロンプトとしました。

AWSのWhat's newを提示しますので、注意深く読み込んでください。

<AWSのWhat's new>
{{What's new}}
</AWSのWhat's new>

タスク
 会話形式でわかりやすく解説してください。

登場人物
- user1: AWSスペシャリスト
- user2: 新入社員

ルール
- 回答は必ず日本語で行ってください。
- ハルシネーションは許されないので、What\'s newの内容からのみ回答を生成してください。
- また、回答付不要な出力は含めず、登場人物の会話のみを出力してください。
- 回答は以下のJSON形式としてください。

{
  "conversations": [
    {
      "actor": "user1",
      "message": "..."
    },
    {
      "actor": "user2",
      "message": "..."
    },
    {
      "actor": "user1",
      "message": "..."
    }
  ]
}

テクニック的には以下のようなものを考慮しながら考えました。

  • ドキュメントを先に示す
  • ルールを示す
  • 例示する

結果的には適当にやってもいい感じになりましたね

処理4:Streamlitで画面UIを作成する

サイドバーに一覧を表示して、選択したWhat's Newを右側に表示します。

選択したらこんな感じ

ソースコード全体
import json

import boto3
import requests
import streamlit as st
from bs4 import BeautifulSoup
from rss_parser import RSSParser

if "rss" not in st.session_state:
    rss_url = "https://aws.amazon.com/about-aws/whats-new/recent/feed/"
    response = requests.get(rss_url)

    st.session_state["rss"] = RSSParser.parse(response.text)

rss = st.session_state["rss"]
items = rss.channel.items


def f1(**kwargs):
    st.session_state["selection"] = kwargs


st.title("AWSのWhat's Newを解説くん")
st.write("←から選んでね")


with st.sidebar:

    for item in items:
        with st.container(border=True):
            st.write(item.title.content)

            kwargs = {
                "title": item.title.content,
                "pub_date": item.pub_date.content,
                "link": item.link.content,
            }

            st.button("おしえて", key=item.guid.content, on_click=f1, kwargs=kwargs)

prompt = """
AWSのWhat's newを提示しますので、注意深く読み込んでください。

<AWSのWhat's new>
{{What's new}}
</AWSのWhat's new>

タスク
 会話形式でわかりやすく解説してください。

登場人物
- user1: AWSスペシャリスト
- user2: 新入社員

ルール
- 回答は必ず日本語で行ってください。
- ハルシネーションは許されないので、What\'s newの内容からのみ回答を生成してください。
- また、回答付不要な出力は含めず、登場人物の会話のみを出力してください。
- 回答は以下のJSON形式としてください。

{
  "conversations": [
    {
      "actor": "user1",
      "message": "..."
    },
    {
      "actor": "user2",
      "message": "..."
    },
    {
      "actor": "user1",
      "message": "..."
    }
  ]
}
"""

if "selection" in st.session_state:
    kwargs = st.session_state["selection"]

    response = requests.get(kwargs["link"])
    soup = BeautifulSoup(response.text, features="html.parser")
    contents = soup.section.get_text()

    st.subheader(kwargs["title"])
    st.write(kwargs["pub_date"])

    with st.spinner("ちょっとまってね"):

        client = boto3.client("bedrock-runtime")

        model_id = "anthropic.claude-3-sonnet-20240229-v1:0"
        response = client.invoke_model(
            modelId=model_id,
            body=json.dumps(
                {
                    "anthropic_version": "bedrock-2023-05-31",
                    "max_tokens": 1024,
                    "messages": [
                        {
                            "role": "user",
                            "content": [
                                {
                                    "type": "text",
                                    "text": prompt.replace("{{What's new}}", contents),
                                }
                            ],
                        }
                    ],
                    "temperature": 0.5,
                }
            ),
        )

    try:
        response_body = json.loads(response.get("body").read())
        conversations = json.loads(response_body["content"][0]["text"])

        for c in conversations["conversations"]:
            if c["actor"] == "user1":
                with st.chat_message("ai"):
                    st.write(c["message"])

            if c["actor"] == "user2":
                with st.chat_message("human"):
                    st.write(c["message"])

    except Exception as e:
        st.write("ごめんなさい。エラーです。")
        with st.expander("Haikuの回答:"):
            st.write(response_body)

    st.link_button("ブログを確認", kwargs["link"])

デモ

(諸事情によりBedrockは使わず、AnthripicのAPIを使用しています)

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4