# -*- 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())