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.py,8组用例含分档边界全过)。
幂等:方案按名复用;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())