Mercury Genesys Token Calculator
This commit is contained in:
358
calculators/Genesys_Token_Calculator/genesyscalc/ratecard.py
Normal file
358
calculators/Genesys_Token_Calculator/genesyscalc/ratecard.py
Normal file
@@ -0,0 +1,358 @@
|
||||
"""THE VERBATIM ANCHOR — Genesys Cloud tokens model, as published.
|
||||
|
||||
Transcribed from
|
||||
https://help.genesys.cloud/articles/genesys-cloud-tokens-model/
|
||||
**last updated 2026-07-12**. Feature names and rate strings below are the
|
||||
article's own wording, character for character.
|
||||
|
||||
VERBATIM — DO NOT EDIT. A vendor republication is a deliberate
|
||||
**re-anchoring**, not a patch (docs/Calculator_Pattern_V1-00.md):
|
||||
|
||||
1. diff the published table against this file
|
||||
2. update the meters AND bump RATE_CARD_SOURCE_DATE in the same edit
|
||||
3. update the pins in tests/test_rate_card.py in the same commit
|
||||
4. re-execute the notebook
|
||||
5. report the cost moves honestly
|
||||
6. Show-first — the user sees the rate diff before it lands
|
||||
|
||||
Never partially re-anchor; never bump the date without the pins.
|
||||
|
||||
Negotiated or contracted values NEVER land here. They are the overlay, and
|
||||
they live in the notebook's ``engagement-data`` cell — this file is the
|
||||
vendor's record, not the client's deal.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from .meters import LicenceModel, Meter, MeterBasis, Tier
|
||||
|
||||
RATE_CARD_SOURCE: str = "https://help.genesys.cloud/articles/genesys-cloud-tokens-model/"
|
||||
RATE_CARD_SOURCE_DATE: str = "2026-07-12"
|
||||
|
||||
# Every meter below is published on the same page on the same date, so the
|
||||
# source pair is spelled out once here and passed explicitly. Explicit beats
|
||||
# a splat: this file is diffed against the article by eye.
|
||||
_URL = RATE_CARD_SOURCE
|
||||
_DATE = RATE_CARD_SOURCE_DATE
|
||||
|
||||
|
||||
#: The published meter table, verbatim. Twenty rows, in the article's order.
|
||||
METERS_VERBATIM: tuple[Meter, ...] = (
|
||||
Meter(
|
||||
key="bots_voice",
|
||||
feature="Bots (Voice)",
|
||||
published_rate="17 minutes per token",
|
||||
basis=MeterBasis.VOICE_MINUTES,
|
||||
rate=1.0 / 17.0,
|
||||
tier=Tier.BOT,
|
||||
unit_label="bot minutes",
|
||||
note=(
|
||||
"Genesys rounds up each call to the next 15-second increment "
|
||||
"(clarified 2026-07-12)."
|
||||
),
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="bots_digital",
|
||||
feature="Bots (Digital)",
|
||||
published_rate="51 sessions per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 51.0,
|
||||
tier=Tier.BOT,
|
||||
unit_label="sessions",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="virtual_agent",
|
||||
feature="Virtual Agent",
|
||||
published_rate="0.5 tokens per Virtual Agent interaction",
|
||||
basis=MeterBasis.TOKENS_PER_UNIT,
|
||||
rate=0.5,
|
||||
tier=Tier.VIRTUAL_AGENT,
|
||||
unit_label="interactions",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="agentic_virtual_agent",
|
||||
feature="Agentic Virtual Agent",
|
||||
published_rate="1.2 tokens per interaction",
|
||||
basis=MeterBasis.TOKENS_PER_UNIT,
|
||||
rate=1.2,
|
||||
tier=Tier.AGENTIC_VIRTUAL_AGENT,
|
||||
unit_label="interactions",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="agent_copilot_named",
|
||||
feature="Agent Copilot [named]",
|
||||
published_rate="40 tokens per user",
|
||||
basis=MeterBasis.PER_USER_PER_MONTH,
|
||||
per_user_named=40.0,
|
||||
per_user_concurrent=60.0,
|
||||
unit_label="users",
|
||||
note="Enabling Copilot makes Supervisor summaries and insights free.",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="agent_copilot_concurrent",
|
||||
feature="Agent Copilot [concurrent]",
|
||||
published_rate="60 tokens per user",
|
||||
basis=MeterBasis.PER_USER_PER_MONTH,
|
||||
per_user_named=40.0,
|
||||
per_user_concurrent=60.0,
|
||||
unit_label="users",
|
||||
note="The concurrent-licence face of the same meter.",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="ai_scoring",
|
||||
feature="AI Scoring",
|
||||
published_rate="20 evaluations per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 20.0,
|
||||
unit_label="evaluations",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="ai_translate",
|
||||
feature="AI Translate",
|
||||
published_rate="2 translations per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 2.0,
|
||||
unit_label="translations",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="ai_summary_and_insights",
|
||||
feature="AI Summary and Insights",
|
||||
published_rate="50 summaries/insights per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 50.0,
|
||||
unit_label="summaries",
|
||||
note=(
|
||||
"Free when Agent Copilot is enabled — see "
|
||||
"COPILOT_COVERS_SUMMARY_RULE."
|
||||
),
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="apple_messages_for_business",
|
||||
feature="Apple Messages for Business",
|
||||
published_rate="400 inbound or outbound messages per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 400.0,
|
||||
unit_label="messages",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="facebook_messenger",
|
||||
feature="Facebook Messenger",
|
||||
published_rate="400 messages per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 400.0,
|
||||
unit_label="messages",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="instagram_direct_messaging",
|
||||
feature="Instagram Direct Messaging",
|
||||
published_rate="400 messages per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 400.0,
|
||||
unit_label="messages",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="whatsapp_messaging",
|
||||
feature="WhatsApp Messaging",
|
||||
published_rate="400 messages per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 400.0,
|
||||
unit_label="messages",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="x_direct_messaging",
|
||||
feature="X Direct Messaging",
|
||||
published_rate="400 messages per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 400.0,
|
||||
unit_label="messages",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="genesys_cloud_social",
|
||||
feature="Genesys Cloud Social",
|
||||
published_rate="400 social post ingestions per channel per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 400.0,
|
||||
unit_label="post ingestions",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="social_post_responses",
|
||||
feature="Social Post Responses",
|
||||
published_rate="400 outbound messages per channel per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 400.0,
|
||||
unit_label="outbound messages",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="predictive_routing",
|
||||
feature="Predictive Routing",
|
||||
published_rate="17 routes per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 17.0,
|
||||
unit_label="routes",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="speech_and_text_analytics_named",
|
||||
feature="Speech and Text Analytics [named]",
|
||||
published_rate="30 tokens per user",
|
||||
basis=MeterBasis.PER_USER_PER_MONTH,
|
||||
per_user_named=30.0,
|
||||
per_user_concurrent=45.0,
|
||||
unit_label="users",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="speech_and_text_analytics_concurrent",
|
||||
feature="Speech and Text Analytics [concurrent]",
|
||||
published_rate="45 tokens per user",
|
||||
basis=MeterBasis.PER_USER_PER_MONTH,
|
||||
per_user_named=30.0,
|
||||
per_user_concurrent=45.0,
|
||||
unit_label="users",
|
||||
note="The concurrent-licence face of the same meter.",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="genesys_cloud_copilot",
|
||||
feature="Genesys Cloud Copilot",
|
||||
published_rate="20 AI actions per token",
|
||||
basis=MeterBasis.UNITS_PER_TOKEN,
|
||||
rate=1.0 / 20.0,
|
||||
unit_label="AI actions",
|
||||
note="Genesys Cloud knowledge queries are not charged.",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
#: Published as included at no token cost. Shown on stage as explicit $0
|
||||
#: lines — a zero the vendor put in writing is a finding, not an omission.
|
||||
ZERO_RATED_VERBATIM: tuple[Meter, ...] = (
|
||||
Meter(
|
||||
key="predictive_engagement",
|
||||
feature="Predictive Engagement",
|
||||
published_rate="No charge for token usage",
|
||||
basis=MeterBasis.ZERO_RATED,
|
||||
unit_label="interactions",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
Meter(
|
||||
key="knowledge_queries",
|
||||
feature="Genesys Cloud knowledge queries",
|
||||
published_rate="no charge for Genesys Cloud knowledge queries",
|
||||
basis=MeterBasis.ZERO_RATED,
|
||||
unit_label="queries",
|
||||
source_url=_URL,
|
||||
source_date=_DATE,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
#: "Named organizations receive 250 tokens; concurrent organizations receive
|
||||
#: 350 tokens" per month.
|
||||
FREE_TOKENS_PER_MONTH: dict[LicenceModel, int] = {
|
||||
LicenceModel.NAMED: 250,
|
||||
LicenceModel.CONCURRENT: 350,
|
||||
}
|
||||
|
||||
#: "These tokens renew each month and do not carry over to future months."
|
||||
ALLOWANCE_CARRIES_OVER: bool = False
|
||||
|
||||
#: "Genesys rounds up each call to the next 15-second increment."
|
||||
#: Clarified in the 2026-07-12 revision. Applied PER CALL, then summed.
|
||||
VOICE_BOT_ROUNDUP_SECONDS: int = 15
|
||||
|
||||
#: The published highest-tier rule, verbatim. Renders on stage.
|
||||
HIGHEST_TIER_RULE: str = (
|
||||
"In cases where an interaction uses multiple AI resources, such as bot "
|
||||
"flows, virtual agents, and agentic virtual agents, Genesys bases charges "
|
||||
"on the highest tier (price) resource that Genesys Cloud uses during the "
|
||||
"interaction."
|
||||
)
|
||||
|
||||
#: The published Copilot exclusion, verbatim. Renders on stage.
|
||||
COPILOT_COVERS_SUMMARY_RULE: str = (
|
||||
"if you enable Agent Copilot simultaneously, then Supervisor Copilot "
|
||||
"summaries and insights do not consume tokens"
|
||||
)
|
||||
|
||||
#: List price per token. The article points to the pricing hub and cites
|
||||
#: "USD 1.00 to JPY 120 per token by currency".
|
||||
LIST_PRICE_BY_CURRENCY: dict[str, float] = {"USD": 1.00, "JPY": 120.0}
|
||||
|
||||
|
||||
#: Every meter by key — the consumption table plus the zero-rated lines.
|
||||
METERS: dict[str, Meter] = {
|
||||
m.key: m for m in METERS_VERBATIM + ZERO_RATED_VERBATIM
|
||||
}
|
||||
|
||||
|
||||
def meter(key: str) -> Meter:
|
||||
"""Look up a published meter, with a useful error when the key is wrong."""
|
||||
try:
|
||||
return METERS[key]
|
||||
except KeyError:
|
||||
raise KeyError(
|
||||
f"{key!r} is not a published Genesys meter. Known keys: "
|
||||
f"{', '.join(sorted(METERS))}"
|
||||
) from None
|
||||
|
||||
|
||||
def per_user_meter(licence: LicenceModel, family: str) -> Meter:
|
||||
"""The Copilot / STA meter face matching ``licence``.
|
||||
|
||||
``family`` is ``"agent_copilot"`` or ``"speech_and_text_analytics"``.
|
||||
Both rates live on both faces, so this is presentation sugar — it picks
|
||||
the row whose published wording matches the licence being modelled.
|
||||
"""
|
||||
return meter(f"{family}_{licence.value}")
|
||||
|
||||
|
||||
def rate_card_rows() -> list[dict[str, str]]:
|
||||
"""The published table as display rows, in publication order."""
|
||||
return [
|
||||
{
|
||||
"Feature": m.feature,
|
||||
"Published rate": m.published_rate,
|
||||
"Confidence": m.confidence.icon,
|
||||
"Source": m.source_date or "",
|
||||
}
|
||||
for m in METERS_VERBATIM + ZERO_RATED_VERBATIM
|
||||
]
|
||||
Reference in New Issue
Block a user