📚

PostmanでAI Engine の音声文字起こしAPIのテスト / Postman Flowsを使わないAPIの連続実行

に公開

この記事では前回の記事に引き続き『さくらのAI Engine』をPostmanでテストしていきます。AI Engineには音声の文字起こしモデルも搭載されています。

curl --request POST \
  --url https://api.ai.sakura.ad.jp/v1/audio/transcriptions \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: multipart/form-data' \
  --form 'file=@sample.mp3' \
  --form 'model=whisper-large-v3-turbo'
{"text":"物差しって要は物の考え方というようなものですね物の考え方とか選び方とか感じ方とか内面にある精神活動みたいなものが相互に影響を与え合っているのですがやはり手っ取り早くということで外に起こることだけを変えようとする発想が多いので世の中にはどうしたら結婚できるんですかどうしたら彼氏ができるんですかなんて言えば好きになってもらえるんですかとか明日から何をしたらお金持ちになるんですかとかっていう考え方が多いので恋愛結婚の場合だとこの人は綺麗だから結婚できるとか若いからとかでなんか割とそれに疑わずにチューブラリンじゃなく疑わない価値観もあるんですけど本当にという目でじっと見てみるとものすごく不幸な綺麗な人とかもいっぱいいるし結婚してる人がみんなそんな素晴らしい人格のすごいいい女なんですか","model":"whisper-large-v3-turbo"}

https://knowledge.sakura.ad.jp/47088/
こちらの記事ではPythonのスクリプトの例を記載していますが、文字起こした内容をさらにChatAPIを使ってサマリーのリクエストを出すことで議事録作成の様に使うことができます。

Post-response と 外部API呼び出し

Postmanのコレクションは一つの設定が一つのAPIコールとなります。Flowsを使えば数珠繋ぎ形式でコレクションAの呼び出し結果(レスポンス)をコレクションBのリクエストにつなげて実行すことができます。

もう一つの手法としてよりシンプルにPost-responseを使うことで外部API呼び出しが可能です。

    pm.sendRequest({
        url: 'https://api.ai.sakura.ad.jp/v1/chat/completions',
        method: 'POST',
        header: {
            'Accept': 'application/json',
            'Authorization': 'Bearer cba157be-9c36-4bb3-a065-2695d4cf598c:8gUIE7u1m4DwgwVTyKDBlP9+duhAUZFo3D7AgSYf',
            'Content-Type': 'application/json'
        },
        body: {
            mode: 'raw',
            raw: JSON.stringify({
                model: 'gpt-oss-120b',
                messages: [
                    { role: 'user', content: "次の文をサマーりしてください"+textFromResponse }
                ],
                temperature: 0.7,
                max_tokens: 500,
                stream: false
            })
        }

これは以下のcurlコマンドと同等です。

curl --location 'https://api.ai.sakura.ad.jp/v1/chat/completions' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <TOKEN>' \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "gpt-oss-120b",
    "messages": [
      { "role": "system", "content": "次の文をサマリーしてください xxxxxx" }
    ],
    "temperature": 0.7,
    "max_tokens": 500,
    "stream": false
  }'

pm.sendRequestを使うことで外部API呼び出しを行ないその結果をコンソールに出力することができます。

さっそくやってみる

1. curlコマンドのインポート

以下の音声文字起こし用curlコマンドを前回の記事と同じ手順でインポートします。

curl --request POST \
  --url https://api.ai.sakura.ad.jp/v1/audio/transcriptions \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: multipart/form-data' \
  --form 'file=@sample.mp3' \
  --form 'model=whisper-large-v3-turbo'

2. ファイルのアップロード

Postman コレクションではファイルをアップロードすることでバイナリやform-data、x-www-form-urlencodedなどのデータを用いたテストが可能です。
https://zenn.dev/kameoncloud/articles/d4250a5513b9ed
https://zenn.dev/kameoncloud/articles/3a70b170e106c7
sample.mp3をアップロードして実行を行います。

{
    "text": "物差しって要は物の考え方というようなものですね物の考え方とか選び方とか感じ方とか内面にある精神活動みたいなものが相互に影響を与え合っているのですがやはり手っ取り早くということで外に起こることだけを変えようとする発想が多いので世の中にはどうしたら結婚できるんですかどうしたら彼氏ができるんですかなんて言えば好きになってもらえるんですかとか明日から何をしたらお金持ちになるんですかとかっていう考え方が多いので恋愛結婚の場合だとこの人は綺麗だから結婚できるとか若いからとかでなんか割とそれに疑わずにチューブラリンじゃなく疑わない価値観もあるんですけど本当にという目でじっと見てみるとものすごく不幸な綺麗な人とかもいっぱいいるし結婚してる人がみんなそんな素晴らしい人格のすごいいい女なんですか",
    "model": "whisper-large-v3-turbo"
}

3. Post-response の設定

以下のスクリプトを挿入して、再度コレクションを実行します。

// レスポンスから text を抽出
let response = pm.response.json();
let textFromResponse = response.text;

if (!textFromResponse) {
    console.warn("text フィールドがレスポンスに存在しません");
} else {
    // API呼び出し
    pm.sendRequest({
        url: 'https://api.ai.sakura.ad.jp/v1/chat/completions',
        method: 'POST',
        header: {
            'Accept': 'application/json',
            'Authorization': 'Bearer <TOEKN>',
            'Content-Type': 'application/json'
        },
        body: {
            mode: 'raw',
            raw: JSON.stringify({
                model: 'gpt-oss-120b',
                messages: [
                    { role: 'user', content: "次の文をサマーりしてください"+textFromResponse }
                ],
                temperature: 0.7,
                max_tokens: 200,
                stream: false
            })
        }
    }, function (err, res) {
        if (err) {
            console.error('API呼び出しエラー:', err);
            return;
        }

        let chatResponse = res.json();
        console.log('gpt-oss-120b 応答:', chatResponse);

        // 必要なら保存
        pm.environment.set("chat_response_content", JSON.stringify(chatResponse));
    });
}

4. コンソールの確認

コンソールを確認すると1回のコレクション実行で2回APIコールが行われていることがわかります。

1回目が音声の文字起こし、2回目が結果のサマリーです。
以下の様なレスポンスが戻っています。

{
  "id": "chatcmpl-365a3c5abe0e446ebbb3181bf4a62deb",
  "object": "chat.completion",
  "created": 1759322518,
  "model": "gpt-oss-120b",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "**要約**\n\n- 「物差し」は、ものごとの見方・選び方・感じ方といった内面的な精神活動のことを指す。\n- これらの精神活動は互いに影響し合っているが、実際には外部の出来事だけを変えようとする考え方が多い。\n- その結果、世間では「どうすれば結婚できるか」「彼氏ができるか」「好きになってもらえるか」「すぐにお金持ちになるには何をすればいいか」など、外的条件に焦点を当てた質問や解決策が溢れている。\n- 恋愛・結婚に関しては「綺麗だから」「若いから」など見た目や年齢だけで結婚できると考える価値観が根強いが、実際には外見だけで判断できないケースが多い。\n- 見かけは良くても不幸な人や、結婚している人すべてが理想的な人格を持っているわけではないという現実がある。",
        "refusal": null,
        "annotations": null,
        "audio": null,
        "function_call": null,
        "tool_calls": [],
        "reasoning_content": "The user wrote in Japanese: \"次の文をサマーりしてください...\" They want a summary of the provided text. The text is somewhat incoherent, but they want a summary. We should comply, summarizing the main points. Ensure we obey policy. It's fine. Provide a concise summary in Japanese."
      },
      "logprobs": null,
      "finish_reason": "stop",
      "stop_reason": null,
      "token_ids": null
    }
  ],
  "service_tier": null,
  "system_fingerprint": null,
  "usage": {
    "prompt_tokens": 330,
    "total_tokens": 657,
    "completion_tokens": 327,
    "prompt_tokens_details": null
  },
  "prompt_logprobs": null,
  "prompt_token_ids": null,
  "kv_transfer_params": null
}

スクリプトの以下の部分が1回目のAPIコールの結果を受け取り、それを2回目のリクエストに挿入しています。

let textFromResponse = response.text;
<snip>
                    { role: 'user', content: "次の文をサマーりしてください"+textFromResponse }
さくらインターネット株式会社

Discussion