nikkie-ftnextの日記

イベントレポートや読書メモを発信

HTTPXのリクエストをRESPXでモックするのを試す(Groqへのリクエストを例に)

はじめに

ふててぺっくす!れすぺっくす!! nikkieです。

イデアを試してみたブログです(プラクティスと言えるかはまだ怪しいです)

目次

登場人物

HTTPX

HTTPクライアントライブラリです。
PythonのHTTPクライアントはrequestsが有名ですが、私の推しはHTTPXです。
requestsと同じインターフェースなので乗り換えやすく、async/awaitの世界へ踏み出せます💪

LLM APIのクライアントライブラリ(例:openaiライブラリやgroqライブラリ)は、async/awaitサポートのためにHTTPXを依存先に選んでいるように見受けられます。

RESPX

requestsがresponsesでモックできるように1、HTTPXはRESPXでモックできるということを最近知りました2

Mock HTTPX with awesome request patterns and response side effects.

今回素振りします。

GroqのWhisper APIへのリクエストをRESPXでモックする

groqは中でHTTPXを使っているので、RESPXでモックしてみます。

動作環境

  • Python 3.12.6
  • pytest 8.3.4
  • RESPX 0.21.1
  • HTTPX 0.27.2
    • 直近出た 0.28.0 はRESPXがうまく動きませんでした
% say 親譲りの無鉄砲で子供の時から損ばかり -o sample.wav --data-format=LEF32@16000
.
├── .venv/
├── sample.wav
├── transcribe.py
└── test_transcribe.py

現段階の設定の伸びしろとして、テストを通すには環境変数GROQ_API_KEYの指定が必要です(export GROQ_API_KEY=dummyでよい)

Groqで書き起こしスクリプトtranscribe.py

from groq import Groq


def transcribe(filename: str) -> str:
    client = Groq()
    with open(filename, "rb") as f:
        transcription = client.audio.transcriptions.create(
            file=(filename, f.read()),
            model="whisper-large-v3-turbo",
        )
    return transcription.text


if __name__ == "__main__":
    print(transcribe("sample.wav"))

関連エントリ

RESPXでモックしたテストコード(test_transcribe.py

RESPXのドキュメントで以下を参考にしました。

レスポンスはGroqのドキュメントから拝借。
https://console.groq.com/docs/speech-text

PCのWi-Fiを切ってネットワークアクセスできない状態でも(モックしていて通信が発生しないので)テストは通りました

宿題事項

  • RESPXでのモックをよりきめ細かくできるかな?
    • ヘッダやJSON形式のデータもモックに指定できるか確認したい(WireMockっぽく3なるかも)
    • 例えば、whisper-large-v3-turboというモデルの指定
  • 環境構築をより簡単にしたい
    • 環境変数GROQ_API_KEY -> 試したい案 monkeypatch.setenv()
    • sample.wavを不要にできる?4

終わりに

groqを例に、HTTPXをRESPXでモックしてみました。
RESPXはなかなか簡単に使い出せるなという感想です。
ただし、まだ確認したいところは多くあります。
LLM APIのクライアントライブラリのテストにRESPXが使えるか、引き続き試してみたいと思っています。

ちなみに、テストがあるので、openaiライブラリを使った書き換えが自信を持ってできます!(export OPENAI_API_KEY=dummy

-from groq import Groq
+from openai import OpenAI


def transcribe(filename: str) -> str:
-     client = Groq()
+     client = OpenAI(base_url="https://api.groq.com/openai/v1")

  1. requestsを使っている場合のみ利用できます。
  2. https://www.python-httpx.org/compatibility/#mocking で知りました
  3. ヘッダやリクエストボディを見てモックできます
  4. mock_openを試していたが実データが必要と判断