pipeline-llm/scripts/apply_pricing_minimax_20260907.py

171 lines
8.4 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

# -*- coding: utf-8 -*-
"""MiniMax 定价落库2026-09-07 用户提供价目表)。
覆盖M3≤512k/>512k 分档永久五折价、M2.7、M2.7-highspeed。
不配M2/M2.1/M2.1-highspeed/M2.5/M2.5-highspeed价目表没有铁律不编造
「缓存写入2.625」因子无运行时usage证据历史流水为空配了永远命中不了
所有 YAML 已过引擎试算tmp_mm.py8组用例含分档边界全过
幂等方案按名复用timing 每 ppid 单条有效行(同内容跳过/同日原地/历史拉链)。
用法py3/bin/python tmp_mm_apply.py [--dry]
"""
import asyncio
import json
import sys
import time
sys.path.insert(0, '/d/pipeline/pipeline-app')
import yaml # noqa: E402
from sqlor.dbpools import DBPools # noqa: E402
from appPublic.uniqueID import getID # noqa: E402
from appPublic.jsonConfig import getConfig # noqa: E402
DRY = '--dry' in sys.argv
DOC_QUOTE = '用户提供的MiniMax按量计费价目表2026-09-07粘贴正文'
TOKEN_FIELDS = {
'price_factors': {'type': 'string', 'role': 'factor', 'label': '计价因子'},
'unit_prices': {'type': 'float', 'role': 'factor', 'label': '单位定价'},
'unit': {'type': 'string', 'role': 'factor', 'label': '计价单位'},
'uncache_tokens': {'type': 'int', 'role': 'factor', 'label': '非缓存输入Token',
'derived': 'prompt_tokens - prompt_tokens_details.cached_tokens'},
'cached_tokens': {'type': 'int', 'role': 'factor', 'label': '缓存Token',
'derived': 'prompt_tokens_details.cached_tokens'},
'completion_tokens': {'type': 'float', 'role': 'factor', 'label': '输出tokens'},
}
def token_yaml(u, c, ca):
return yaml.dump({'unit_values': {'百万': 1000000}, 'fields': TOKEN_FIELDS,
'pricings': [
{'price_factors': 'uncache_tokens', 'unit_prices': u, 'unit': '百万'},
{'price_factors': 'completion_tokens', 'unit_prices': c, 'unit': '百万'},
{'price_factors': 'cached_tokens', 'unit_prices': ca, 'unit': '百万'}]},
allow_unicode=True, sort_keys=False)
def tiered_token_yaml(tiers):
fields = dict(TOKEN_FIELDS)
fields['prompt_tokens'] = {'type': 'int', 'role': 'filter', 'label': 'prompt_tokens',
'value_mode': 'between'}
pricings = []
for fi, factor in enumerate(('uncache_tokens', 'completion_tokens', 'cached_tokens')):
filters = []
for lo, hi, u, c, ca in tiers:
op = ('0 =~= %d' % hi) if lo == 0 else ('%d ~= %d' % (lo, hi))
filters.append({'prompt_tokens': op, 'value_mode': 'between',
'unit_prices': (u, c, ca)[fi]})
pricings.append({'price_factors': factor, 'unit_prices': tiers[-1][2 + fi],
'unit': '百万', 'filters': filters})
return yaml.dump({'unit_values': {'百万': 1000000}, 'fields': fields, 'pricings': pricings},
allow_unicode=True, sort_keys=False)
PLANS = [
('MiniMax-M3 定价', tiered_token_yaml([
(0, 512000, 2.10, 8.40, 0.42),
(512000, 1000000, 4.20, 16.80, 0.84)]),
'MiniMax-M3 ≤512k输入tokens永久五折 输入2.10/输出8.40/缓存读取0.42; '
'>512k永久五折 4.20/16.80/0.84 元/百万tokens', ['MiniMax-M3']),
('MiniMax-M2.7 定价', token_yaml(2.1, 8.4, 0.42),
'MiniMax-M2.7 输入2.1/输出8.4/缓存读取0.42 元/百万tokens', ['MiniMax-M2.7']),
('MiniMax-M2.7-highspeed 定价', token_yaml(4.2, 16.8, 0.42),
'MiniMax-M2.7-highspeed 输入4.2/输出16.8/缓存读取0.42 元/百万tokens',
['MiniMax-M2.7-highspeed']),
]
async def main():
cfg = getConfig()
DBPools(cfg.databases)
db = DBPools()
log = []
now = time.strftime('%Y-%m-%d')
async with db.sqlorContext('pipeline') as sor:
for pname, yml, quote, model_names in PLANS:
desc = '定价出处:%s | 文档原文:%s' % (DOC_QUOTE, quote)
recs = await sor.sqlExe(
"SELECT id FROM pricing_program WHERE name=${n}$ LIMIT 1", {"n": pname})
await sor.sqlExe("COMMIT", {})
if recs:
ppid = recs[0].id
action = '复用方案'
recs2 = await sor.sqlExe(
"SELECT id, pricing_data, enabled_date FROM pricing_program_timing "
"WHERE ppid=${p}$ AND expired_date='9999-12-31' "
"ORDER BY enabled_date DESC LIMIT 1", {"p": ppid})
await sor.sqlExe("COMMIT", {})
cur = recs2[0] if recs2 else None
same = False
if cur is not None:
try:
same = (yaml.safe_load(cur.pricing_data or '{}') == yaml.safe_load(yml))
except Exception:
same = (cur.pricing_data or '') == yml
if same:
action = '复用方案+内容无变化(幂等跳过)'
elif cur is not None and str(cur.enabled_date)[:10] == now:
if not DRY:
await sor.sqlExe(
"UPDATE pricing_program_timing SET pricing_data=${y}$ WHERE id=${i}$",
{"y": yml, "i": cur.id})
await sor.sqlExe("COMMIT", {})
action = '复用方案+原地更新(同日)'
elif cur is not None:
if not DRY:
await sor.sqlExe(
"UPDATE pricing_program_timing SET expired_date=${d}$ "
"WHERE ppid=${p}$ AND expired_date='9999-12-31'",
{"d": now, "p": ppid})
await sor.C('pricing_program_timing', {
'id': getID(), 'ppid': ppid, 'name': pname, 'pricing_data': yml,
'enabled_date': now, 'expired_date': '9999-12-31'})
await sor.sqlExe("COMMIT", {})
action = '复用方案+拉链更新'
else:
if not DRY:
await sor.C('pricing_program_timing', {
'id': getID(), 'ppid': ppid, 'name': pname, 'pricing_data': yml,
'enabled_date': now, 'expired_date': '9999-12-31'})
await sor.sqlExe("COMMIT", {})
action = '复用方案+新建时序'
if not DRY:
await sor.sqlExe(
"UPDATE pricing_program SET description=${d}$ WHERE id=${i}$",
{"d": desc[:1000], "i": ppid})
await sor.sqlExe("COMMIT", {})
else:
ppid = getID()
if not DRY:
await sor.C('pricing_program', {
'id': ppid, 'name': pname, 'ownerid': '0', 'providerid': '',
'pricing_belong': '', 'description': desc[:1000], 'currency': 'CNY'})
await sor.C('pricing_program_timing', {
'id': getID(), 'ppid': ppid, 'name': pname, 'pricing_data': yml,
'enabled_date': now, 'expired_date': '9999-12-31'})
await sor.sqlExe("COMMIT", {})
action = '新建方案+时序'
for mn in model_names:
recs3 = await sor.sqlExe(
"SELECT id, COALESCE(ppid,'') AS ppid FROM llm_model "
"WHERE name=${n}$ AND status='active'", {"n": mn})
await sor.sqlExe("COMMIT", {})
if not recs3:
log.append(' ⚠ 模型 %s 未找到active——跳过挂载' % mn)
continue
mid = recs3[0].id
old_ppid = recs3[0].ppid or ''
if old_ppid == ppid:
log.append(' %s ppid 已正确' % mn)
continue
if not DRY:
await sor.sqlExe(
"UPDATE llm_model SET ppid=${p}$, updated_at=NOW() WHERE id=${i}$",
{"p": ppid, "i": mid})
await sor.sqlExe("COMMIT", {})
log.append(' %s: ppid %s%s [%s]' % (mn, old_ppid or '', ppid, action))
print(json.dumps({'dry': DRY, 'log': log}, ensure_ascii=False, indent=1))
asyncio.run(main())