サーバーレス

Streamlitを使ってWebページ要約アプリを作ってみた

choco80

こんにちは、ちょこはまです。

今回は、最近読んだ書籍で扱われていたStreamlitというサービスを使ってWebページの内容を要約するアプリを作ってみたいと思います。

はじめに

サンプルアプリの概要

サンプルアプリは、要約対象WebページのURLを入力として受け取り、ChatGPTを使用して300字程度のWebページの要約を出力します。
ソースはGitHubリポジトリで管理し、Streamlit Community Cloudというサービスを使ってデプロイします。
※AIサービスはClaudeやGeminiなど、APIキーを取得できる任意のサービスを利用可能です。今回はサンプルとしてChatGPTを利用します。

Streamlitとは

Streamlitは、Pythonでデータアプリケーションを簡単に作成できるオープンソースのフレームワークです。
特徴は以下の通りです。

  • シンプルなコード構造: Pythonスクリプト内に直接UIを記述可能です。
  • リアルタイム更新: 変更が即座に反映され、開発がスムーズです。
  • デプロイの容易さ: Streamlit Cloudなどで簡単にアプリを公開可能です。
  • データサイエンスに最適: データフレームやモデルの可視化が得意です。

できることの参考:公式サイトのギャラリー

本記事の前提

  • GitHubのアカウントを作成済み
  • streamlitのアカウントを作成済み
  • OpenAI APIキーを取得済み

リポジトリの作成

GitHub上で「streamlit-app」という名前のリポジトリを作成します。
最終的なリポジトリ構成と各ファイルの用途は以下の通りです。

streamlit-app/
├── requirements.txt # アプリを実行するために必要なPythonパッケージを指定する
└── streamlit_app.py # メインスクリプト

今回はStreamlitを動かしてみることを目標に最小限の構成にしています。
公式ブログ(英語)ではテンプレートリポジトリおよび各ファイルの用途が紹介されています。興味がある方は覗いてみて下さい。

アプリの実装

実装

各ファイルを以下の通り実装し、プッシュします。

requirements.txt

streamlit
openai==0.28.0
beautifulsoup4
requests

streamlit_app.py

import streamlit as st
import openai
import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse

# OpenAI APIキーの設定
openai.api_key = st.secrets["openai_api_key"]

def initialize_app():
    st.set_page_config(
        page_title="Web Content Summarizer",
        page_icon="📝"
    )
    st.title("Web Content Summarizer 📝")

def is_valid_url(url):
    """URLの形式を検証"""
    try:
        result = urlparse(url)
        return all([result.scheme, result.netloc])
    except ValueError:
        return False

def fetch_website_content(url):
    """Webサイトの内容を取得"""
    try:
        response = requests.get(url)
        response.raise_for_status()
        soup = BeautifulSoup(response.text, 'html.parser')
        content = soup.find('main') or soup.find('article') or soup.find('body')
        return content.get_text(separator="\n").strip() if content else None
    except requests.exceptions.RequestException as e:
        st.error(f"Error fetching the website: {e}")
        return None

def summarize_content(content, model="gpt-4o", max_tokens=500):
    """ChatGPTを使用してコンテンツを要約"""
    try:
        system_prompt = """
        あなたは、ユーザーのリクエストに基づいてインターネット上で情報を検索するアシスタントです。
        利用可能なツールを活用し、得られた情報を説明してください。
        すでに知っていることだけで回答せず、可能な限り検索を行ってから答えてください。
        (ユーザーが特定のページを指定した場合など、特別な状況では検索は不要です。)

        検索結果だけでは十分な情報が得られないと感じた場合は、以下の方法を試みてください。

        - 検索結果のリンクをクリックし、各ページの内容を確認してください。
        - 1ページが非常に長い場合、メモリの負荷を避けるため、ページ送りは3回までに制限してください。
        - 検索クエリを修正して、新しい検索を実行してください。
        - 検索する内容に応じて、適切な言語で検索を行ってください。

        ユーザーが使用している言語で回答してください。
        ユーザーが日本語で質問した場合は日本語で、英語で質問した場合は英語で回答してください。
        """

        response = openai.ChatCompletion.create(
            model=model,
            messages=[
                {"role": "system", "content": system_prompt},
                {"role": "user", "content": f"以下の内容を日本語で300字程度にまとめてください。:\n\n{content}"}
            ],
            max_tokens=max_tokens
        )
        return response['choices'][0]['message']['content'].strip()
    except openai.OpenAIError as e:  
        st.error(f"Error generating summary: {e}")
        return None

def main():
    initialize_app()

    url = st.text_input("Enter URL:")

    if url:
        if not is_valid_url(url):
            st.warning("Please enter a valid URL.")
        else:
            content = fetch_website_content(url)
            if content:
                st.subheader("Summary")
                summary = summarize_content(content)
                if summary:
                    st.write(summary)

if __name__ == "__main__":
    main()

説明

主要な関数や変数について簡単に説明します。

openai.api_key = st.secrets["openai_api_key"]

後ほどStreamlitのサイト上で設定したOpenAI APIキーを取得します。
ローカルで実装する場合はsecrets.tomlを作成してAPIキー指定できます。

initialize_app():

Streamlitアプリケーションの初期設定を行い、ページタイトルとアイコンを設定します。アプリのタイトルも表示します。

is_valid_url(url):

入力されたURLの形式が有効かどうかを検証します。

fetch_website_content(url):

指定されたURLからウェブページの内容を取得します。main, article, bodyタグ内のテキストを優先的に取得し、それが
ない場合はエラーを表示します。

summarize_content(content, model="gpt-4o", max_tokens=500):

OpenAIのChatGPTを使用して、取得したウェブページの内容を要約します。
model="gpt-4o"を指定しておりますが、サービス課金していない場合は"gpt-3.5-turbo"を指定してください。

アプリのデプロイ

  1. streamlitのサイトに移動し、画面左上の[Sigin in]を押下する。

  2. 画面左上の[Create app]を押下する。

  3. [Yup, I have an app]を押下する。

  4. GitHubリポジトリ、ブランチ、メインファイルを指定して[Deploy!]を押下する。

    ※画像内の情報はサンプルです。

  5. 発行されたURLからアプリにアクセスする。

動作確認

以下のようにアプリが表示できました。
DWSのWebページを要約してみました。

今後やりたいこと

複数のAIサービス(ClaudeやGeminiなど)を切り替えて要約できるようにしたいです。
また、公式サイトのギャラリーを参考に何かしらデータを可視化するアプリを作ってみたいです。

参考

ブログ記事:LangChain tutorial #3: Build a Text Summarization app(英語)
ブログ記事:はじめてのAIアプリを作ろう - WEBサイト要約
書籍:つくりながら学ぶ!生成AIアプリ&エージェント開発入門

AUTHOR
choco80
choco80
記事URLをコピーしました