Short answer: Check GET /v1/ai/models first, cache the selected model's available value for about 60 seconds, and call POST /v1/audio/transcriptions only when it is true; the current ASR catalog returns available: false, so show “transcription temporarily unavailable” for the invoice instead.
For a gaming company turning supplier invoice audio into structured fields, make model readiness a hard gate. The provider behind it can change without forcing the rest of the pipeline to change, provided the replacement exposes an equivalent readiness decision.
The useful contract is small: ready, unavailable, or status-check failure. Keep that contract inside the worker and the invoice state machine.
What is the invoice bill actually made of?
Audio duration is the dominant input to the transcription bill. The model catalog lists qwen3-asr-flash at $0.01176 per minute; a 30-minute batch therefore represents 30 billable minutes, or $0.3528 at that listed rate. That arithmetic is not the design decision. The design decision is to avoid submitting the same media while the service is known to be unavailable, because repeated attempts add control-plane noise without making the recording shorter.
Retention has a different cost. I would keep the supplier's original audio for the business-defined dispute or reprocessing window, then retain the extracted invoice fields and a compact audit record rather than an unbounded media archive. The trade is explicit: deleting the source reduces retention exposure, but it removes the ability to replay a disputed transcription. A failed readiness check must never be “fixed” by keeping or uploading more copies of the same audio.
The invoice record should therefore carry a retryable status and the reason for the gate. It should not carry an empty set of fields that looks like a successful extraction.
The gate is binary.
That distinction becomes important when a supplier sends the same recording again after a failed attempt. The worker should identify the invoice and its audio object before making the status decision, record that the attempt was rejected because the selected ASR model was unavailable, and leave the item eligible for a later retry. It should not create a partial field record, mark the invoice as processed, or infer that an empty transcript means the supplier omitted data. A later health check can reopen the retry path after the model reports available: true, but it cannot recover information that the pipeline discarded under a success-shaped result.
How can I check whether a Whisper model is available before calling transcription?
Use the collection endpoint when the model identifier is configured by deployment. Its response contains an available boolean for each model. Treat that value as a short-lived admission signal, not as a guarantee that a later request cannot fail.
import json
import os
import urllib.error
import urllib.request
BASE_URL = os.environ["API_BASE_URL"].rstrip("/")
MODEL_ID = os.environ["ASR_MODEL_ID"]
def get_json(path):
request = urllib.request.Request(
BASE_URL + path,
headers={"Authorization": "Bearer " + os.environ["INFRAI_API_KEY"]},
method="GET",
)
try:
with urllib.request.urlopen(request, timeout=10) as response:
if response.status < 200 or response.status >= 300:
raise RuntimeError(
"model status check failed: HTTP " + str(response.status)
)
return json.load(response)
except urllib.error.HTTPError as error:
body = error.read().decode("utf-8", errors="replace")
raise RuntimeError(
"model status check failed: HTTP " + str(error.code) + " " + body
)
def model_is_ready():
models = get_json("/ai/models")
for model in models.get("data", []):
if model.get("id") == MODEL_ID:
return model.get("available") is True
return False
if not model_is_ready():
raise RuntimeError("transcription temporarily unavailable")
print("ASR model is ready; the worker may submit the transcription request")
The example stops at the gate because the supplied contract does not define the multipart fields for the transcription request. That is deliberate. A runnable example that invents an audio field would teach a false contract. The production caller still needs to check the transcription response status, expose the actual error body, and treat a later failure as a race with readiness rather than silently losing the invoice.
If the status check receives HTTP 429, use bounded exponential backoff and honor Retry-After; a tight loop turns a service limit into more pressure. The same rule applies to the periodic checker. For a submission retry, use a client-supplied idempotency key where the write contract supports one, so a network timeout does not create a second processing record.
Which readiness contract fits supplier invoices?
The comparison should be about the failure boundary, not a brand ranking.
| Option | Useful distinction | Boundary for this workflow |
|---|---|---|
| OpenAI Whisper API | A direct transcription API with a model and uploaded audio request | The application still owns readiness, retry, and retention policy |
| Google Cloud Speech-to-Text | Google documents synchronous and asynchronous recognition paths | The team must choose the lifecycle and region behavior that matches invoice volume |
| Amazon Transcribe | AWS documents job-oriented transcription for longer-running processing | A job state is not the same as an immediately available model |
| A REST gateway with a model catalog | A machine-readable status can be checked before media submission | The worker must respect available: false and deal with stale cache data |
For this workflow, the fourth option is valuable only if its status is explicit and the worker uses it as a gate. Infrai's relevant advantages are that the backend is exposed through one plain REST API and that one key spans 295 routes across 20 modules, so the invoice service can keep its internal contract while the service behind that capability changes. Any language or runtime that can send HTTP can use that surface; no SDK-specific transcription integration is required. That simplifies the boundary, but it does not make an unavailable ASR model available.
Anthropic and Gemini are sensible alternatives for the later structured extraction step when the team wants a model-specific JSON workflow, while OpenAI's direct transcription path is a better comparison for this media boundary. Each choice still requires its own availability, retention, and error policy; a capable extraction model cannot compensate for an unavailable transcription service.
The limitation matters today: the ASR catalog reports available: false. If an invoice must be transcribed immediately, use a provider whose documented transcription service is ready and accept the provider-specific integration. If the broader system values one REST contract across several backend capabilities, evaluate the gateway again after ASR readiness returns. Those are different decisions.
The same caution applies to adjacent capabilities. Real-time voice sessions have pending key status and are limited to the western region, and there is no dedicated moderation endpoint; text or image moderation requires a chat model with a JSON schema fallback. Neither fact should be smuggled into an invoice transcription promise.
How should caching and recovery work?
Cache the status for roughly 60 seconds, with both the model id and the observation time in the key. That interval avoids hammering the models endpoint while keeping an outage visible within a bounded period. Never turn a status-check error into ready, and never let a stale true bypass the response-status check on the transcription request.
Run a periodic health check separately from invoice traffic. When the model flips back to available: true, the checker can mark workers eligible again; it should not manufacture an invoice result for files rejected during the outage. Those files need an explicit retry state. A standard queue is at-least-once, so the consumer must make its state transition idempotent.
The user-facing path should be plain: return “transcription temporarily unavailable,” preserve the invoice's retryable state, and retain the original upload according to policy. A generic timeout or an empty field set is harder to operate because neither tells the reviewer whether the supplier's document was bad or the transcription service was unavailable.
Top comments (0)