Skip to main content
Measure how quickly you receive the first audio from Chariot using the Python latency tool. You can test HTTP streaming and WebSocket, compare fresh and reused connections, and save the results for inspection.

Get the latency tool

Read the source, install the dependencies, and run the same measurements from your laptop or application host.

Set up

You need Git, Python 3.10 or later, a Chariot API key, and a voice that supports your selected model.
1

Install the tool

Run these commands in a macOS or Linux shell. Keep your terminal in tools/latency for the commands below. If you already have the repository, update your checkout from main first.
2

Configure your key, voice, and model

Edit .env:
Create your API key in the Dashboard. Get a voice UUID from GET /v1/voices. Choose a voice whose models[].model includes chariot-multilingual-v1.The tool defaults to Chariot Multilingual v1 and sends model_type explicitly. You can override CHARIOT_MODEL with --model. See Models for compatible voices, input limits, and speaking rates.
3

Run the latency test

You receive per-request timings, connection measurements, and a TTFB summary with min, p50, p90, p99, and max. The JSON file preserves the individual measurements and configuration.
The default run makes 20 sequential synthesis requests. Normal API credits apply. There are no hidden warm-up requests or automatic retries.

Choose what to test

Both streaming endpoints are included by default: The tool sends the same complete text for every request. It measures latency rather than concurrency, throughput, real-time factor, or playback underruns.
--save-audio writes one WAV file per successful request after consuming the response. File writes do not enter the first-audio timing. Reusing an output path overwrites its previous results.

Fresh and reused connections

  • Fresh: each request opens a new connection. DNS caches and the model may already be warm.
  • Reused HTTP: the tool reads the complete response before sending the next request on the same HTTP/1.1 connection.
  • Reused WebSocket: the tool sends input.text followed by input.flush, reads through audio.done, and repeats on the same session. It sends input.done when finished.
With --runs 5, each reused group contains one request labeled first and four labeled reused. The summary keeps them separate. With --runs 1, you get no reused samples.

Read the results

The tool prints endpoint URLs before the trials. In the output, http means HTTP streaming. This illustrative excerpt shows the output format, not expected latency:
All timings are in milliseconds. TTFB stops on audio, not HTTP headers or a WebSocket audio.start event. Both transports return raw signed 16-bit mono PCM. The tool reads the sample rate from the response metadata. setup+TTFB excludes local work between connection setup and text submission. It does not measure playback startup, the time to receive all audio, or an entire voice conversation. For WebSocket, TTFB includes sending both input.text and input.flush; it does not simulate tokens arriving from an LLM.

Interpret connection timings

A first DNS lookup can take longer than later lookups. A cache miss is one possible cause, but the timer includes the whole local lookup call. You cannot attribute that delay to a particular DNS server from this measurement alone. TCP connect time and WebSocket ping RTT are different measurements. Neither isolates pure network transit, so the tool does not subtract either from TTFB to claim model inference latency. Reused requests refer to the original connection’s setup and network measurements. A WebSocket handshake can finish before application authentication and session initialization. First-request TTFB includes any remaining work. Reusing a WebSocket session therefore measures a different lifecycle from sending another HTTP request on a keep-alive connection.

Interpret percentiles and failures

Percentiles use the nearest-rank method over successful generations. The tool does not discard outliers. n counts successes; failed and skipped show the other outcomes.
Five requests per group provide a quick check. With fewer than 100 successful samples, p99 is the observed maximum. In the default run, both p90 and p99 equal the maximum for each group. Increase --runs when you need more samples, and report the sample count with your results.
If a reused connection or generation fails, the tool skips the rest of that group. It does not reconnect and label later requests as warm. A failure reported after the first audio still excludes that generation from the successful TTFB summary. HTTP raw PCM has no application-level completion marker, so a normally terminated response cannot independently prove that synthesis was complete. The process exits with a nonzero status if any generation fails or is skipped. A failed WebSocket ping is reported separately from synthesis failures. See Errors and status codes when troubleshooting API failures.

Configuration reference

The tool reads CHARIOT_API_KEY from .env or your environment and authenticates with the chariotai-api-key header. It connects directly to api.chariot.in with certificate verification. It does not use environment proxy settings.

Save and compare runs

Use a different --json path for each run. The report includes the UTC start time, platform, Python and WebSocket library versions, model, voice, text, settings, raw trials, connection IDs, and summaries. It does not include your API key. Keep the voice, model, text, speed, and latency setting consistent when comparing results. Record your client location and network conditions alongside the JSON report. Run from the host where your application will make requests if you want to measure that path. The default order is HTTP fresh, HTTP reused, WebSocket fresh, then WebSocket reused. These groups run sequentially, so server load and network conditions can change between them. For the complete implementation and local protocol checks, see the latency tool source and README.