Preview Sume TTS sentence ids, lengths and job cost before you submit
A short Python script that splits a script like Sume's source API, groups sentences under 20,000 characters and prices each job at $0.0475 per 1,000 characters.

Before you accept a script and generate, you can predict three things offline: the sentence ids the source API will assign, the character count of each, and what each job will cost. The cost rule is Sume TTS's list price of $0.0475 per 1,000 characters, rounded up to the next cent per job, with a one-cent minimum and a 20,000-character cap per request.
Integer math avoids float surprises: cents = ceil(characters x 19 / 4000), which is the same as 4.75 cents per 1,000.
The script
It uses the same sentence rule as the source API (cut after ., !, ?), then packs consecutive sentences into jobs under the cap. It does not call the API, so it needs no key.
import re
def cents(chars):
return max(1, -(-chars * 19 // 4000))
def plan(text, cap=20000):
parts = [p for p in re.findall(r"[^.!?]*[.!?]|[^.!?]+\Z", text) if p.strip()]
jobs, cur = [], ""
for p in parts:
if cur and len((cur + p).strip()) > cap:
jobs.append(cur.strip())
cur = ""
cur += p
if cur.strip():
jobs.append(cur.strip())
return jobs
script = "Welcome back. Today we cover three tips! Ready? " * 400
jobs = plan(script)
for i, j in enumerate(jobs):
print(i, len(j), cents(len(j)))
print("total cents", sum(cents(len(j)) for j in jobs))What it prints
The sample script is 19,200 characters before trimming. Cost depends on how the packing lands, so run it on your own text. The per-job rounding is the only place the total can exceed a flat per-character estimate.
Caveats
- The server also adds a newline when a selection crosses a block boundary; keep a small margin under 20,000.
- This predicts the price of the literal characters. It does not know your voice or model; the table price is for Sume TTS 1.0 at the list rate.
- A sentence longer than the cap needs a rewrite; the splitter above would put it in a job of its own and the API would refuse it.
Sources
Related posts
More in Developers
- Sume waitForJob pollInterval is a floor; next_poll_after_seconds wins
waitForJob never polls faster than pollInterval, and a longer next_poll_after_seconds from the server raises the gap. Defaults, timing table, sample.
- Sume webhook fails the 300-second window: find the clock drift
A valid Sume signature still fails if your server clock is more than five minutes off. Tell drift from a bad secret with a small Python check.
- Sume webhook handler over 10 seconds: acknowledge first, then work
Sume gives each webhook attempt 10 seconds. Verify, answer 2xx, then process in the background and dedupe on job_id. Node sample you can run locally.
- Sume webhook rotation: upgrade the verifier before you click Rotate
During a rotation window Sume sends two signatures in one header. A receiver that compares the whole header for equality fails every delivery. Fix it first.
Written by Sume