> ## Documentation Index
> Fetch the complete documentation index at: https://docs.supertoneapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# ボイス検索とプレビュー

> アプリ内ボイスピッカーを構築します — ライブラリを検索し、サンプル音声を表示し、ユーザーにボイスIDを選んでもらえるようにします。

<Note>
  このドキュメントは英語の原文から自動翻訳されています。表現に不自然な箇所がある場合があります。正確な内容は[英語の原文](/en/docs/examples/voice-search-and-preview)もあわせてご確認ください。
</Note>

ユーザーがボイスを選択できるプロダクトでは、検索可能なリストとオーディオプレビューを表示したくなるはずです。Supertone APIはこれを直接サポートしています。`search_voices`はフィルター条件に一致するボイスに加えて、ブラウザでそのまま再生できる事前生成済みのサンプルクリップを返します。

## Python — フィルター指定してサンプルを表示する

```python theme={"dark"}
import os
from supertone import Supertone

with Supertone(api_key=os.environ["SUPERTONE_API_KEY"]) as client:
    result = client.voices.search_voices(
        language="en,ko",
        style="happy,neutral",
        gender="female",
        age="young-adult",
        page_size=20,
    )

    for voice in result.items or []:
        sample = next(
            (s for s in (voice.samples or []) if s.language == "en"),
            None,
        )
        print(f"{voice.voice_id}\t{voice.name}\t{sample.url if sample else '(no en sample)'}")
```

## TypeScript — ピッカーを描画する

```typescript theme={"dark"}
import { Supertone } from "@supertone/supertone";

const client = new Supertone({ apiKey: process.env.SUPERTONE_API_KEY });

async function loadVoices() {
  return client.voices.searchVoices({
    language: "en,ko",
    style: "happy,neutral",
    gender: "female",
    age: "young-adult",
    pageSize: 20,
  });
}

const result = await loadVoices();

for (const voice of result.items ?? []) {
  const sample = voice.samples?.find((s) => s.language === "en");
  console.log(
    voice.voiceId,
    voice.name,
    sample?.url ?? "(no en sample)",
  );
}
```

## ブラウザでピッカーを描画する

WebのUIにボイスを表示する場合は、リストはバックエンド経由で取得してください（ブラウザから自分のキーで直接Supertone APIを呼び出してはいけません）。その上で、サンプルURLを`<audio>`要素として描画します。

```html theme={"dark"}
<!-- After your backend returns the search result as JSON -->
<ul id="voice-picker"></ul>

<script>
  async function renderVoices() {
    const res = await fetch("/api/voices?language=en&style=happy");
    const { items } = await res.json();
    const ul = document.getElementById("voice-picker");

    for (const voice of items) {
      const sample = voice.samples?.find((s) => s.language === "en");
      const li = document.createElement("li");
      li.innerHTML = `
        <button data-voice-id="${voice.voiceId}">${voice.name}</button>
        ${sample ? `<audio controls src="${sample.url}"></audio>` : ""}
      `;
      ul.appendChild(li);
    }
  }

  renderVoices();
</script>
```

ヒント: `samples`フィールドは`(language, style, model)`の組み合わせをキーとしています。実際にアプリで使う組み合わせに一致するサンプルを選ぶことで、プレビューと本番出力を一致させられます。

## ページネーション

`search_voices`は`page_size`件まで（デフォルト20、最大100）のボイスを返し、続きがある場合は`next_page_token`を一緒に返します。そのトークンを再度渡せば次のページを取得できます。

<Tabs>
  <Tab title="Python">
    ```python theme={"dark"}
    page = client.voices.search_voices(language="en", page_size=50)
    while True:
        for voice in page.items or []:
            handle(voice)
        if not page.next_page_token:
            break
        page = client.voices.search_voices(
            language="en",
            page_size=50,
            next_page_token=page.next_page_token,
        )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"dark"}
    let page = await client.voices.searchVoices({ language: "en", pageSize: 50 });
    while (true) {
      for (const voice of page.items ?? []) {
        handle(voice);
      }
      if (!page.nextPageToken) break;
      page = await client.voices.searchVoices({
        language: "en",
        pageSize: 50,
        nextPageToken: page.nextPageToken,
      });
    }
    ```
  </Tab>
</Tabs>

## ヒント

* **複数値はORで評価されます。** `language=ko,en`は**いずれか**をサポートするボイスを返します。複数のフィルターを組み合わせるとAND的に絞り込めます。
* **`sort`パラメータはありません。** 結果は自然な順序で返ります。独自の並び順が必要な場合はクライアント側でソートしてください。
* **レスポンスをキャッシュしましょう。** ボイスライブラリの内容は頻繁には変わりません。バックエンドでリストをキャッシュ（15〜60分程度が目安）すると、呼び出し回数を減らしつつピッカーのレイテンシも改善できます。

## 関連情報

<CardGroup cols={2}>
  <Card title="ボイス" icon="users" href="/ja/docs/core-concepts/voices">
    ボイスIDとボイスオブジェクトの概念的な解説です。
  </Card>

  <Card title="ボイス検索" icon="magnifying-glass" href="/ja/api-reference/endpoints/search-voices">
    フィルターパラメータの完全なリファレンスです。
  </Card>
</CardGroup>
