zcbot/tests/test_pricing.py

99 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from contextlib import contextmanager
from datetime import datetime, timezone
from decimal import Decimal
from pathlib import Path
from types import SimpleNamespace
import unittest
from unittest.mock import patch
from uuid import uuid4
from core.capabilities import ModelCapabilities
from core.pricing import calculate_chat_cost, resolve_chat_price
from core.storage.usage import record_chat_usage
MODELS_DIR = Path(__file__).resolve().parents[1] / "config" / "models"
class PricingTests(unittest.TestCase):
def test_deepseek_flash_selects_peak_and_off_peak(self) -> None:
caps = ModelCapabilities.load("deepseek_v4.flash", MODELS_DIR)
# 2026-08-17 是周一01:00 UTC 为峰时起点04:00 已回到谷时。
peak = resolve_chat_price(
caps.pricing,
occurred_at=datetime(2026, 8, 17, 1, 0, tzinfo=timezone.utc),
)
off_peak = resolve_chat_price(
caps.pricing,
occurred_at=datetime(2026, 8, 17, 4, 0, tzinfo=timezone.utc),
)
self.assertIsNotNone(peak)
self.assertIsNotNone(off_peak)
assert peak is not None and off_peak is not None
self.assertEqual(peak.tier, "peak")
self.assertEqual(peak.input_per_mtoken, Decimal("0.44"))
self.assertEqual(off_peak.tier, "default")
self.assertEqual(off_peak.output_per_mtoken, Decimal("0.66"))
def test_deepseek_weekend_is_off_peak(self) -> None:
caps = ModelCapabilities.load("deepseek_v4.pro", MODELS_DIR)
quote = resolve_chat_price(
caps.pricing,
occurred_at=datetime(2026, 8, 22, 2, 0, tzinfo=timezone.utc),
)
assert quote is not None
self.assertEqual(quote.tier, "default")
def test_usd_quote_calculates_cache_split_in_cny(self) -> None:
caps = ModelCapabilities.load("deepseek_v4.flash", MODELS_DIR)
quote = resolve_chat_price(
caps.pricing,
occurred_at=datetime(2026, 8, 17, 1, 0, tzinfo=timezone.utc),
)
assert quote is not None
result = calculate_chat_cost(
quote,
prompt_tokens=1_000_000,
completion_tokens=500_000,
cache_hit_tokens=800_000,
)
# miss:0.2*0.44*7.2 + hit:0.8*0.014*7.2 + out:0.5*1.32*7.2
self.assertEqual(result.total_cny, Decimal("5.466240"))
self.assertEqual(result.cache_miss_tokens, 200_000)
def test_local_catalog_precedes_litellm_cost_map(self) -> None:
caps = ModelCapabilities.load("deepseek_v4.flash", MODELS_DIR)
added = []
class FakeSession:
def add(self, row):
added.append(row)
@contextmanager
def fake_scope():
yield FakeSession()
with (
patch("core.storage.usage.session_scope", fake_scope),
patch("core.storage.usage._safe_chat_cost_usd", return_value=Decimal("999")),
):
cost = record_chat_usage(
task_id=None,
user_id=uuid4(),
message_id=None,
model_profile="deepseek_v4.flash",
prompt_tokens=1_000_000,
completion_tokens=0,
pricing=caps.pricing,
occurred_at=datetime(2026, 8, 17, 4, 0, tzinfo=timezone.utc),
response=SimpleNamespace(created=None),
)
self.assertEqual(cost, Decimal("1.584000"))
self.assertEqual(added[0].units["pricing_revision"], "deepseek-v4-20260816")
self.assertEqual(added[0].units["price_tier"], "default")
if __name__ == "__main__":
unittest.main()