Unit-test your Omni price math before Oct 22: Python asserts for Sume
A runnable Python test for Sume's gemini-omni-flash-1.1 pricing: Decimal rates, the 3 to 10 second rule, and a one-cent check against the usage.cost on a poll.

Put the price of a Sume Omni clip under test before you change a model id: write the rate table once with Decimal, reject lengths the model does not accept, and compare each real usage.cost with your own figure to within one cent. The script below does all three in plain Python and prints ok when it passes. It uses the rates Sume's docs imply, the provider list of $0.03, $0.10, $0.15 and $0.30 times 1.25.
The test file
The tests use asserts, so they run under pytest or with plain python. Use Decimal and strings, not floats, because $0.0375 a second does not survive float arithmetic cleanly in a total over many jobs. The one-cent tolerance exists because a billed amount may be rounded to cents, so the test should not fail on a fraction of a cent.
from decimal import Decimal as D
RATE = {"360p": D("0.0375"), "720p": D("0.125"), "1080p": D("0.1875"), "4K": D("0.375")}
def omni_cost(seconds, resolution):
if int(seconds) != seconds or not 3 <= seconds <= 10:
raise ValueError("Omni takes whole seconds from 3 to 10")
return RATE[resolution] * seconds
def close(a, b):
return abs(D(str(a)) - D(str(b))) < D("0.01")
def test_known_prices():
assert omni_cost(8, "720p") == D("1.00")
assert omni_cost(8, "1080p") == D("1.50")
assert omni_cost(10, "4K") == D("3.75")
assert omni_cost(10, "360p") == D("0.375")
def test_rejects_bad_lengths():
for bad in (2, 11, 7.5):
try:
omni_cost(bad, "720p")
except ValueError:
continue
raise AssertionError(bad)
def test_poll_cost_matches(poll):
assert close(poll["usage"]["cost"], omni_cost(8, "720p"))
test_known_prices()
test_rejects_bad_lengths()
test_poll_cost_matches({"usage": {"cost": 1.0}})
print("ok")What each test protects
The first test pins four prices that appear in this post series, so a rate change shows up as a failing test instead of a surprise on the invoice. The second encodes the 3 to 10 second window in the Sume docs; a caller that passes 11 seconds, 2 seconds or 7.5 seconds is wrong before the request leaves your machine. The third is the check you run on real data: after a job completes, compare usage.cost with the figure your code predicted.
| Rule | Value | Where it comes from |
|---|---|---|
| Rate at 720p | $0.125 per second | Provider list $0.10 x 1.25 |
| Clip length | 3 to 10 whole seconds | Video Router and Video generation docs |
| Aspect ratios | 16:9 or 9:16 | Video generation docs |
| Cost field | usage.cost on the poll response | Video generation docs |
When the test should fail
It should fail when Sume changes a rate, and that is the point: update the table only after you have read the new price from the catalog or from a completed job. It should also fail when a caller asks for a length Omni does not take, and then the fix is a clamp or a split, not a looser test. Run the file in CI on every deploy until Google's October 22 shutdown has passed and your migration is complete.
Extending it
Add one row per model you use. The Wan 3.0 rate is $0.0625, $0.125 and $0.25 a second at 480p, 720p and 1080p, and it accepts 2 to 30 seconds, so a new function with a different window is a copy of the first. Keep one function per model so that a model swap is a diff in one place.
Sources
Related posts
More in Developers
- One Sume webhook route for job and run events, 204 on the rest
Route job.* and *.run.terminal events from one verified webhook handler and answer 204 for any unknown event, so a new type cannot trigger retries.
- urllib3 Retry on POST: retry a Sume submit only with a key
A urllib3 Retry config that retries 429, 502, 503 and 504 on a Sume submit, and a wrapper that refuses to send a POST without an Idempotency-Key.
- Sume video poll usage.cost: reserved while running, captured at end
The usage.cost number is the Sume billable amount: the reservation while a job runs and the captured amount once it settles. wan-3.0 at 720p, 10 s, as math.
- Validate a Gemini Omni Flash 1.1 request in Python before sending
A 28-line Python check for Sume's gemini-omni-flash-1.1 rules: 3-10 s, 10 reference images, 3 reference videos, no audio off, and edit mode exclusions.
Written by Sume