タイトル画像
琴葉葵

前回でだいたい動くようになって使ってみたけど、ページを更新すると今までの技の情報が消えちゃうのってちょっともったいないよね

琴葉茜

確かにそうだね
じゃあ今回はページを更新しても技の履歴が残るようにしてみようか

琴葉葵

おおー!そんな事ができるんだね!!

琴葉茜

ブラウザには「ローカルストレージ」っていう情報を保存する機能があるんよ

琴葉葵

ほうほう
そういえば、たまにサイトによっては入力情報が残ってることがあるよね

琴葉茜

そうそう
まぁ入力情報を保持する機能は「ローカルストレージ」以外にもあるんだけどね

琴葉葵

じゃあ早速お願いします!

琴葉茜

まずはstreamlitでローカルストレージを扱えるライブラリ「streamlit_javascript」をインストールしよう

pip install streamlit-javascript
琴葉茜

インストールが終わったら「streamlit_javascript」をインポートして、まずはローカルストレージのデータを読み込む処理を追加しよう

history_json = st_javascript("localStorage.getItem('skill_history');")
琴葉葵

なんか、JavaScriptのプログラムを直接動かす感じになるんだね

琴葉茜

ちなみに、ローカルストレージは「JSON」形式になっていて、今回はキーを「skill_history」にしてるよ

琴葉茜

んで、次はその読み込んだデータを表示する方法だけど、これはサイドバーに表示するようにしようか

with st.sidebar:
    st.title("⚙️ 設定")
    api_key = st.text_input("Gemini API Keyを入力", type="password")

    # サイドバーに履歴を表示する
    st.markdown("---")
    st.subheader("📜 生成履歴")
    if history_json and history_json != "null":
        try:
            history_data = json.loads(history_json)
            # 新しい順に表示
            for h in reversed(history_data):
                st.markdown(f"**{h['name']}** ({h['element']})")
                st.caption(f"威力: {h['power']} / MP: {h['mp_cost']}")
        except Exception:
            st.caption("履歴の解析に失敗しました")
琴葉葵

おっけー!
まだローカルストレージに情報はないけど、とりあえず「生成履歴」って表示されたよ!

琴葉茜

じゃあ次は、技を生成したときにローカルストレージに保存するようにしよう

response = generate_response(skill_name, api_key)
    st.write(f"技名: {skill_name}")
    st.write(f"属性: {response['element']}")
    st.write(f"威力: {response['power']}")
    st.write(f"消費MP: {response['mp_cost']}")

    # ここから下を追加する
    current_history = []
    if history_json and history_json != "null":
        try:
            current_history = json.loads(history_json) # 読み込んだデータを変換
        except:
            current_history = []
    
    if len(current_history) >= 10: # 追加する前に10個以上だったら一番古いデータを消す
        current_history.pop(0)
    current_history.append(response) # 追加
    st_javascript(f"localStorage.setItem('skill_history', '{json.dumps(current_history)}');") # 保存
琴葉茜

この時、読み込んだデータの後ろに追加する形にしていて、データを保持しすぎないように10個以上になったら古いデータを消すようにしてるよ

解説画像1
琴葉葵

おおー!
技を生成した時点ではまだ何も増えてないけど、ページを再読み込みしたら表示された!

琴葉茜

ひとまずはこれで完成!!
他にも、キー名を変えることでAPIキーを保持出来るようにしたりできるから、色々と試してみてね!

琴葉葵

生成AIを使ったら、AIと会話してクリアを目指すゲームとか診断とかも作れそうだよね!

琴葉茜

上手く使いこなせば、まだまだ新しいゲームの形を生み出せるかもだから、いっぱいアイデアを形にしていこうね!

全体のプログラム

from google import genai
import json
import streamlit as st
from streamlit_javascript import st_javascript

# 技の名前を渡すと、AIがJSON形式で技の設定を返してくれる関数
def generate_response(skill_name, api_key):
    # AIの設定
    client = genai.Client(api_key=api_key)

    prompt = f"""
    RPGのゲームマスターとして、技名「{skill_name}」の設定を作ってください。
    以下のJSONフォーマットで出力してください。

    {{
    "name": "{skill_name}",
    "element": "属性(火、水、風、雷、光、闇から選択)",
    "power": "威力(10〜999の数値)",
    "mp_cost": "消費MP(5〜100の数値)"
    }}
    """

    response = client.models.generate_content(
        model='gemini-2.5-flash',
        contents=prompt,
        config={'response_mime_type': 'application/json'}
    )
    return json.loads(response.text)

# 1. 起動時にローカルストレージから履歴を読み込む
history_json = st_javascript("localStorage.getItem('skill_history');")

with st.sidebar:
    st.title("⚙️ 設定")
    api_key = st.text_input("Gemini API Keyを入力", type="password")

    # 2. サイドバーに履歴を表示する
    st.markdown("---")
    st.subheader("📜 生成履歴")
    if history_json and history_json != "null":
        try:
            history_data = json.loads(history_json)
            # 新しい順に表示
            for h in reversed(history_data):
                st.markdown(f"**{h['name']}** ({h['element']})")
                st.caption(f"威力: {h['power']} / MP: {h['mp_cost']}")
        except Exception:
            st.caption("履歴の解析に失敗しました")

# 画面のタイトル
st.title("AIで技の設定を作ろう")

# ユーザーが技名を入力する欄
skill_name = st.text_input("技の名前を入力してください")

# ボタンが押された時の処理
if st.button("技の設定を作る"):
    if not api_key:
        st.error("左のサイドバーにAPIキーを入力してください!")
    elif not skill_name:
        st.warning("技の名前を入力してください。")
    else:
        try:
            response = generate_response(skill_name, api_key)
            st.write(f"技名: {skill_name}")
            st.write(f"属性: {response['element']}")
            st.write(f"威力: {response['power']}")
            st.write(f"消費MP: {response['mp_cost']}")

            # 3. 生成した技を履歴に追加して保存する
            current_history = []
            if history_json and history_json != "null":
                try:
                    current_history = json.loads(history_json)
                except:
                    current_history = []
            
            if len(current_history) >= 10:
                current_history.pop(0)
            current_history.append(response)
            st_javascript(f"localStorage.setItem('skill_history', '{json.dumps(current_history)}');")

        except Exception as e:
            st.error(f"エラーが発生したよ。APIキーが正しいか確認してね!\n{e}")