115 lines
4.1 KiB
Python
115 lines
4.1 KiB
Python
"""Enhanced TTS — the non-token line, its round-up, and its free share."""
|
||
|
||
from __future__ import annotations
|
||
|
||
import pytest
|
||
from genesyscalc.meters import Confidence
|
||
from genesyscalc.tts import (
|
||
TTS_PRICE_PER_MILLION_CHARS,
|
||
TTS_SOURCE,
|
||
TTS_SOURCE_DATE,
|
||
TTS_STANDARD_END_OF_SALE,
|
||
TTS_STANDARD_END_OF_SUPPORT,
|
||
TtsUsage,
|
||
tts_cost,
|
||
tts_free_share,
|
||
)
|
||
from genesyscalc.usage import DeflectionMix
|
||
|
||
|
||
def test_published_rates() -> None:
|
||
assert TTS_PRICE_PER_MILLION_CHARS == {"advanced": 20.0, "standard": 5.0}
|
||
|
||
|
||
def test_source_pinned_and_distinct_from_the_tokens_article() -> None:
|
||
"""TTS has its own page and its own date — it is not a token meter."""
|
||
from genesyscalc.ratecard import RATE_CARD_SOURCE, RATE_CARD_SOURCE_DATE
|
||
|
||
assert TTS_SOURCE_DATE == "2026-05-22"
|
||
assert TTS_SOURCE.endswith("genesys-enhanced-tts-pricing/")
|
||
assert TTS_SOURCE != RATE_CARD_SOURCE
|
||
assert TTS_SOURCE_DATE != RATE_CARD_SOURCE_DATE
|
||
|
||
|
||
def test_tts_is_published_so_confirmed() -> None:
|
||
line = tts_cost(TtsUsage(calls_monthly=100_000))
|
||
assert line.confidence is Confidence.CONFIRMED
|
||
|
||
|
||
def test_hand_checked_advanced_cost() -> None:
|
||
"""100,000 calls × 2,000 chars = 200M chars → 200 units × $20 = $4,000/mo."""
|
||
line = tts_cost(TtsUsage(calls_monthly=100_000, chars_per_call=2_000))
|
||
assert line.total_chars_monthly == pytest.approx(200_000_000.0)
|
||
assert line.billed_millions_monthly == 200
|
||
assert line.cost_monthly == pytest.approx(4_000.0)
|
||
assert line.cost_annual == pytest.approx(48_000.0)
|
||
|
||
|
||
def test_hand_checked_standard_cost() -> None:
|
||
"""Same volume on standard voices: 200 × $5 = $1,000/mo."""
|
||
line = tts_cost(
|
||
TtsUsage(calls_monthly=100_000, chars_per_call=2_000, tier="standard")
|
||
)
|
||
assert line.cost_monthly == pytest.approx(1_000.0)
|
||
|
||
|
||
def test_per_million_roundup_published_examples() -> None:
|
||
"""The article's own examples: 200,000 chars = $5; 1,000,005 chars = $10.
|
||
|
||
Both on standard voices, where the unit rate is $5.
|
||
"""
|
||
small = tts_cost(TtsUsage(calls_monthly=1, chars_per_call=200_000, tier="standard"))
|
||
assert small.billed_millions_monthly == 1
|
||
assert small.cost_monthly == pytest.approx(5.0)
|
||
|
||
just_over = tts_cost(
|
||
TtsUsage(calls_monthly=1, chars_per_call=1_000_005, tier="standard")
|
||
)
|
||
assert just_over.billed_millions_monthly == 2
|
||
assert just_over.cost_monthly == pytest.approx(10.0)
|
||
|
||
|
||
def test_free_share_tracks_the_virtual_agent_tiers() -> None:
|
||
"""Free during VA and agentic VA — bot-only deflection does not qualify."""
|
||
mix = DeflectionMix(
|
||
bot_only_share=0.30, virtual_agent_share=0.15, agentic_va_share=0.05
|
||
)
|
||
assert tts_free_share(mix) == pytest.approx(0.20)
|
||
|
||
|
||
def test_free_share_reduces_the_bill() -> None:
|
||
"""200M chars, 20% free → 160M billable → 160 × $20 = $3,200/mo."""
|
||
mix = DeflectionMix(virtual_agent_share=0.15, agentic_va_share=0.05)
|
||
line = tts_cost(TtsUsage(calls_monthly=100_000, chars_per_call=2_000), mix)
|
||
assert line.free_share == pytest.approx(0.20)
|
||
assert line.free_chars_monthly == pytest.approx(40_000_000.0)
|
||
assert line.billable_chars_monthly == pytest.approx(160_000_000.0)
|
||
assert line.cost_monthly == pytest.approx(3_200.0)
|
||
|
||
|
||
def test_standard_tier_warns_about_end_of_life() -> None:
|
||
line = tts_cost(TtsUsage(calls_monthly=1_000, tier="standard"))
|
||
assert len(line.warnings) == 1
|
||
assert TTS_STANDARD_END_OF_SALE in line.warnings[0]
|
||
assert TTS_STANDARD_END_OF_SUPPORT in line.warnings[0]
|
||
|
||
|
||
def test_advanced_tier_does_not_warn() -> None:
|
||
assert tts_cost(TtsUsage(calls_monthly=1_000)).warnings == ()
|
||
|
||
|
||
def test_concession_applies_to_tts_too() -> None:
|
||
line = tts_cost(TtsUsage(calls_monthly=100_000), concession_pct=0.25)
|
||
assert line.cost_monthly == pytest.approx(3_000.0)
|
||
|
||
|
||
def test_zero_volume_costs_nothing() -> None:
|
||
line = tts_cost(TtsUsage(calls_monthly=0))
|
||
assert line.billed_millions_monthly == 0
|
||
assert line.cost_monthly == 0.0
|
||
|
||
|
||
def test_unknown_tier_rejected() -> None:
|
||
with pytest.raises(ValueError, match="unknown TTS tier"):
|
||
TtsUsage(calls_monthly=1, tier="neural-ultra")
|