0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Python] Streamlit入門から上級まで:爆速でWebアプリを作る方法

0
Posted at

こんにちは!

先日、Streamlit を使ってみたので備忘録です。
最後は、実際にローカルLLM(Ollama)と会話できるチャットUIまで作ります。

元ネタはこちら:Streamlit 公式ドキュメント

Streamlitとは

Streamlitは、データサイエンスや機械学習、生成AIなどのスクリプトを数分でインタラクティブなWebアプリに変換できるオープンソースのPythonライブラリです。HTMLやCSS、JavaScriptを書く必要がありません。

フロントエンドの知識がなくても、PythonコードだけでUIが完結するのが最大のメリットです。

主な使用目的

  • 分析データやグラフの可視化ダッシュボードを素早く作りたい場合
  • ローカルで動かす生成AIやLLMのプロトタイプUIを構築したい場合
  • 社内向けの簡単なツールや管理画面を爆速でデプロイしたい場合

基本的なメソッド(ウィジェット)

ウィジェット メソッド 説明
テキスト・Markdown st.write() / st.markdown() テキストやマークダウンを出力
データフレーム表示 st.dataframe() 表データをインタラクティブに表示
テキスト入力 st.text_input() ユーザーからの文字列入力を受け付ける
ボタン st.button() クリックされたらTrueを返す
チャット入力 st.chat_input() チャット形式の入力欄を表示
ストリーミング表示 st.write_stream() ジェネレータの出力を逐次描画

環境構築

今回の検証環境は以下のとおりです。(やや古めのPC)

項目 バージョン
macOS 26.6 (Tahoe)
CPU Intel Core i5-1038NG7(x86_64)
Python 3.12.8
Streamlit 1.61.1
Ollama 0.32.6

1. 作業ディレクトリと仮想環境の作成

プロジェクトごとに仮想環境を切っておくと、後片付けが楽になります。

mkdir my_work
cd my_work
python -m venv .venv
source .venv/bin/activate

Windows の場合、仮想環境の有効化は .venv\Scripts\activate です。

2. ライブラリのインストール

Streamlit本体に加えて、データ表示用の pandas と、後述のOllama連携で使う requests を入れておきます。

pip install streamlit pandas requests

インストールできたか確認します。

streamlit version

3. ローカルLLM(Ollama)の準備

上級編で使うローカルLLMを用意します。Ollama公式サイトからインストーラを入手するか、Homebrewで導入します。

brew install ollama

インストール後、モデルを取得します。今回は軽量な gemma4:e2b-it-qat(約4GB)を使いました。

ollama pull gemma4:e2b-it-qat

サーバーを起動します。アプリ本体とは別のターミナルで実行し、起動したままにしておいてください。

ollama serve

Ollamaは既にバックグラウンドで常駐している場合があります。その場合 ollama serveaddress already in use で失敗しますが、問題ありません。次のコマンドでモデル一覧が返ってくれば準備完了です。

curl http://localhost:11434/api/tags
Ollamaが動いているかの確認方法

以下のコマンドで、取得済みのモデルが一覧表示されれば正常です。

ollama list
NAME                    ID              SIZE      MODIFIED
gemma4:e2b-it-qat       07ea59a47401    4.3 GB    7 weeks ago
qwen2.5-coder:latest    dae161e27b0e    4.7 GB    2 months ago

基本編:テキストとデータの表示

まずは基本的な表示から試してみます。

app.py
import streamlit as st
import pandas as pd

st.title("Streamlitの基本テスト")
st.write("これは最初のStreamlitアプリです。")

# データフレームの表示
df = pd.DataFrame({
    "名前": ["Alice", "Bob", "Charlie"],
    "年齢": [25, 30, 35]
})

st.dataframe(df)
実行方法と結果

ターミナルで以下のコマンドを実行します。

streamlit run app.py

ブラウザが自動的に立ち上がり、http://localhost:8501 にアクセスされます。タイトルとテーブルが表示されていれば成功です。

スクリーンショット 2026-08-06 22.01.39.png

応用編:インタラクティブなウィジェットと状態管理

次に、よく使うウィジェット(入力フォームなど)を組み合わせてみます。ボタンを押すと状態が更新される仕組みを作ります。

app2.py
import streamlit as st

st.header("応用編:カウンターアプリ")

# セッションステート(状態管理)の初期化
if "count" not in st.session_state:
    st.session_state.count = 0

# ボタンの配置
if st.button("カウントアップ"):
    st.session_state.count += 1

st.write(f"現在のカウント: {st.session_state.count}")
実行方法と結果
streamlit run app2.py

ボタンを押すたびにカウントが増えていきます。

スクリーンショット 2026-08-06 22.05.38.png

Streamlitはユーザーが操作するたびにスクリプト全体を上から下へ再実行します。変数の状態を保持したい場合は、必ず st.session_state を使用してください。

上級編:ローカルLLM連携のチャットUI構築

最後に、チャットUIコンポーネントを使って、実際にローカルLLMと会話できるアプリを作ります。
Ollamaが提供するREST APIを requests で叩き、返ってきたトークンを st.write_stream() で逐次描画します。

Ollama APIの使い方

Ollamaは http://localhost:11434 でREST APIを公開しています。今回使うのは2つだけです。

エンドポイント 用途
GET /api/tags インストール済みモデルの一覧を取得
POST /api/chat チャット形式で応答を生成

/api/chat"stream": true を渡すと、レスポンスが 1行1JSON(NDJSON) で少しずつ返ってきます。この各行から message.content を取り出して繋げていけば、タイピング風のストリーミング表示になります。

実装

app3.py
import json

import requests
import streamlit as st

OLLAMA_URL = "http://localhost:11434"

st.header("上級編:ローカルLLMチャットUI")


@st.cache_data(ttl=60, show_spinner=False)
def list_models() -> list[str]:
    """Ollama にインストール済みのモデル名を取得する。"""
    res = requests.get(f"{OLLAMA_URL}/api/tags", timeout=5)
    res.raise_for_status()
    return [m["model"] for m in res.json().get("models", [])]


def stream_chat(model: str, messages: list[dict]):
    """Ollama の /api/chat を stream=True で叩き、生成トークンを逐次 yield する。"""
    with requests.post(
        f"{OLLAMA_URL}/api/chat",
        json={"model": model, "messages": messages, "stream": True},
        stream=True,
        timeout=300,
    ) as res:
        res.raise_for_status()
        for line in res.iter_lines(decode_unicode=True):
            if not line:
                continue
            chunk = json.loads(line)
            if chunk.get("done"):
                break
            yield chunk.get("message", {}).get("content", "")


# 利用可能なモデルの取得(Ollama が起動していない場合はここで気付ける)
try:
    models = list_models()
except requests.RequestException as e:
    st.error(f"Ollama に接続できません({OLLAMA_URL})。`ollama serve` を確認してください。\n\n{e}")
    st.stop()

if not models:
    st.warning("モデルがありません。`ollama pull gemma4:e2b-it-qat` などで取得してください。")
    st.stop()

model = st.selectbox("モデル", models)

# チャット履歴の初期化
if "messages" not in st.session_state:
    st.session_state.messages = []

# 過去のメッセージを表示
for msg in st.session_state.messages:
    with st.chat_message(msg["role"]):
        st.markdown(msg["content"])

# ユーザーの入力
if prompt := st.chat_input("メッセージを入力してください...", submit_mode="disable"):
    # ユーザーメッセージを表示・保存
    st.session_state.messages.append({"role": "user", "content": prompt})
    with st.chat_message("user"):
        st.markdown(prompt)

    # ローカルLLMの応答をストリーミング表示
    with st.chat_message("assistant"):
        try:
            answer = st.write_stream(stream_chat(model, st.session_state.messages))
        except requests.RequestException as e:
            st.error(f"生成に失敗しました: {e}")
            st.stop()

    # アシスタントメッセージを保存
    st.session_state.messages.append({"role": "assistant", "content": answer})

実装のポイント

  • 会話履歴をそのまま渡す
    st.session_state.messages{"role": ..., "content": ...} の配列で、Ollamaの messages パラメータの形式と同じです。そのまま渡すだけで、文脈を踏まえた会話になります。
  • st.write_stream() にジェネレータを渡す
    自前で st.empty() とループを書かなくても、文字列を yield するジェネレータを渡すだけでタイピング風の表示になります。戻り値には連結済みの全文が入るので、そのまま履歴に保存できます。
  • @st.cache_data(ttl=60) でモデル一覧をキャッシュ
    Streamlitは操作のたびに全体を再実行するため、キャッシュがないと毎回APIを叩いてしまいます。
  • submit_mode="disable"
    生成中は入力欄を無効化し、応答の途中で次のメッセージが割り込むのを防ぎます。
  • 接続エラーを握りつぶさない
    Ollamaが起動していないケースが一番よくあるので、起動時に st.error() で明示的に知らせます。
実行方法と結果

Ollamaを起動した状態で、別のターミナルからアプリを実行します。

streamlit run app3.py

モデルを選んでメッセージを送ると、ローカルLLMからの応答が1文字ずつ流れてきます。

思考内容も出てますね。
スクリーンショット 2026-08-06 22.39.36.png

内容は置いといて、十分な回答を得られました!
スクリーンショット 2026-08-06 22.40.56.png

うまく動かないとき
症状 原因と対処
「Ollama に接続できません」と表示される Ollamaが起動していません。ollama serve を実行してください
「モデルがありません」と表示される ollama pull gemma4:e2b-it-qat でモデルを取得してください
応答が返るまで非常に遅い モデルの初回ロードに時間がかかります。2回目以降は高速になります
ModuleNotFoundError: requests 仮想環境を有効化した上で pip install requests を実行してください
応用のヒント

OLLAMA_URL を差し替えれば、vLLMやllama.cppのサーバーなど、OpenAI互換APIを持つ他のバックエンドにも同じ構成で接続できます。完全にオフラインで動作するセキュアなAIチャット環境をすぐに構築可能です!

まとめ

Streamlitを使うと、簡単なデータ表示から状態管理が必要なチャットUIまで、素早く綺麗に実装できます。
特にローカルLLMとの連携は st.chat_input()st.write_stream() の2つだけで完結するので、プロトタイピングには最適でした。
このツールを活用して、サクサク開発を行いましょう!

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?