タイトル画像
琴葉茜

次は、もっと図鑑らしくするために画像と鳴き声を追加しようか

琴葉葵

Streamlitで画像とか音を扱う場合も「st.write()」みたいな感じで出来るの?

琴葉茜

そうだね、画像を表示する場合は「st.image()」、音の再生は「st.audio()」を使うよ
引数には対象になる画像や音のファイルが置いてある場所を設定すればOK!

琴葉葵

画像や音が置いている場所...でも、今回は画像とか用意してなくない??

琴葉茜

そうだね、だけど「PokeAPI」で取得したJSONには画像や鳴き声のデータを返してくれるURLがあるから、それを利用するよ!

琴葉葵

おお!そうなんだ!!

琴葉茜

画像のURLは「sprites」、鳴き声のURLは「cries」がキーになってるよ!
画像については公式の画像だけじゃなくて、ゲーム内で使われている正面や色違いのドット絵とか沢山種類があるんだよね

琴葉葵

じゃあ、画像は何パターンか表示されるようにしたいね!

琴葉茜

OK!!じゃあ正面・背面・公式アートの3種類の画像の表示と、鳴き声を再生する仕組みを追加しよう!

琴葉茜

鳴き声については、たまに用意されてない時もあるからエラーが出ないように「.get()」を使ってるよ

# 「種族値」を表示する部分の下に配置しよう

# 画像の表示(通常・色違い・公式アート)
st.subheader("画像")
st.image(data["sprites"]["front_default"], caption="通常", width=200)
st.image(data["sprites"]["front_shiny"], caption="色違い", width=200)
st.image(data["sprites"]["other"]["official-artwork"]["front_default"], caption="公式アート", width=200)

# 鳴き声の再生
cry_url = data.get("cries", {}).get("latest")
if cry_url:
    st.subheader("鳴き声")
    st.audio(cry_url)
else:
    st.info("このポケモンには鳴き声が登録されていません。")
解説画像1

※サイト内でのポケモンの画像は著作権に影響が出ないようにモザイクにしています

琴葉葵

おおー!ちゃんと表示できてるし、音を鳴らすための機能が増えてる!!

琴葉茜

だけど今回みたいに画像や音を使う場合、「著作権」にはくれぐれも注意してね

琴葉茜

ポケモンの場合は「任天堂」「株式会社クリーチャーズ」「株式会社ゲームフリーク」が著作権を保有してるから、著作権について知るためにも下のリンク先確認してみると良いよ!
ネットワークサービスにおける任天堂の著作物の利用に関するガイドライン
株式会社クリーチャーズのサイトポリシー
株式会社ゲームフリークのサイトポリシー
ご利用について|ポケットモンスターオフィシャルサイト

琴葉葵

見るところが多いし、なんか判断が難しいね...汗
当たり前のようにSNSとかのアイコンでキャラクターの画像を使ってるけど、著作権って難しいし気をつけないとダメなんだね

琴葉茜

基本的に個人の学習目的で留める分には著作権の侵害とみなされにくいことが多いけど、はっきりと「使っても良いですよ」とは書かれてないから頭に入れといてね
くれぐれも、営利目的・商用利用はダメだからね!!

琴葉葵

気をつけます...!!

琴葉葵

ところで、画像を追加したらページ内をスクロールしないといけなくなって見づらくなっちゃったね

琴葉茜

確かにそうだね
じゃあ次の項目でUIデザインの整理をしていこうか!

この時点での全体のプログラム

import streamlit as st
import json
import requests

# タイプと能力値の日本語辞書
TYPES = {
    "normal": "ノーマル", "fire": "ほのお", "water": "みず", "electric": "でんき",
    "grass": "くさ", "ice": "こおり", "fighting": "かくとう", "poison": "どく",
    "ground": "じめん", "flying": "ひこう", "psychic": "エスパー", "bug": "むし",
    "rock": "いわ", "ghost": "ゴースト", "dragon": "ドラゴン", "dark": "あく",
    "steel": "はがね", "fairy": "フェアリー"
}

STATS = {
    "hp": "HP", "attack": "こうげき", "defense": "ぼうぎょ",
    "special-attack": "とくこう", "special-defense": "とくぼう",
    "speed": "すばやさ"
}

# JSONファイルを読み込み(日本語名 → ID)
with open("poke_dict.json", "r", encoding="utf-8") as f:
    NAME_TO_ID = json.load(f)

# ID → 日本語名 の逆引き辞書も作成
ID_TO_NAME = {str(v): k for k, v in NAME_TO_ID.items()}

# タイトル・説明
st.title("ポケモン図鑑")
st.caption("このサイトはポケモン非公式ファン作品です。画像・音声は株式会社ポケモンおよび関連各社の著作物に基づいています。学習目的のみに使用し、無断転載・商用利用・再配布は禁止されています。")

# 入力とボタン
user_input = st.text_input("ポケモンの名前またはIDを入力してください")
search_btn = st.button("検索")

# 検索処理
if search_btn:
    poke_id = None
    poke_name = None

    if user_input in NAME_TO_ID:
        poke_id = NAME_TO_ID[user_input]
        poke_name = user_input
    elif user_input in ID_TO_NAME:
        poke_id = int(user_input)
        poke_name = ID_TO_NAME[user_input]

    if poke_id is not None:
        api_url = f"https://pokeapi.co/api/v2/pokemon/{poke_id}"
        res = requests.get(api_url)
        
        if res.status_code == 200:
            data = res.json()
            height = data["height"] / 10
            weight = data["weight"] / 10

            # タイプを日本語に変換
            types = [TYPES[t["type"]["name"]] for t in data["types"]]

            # 種族値を日本語に変換
            stats = {STATS[s["stat"]["name"]]: s["base_stat"] for s in data["stats"]}


            st.header(f"{poke_name}")
            st.write(f"ID: {poke_id}")
            st.write(f"タイプ: {', '.join(types)}")
            st.write(f"たかさ: {height} m")
            st.write(f"おもさ: {weight} kg")
            st.subheader("種族値")
            for stat_name, stat_val in stats.items():
                st.write(f"- {stat_name}: {stat_val}")

            # 画像の表示(通常・色違い・公式アート)
            st.subheader("画像")
            st.image(data["sprites"]["front_default"], caption="通常", width=200)
            st.image(data["sprites"]["front_shiny"], caption="色違い", width=200)
            st.image(data["sprites"]["other"]["official-artwork"]["front_default"], caption="公式アート", width=200)

            # 鳴き声の再生
            cry_url = data.get("cries", {}).get("latest")
            if cry_url:
                st.subheader("鳴き声")
                st.audio(cry_url)
            else:
                st.info("このポケモンには鳴き声が登録されていません。")
    else:
        st.error("その名前やIDのポケモンは見つかりませんでした。")