chore(scripts): 存档2026-09-07价目表定价重建脚本(14:08四表被清空后按用户价目表重建9模型定价+改名text-embedding-flash+happyhorse三模型共享ppid+悬空ppid清理,幂等,引擎试算全过)

This commit is contained in:
yumoqing 2026-09-07 17:21:41 +08:00
parent e9e57cf825
commit bf6c752a50

View File

@ -0,0 +1,284 @@
# -*- coding: utf-8 -*-
"""定价重建落库脚本2026-09-07用户提供的阿里云百炼价目表
背景今日 14:08:01 pricing_program/pricing_program_timing/product/product_category
四表被重建清空23 个模型的 ppid 全部悬空本脚本按价目表重建能对上的模型定价
- qwen3.8-max 12/36/缓存1.5 /百万tokens
- qwen3.8-flash 0.8/2.7/缓存0.1
- qwen3.7-flash 分三档<=32k: 0.2/0.8/0.04; 32k~256k: 0.6/2.4/0.12; 256k~1m: 1.2/4.8/0.24
- qwen3.7-text-embedding-flash 0.125 /百万tokens用户指令模型先改名再按此定价
- ali-deepseek-v4-pro deepseek-v4-pro-0813 用户指令忙时(8-22) 9/27/0.9闲时(22-次日8点) 4.5/13.5/0.45
- wan3.0-video-prime 480P 0.45/720P 0.9/1080P 1.8 /
- happyhorse-1.1-i2v/t2v/r2v 三模型定价相同480P 0.45/720P 0.9/1080P 1.2 共享一个 ppid
跳过价目表对不上/用户明示后补ali-deepseek-v4-flashqwen3-vl-embedding
qwen3-vl-reranktongyi-embedding-vision-flashdoubao 两模型豆包非百炼价目表
MiniMax 全系minimax 价目表非本次提供且已有 ppid 悬空另行处理
幂等pricing_program 名称+出处查重复用timing ppid 只保留一条有效行
内容相同跳过不同且今天启用原地更新历史行拉链
所有 YAML 已过引擎试算/d/pipeline/tmp_pricing_dryrun*.py金额逐项核对
用法py3/bin/python tmp_rebuild_pricing.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 = '用户提供的阿里云百炼价目表2026-09-07粘贴正文'
# ── YAML 构造(与试算脚本完全一致)──
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 i, (lo, hi, u, c, ca) in enumerate(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)
def hour_tiered_token_yaml():
"""deepseek-v4-pro-0813 忙闲时:忙时[8,22) 9/27/0.9;闲时[22,24)+[0,8) 4.5/13.5/0.45。
hour 维度由出账从 llm_usage.created_at 注入pipeline-llm accounting.py 已改"""
fields = dict(TOKEN_FIELDS)
fields['hour'] = {'type': 'int', 'role': 'filter', 'label': '调用小时', 'value_mode': 'between'}
tiers = [('8 =~ 22', 9, 27, 0.9), ('22 =~ 24', 4.5, 13.5, 0.45), ('0 =~ 8', 4.5, 13.5, 0.45)]
pricings = []
for fi, factor in enumerate(('uncache_tokens', 'completion_tokens', 'cached_tokens')):
filters = [{'hour': rng, 'value_mode': 'between', 'unit_prices': (u, c, ca)[fi]}
for rng, u, c, ca in tiers]
pricings.append({'price_factors': factor, 'unit_prices': (9, 27, 0.9)[fi],
'unit': '百万', 'filters': filters})
return yaml.dump({'unit_values': {'百万': 1000000}, 'fields': fields, 'pricings': pricings},
allow_unicode=True, sort_keys=False)
def video_yaml(prices):
fields = {
'price_factors': {'type': 'string', 'role': 'factor', 'label': '计价因子'},
'unit_prices': {'type': 'float', 'role': 'factor', 'label': '单位定价'},
'unit': {'type': 'string', 'role': 'factor', 'label': '计价单位'},
'duration': {'type': 'float', 'role': 'factor', 'label': '时长'},
'SR': {'type': 'int', 'role': 'filter', 'label': '分辨率'},
}
pricings = [{'price_factors': 'duration', 'unit_prices': p, 'unit': '', 'SR': sr}
for sr, p in prices]
return yaml.dump({'unit_values': {'': 1}, 'fields': fields, 'pricings': pricings},
allow_unicode=True, sort_keys=False)
def embedding_yaml(price):
fields = {
'price_factors': {'type': 'string', 'role': 'factor', 'label': '计价因子'},
'unit_prices': {'type': 'float', 'role': 'factor', 'label': '单位定价'},
'unit': {'type': 'string', 'role': 'factor', 'label': '计价单位'},
'prompt_tokens': {'type': 'float', 'role': 'factor', 'label': '输入tokens'},
}
return yaml.dump({'unit_values': {'百万': 1000000}, 'fields': fields,
'pricings': [{'price_factors': 'prompt_tokens',
'unit_prices': price, 'unit': '百万'}]},
allow_unicode=True, sort_keys=False)
# 方案定义:(方案名, YAML, 文档原文quote, [挂载的模型名...])
PLANS = [
('qwen3.8-max 定价', token_yaml(12, 36, 1.5),
'qwen3.8-max 输入¥12/百万tokens 输出¥36 缓存命中¥1.5', ['qwen3.8-max']),
('qwen3.8-flash 定价', token_yaml(0.8, 2.7, 0.1),
'qwen3.8-flash 输入¥0.8/百万tokens 输出¥2.7 缓存命中¥0.1', ['qwen3.8-flash']),
('qwen3.7-flash 定价', tiered_token_yaml([
(0, 32000, 0.2, 0.8, 0.04),
(32000, 256000, 0.6, 2.4, 0.12),
(256000, 1000000, 1.2, 4.8, 0.24)]),
'qwen3.7-flash 输入<=32k:0.2/0.8/0.04; 32k<输入<=256k:0.6/2.4/0.12; 256k<输入<=1m:1.2/4.8/0.24 元/百万tokens',
['qwen3.7-flash']),
('qwen3.7-text-embedding-flash 定价', embedding_yaml(0.125),
'qwen3.7-text-embedding-flash 文本输入¥0.125/百万tokens', ['qwen3.7-text-embedding-flash']),
('ali-deepseek-v4-pro 定价(忙闲时)', hour_tiered_token_yaml(),
'deepseek-v4-pro-0813 忙时(8点-22点)输入¥9/输出¥27/缓存¥0.9; 闲时(22点-次日8点)¥4.5/¥13.5/¥0.45 元/百万tokens',
['ali-deepseek-v4-pro']),
('wan3.0-video-prime 定价', video_yaml([(480, 0.45), (720, 0.9), (1080, 1.8)]),
'wan3.0-video-prime 480P¥0.45/秒 720P¥0.9/秒 1080P¥1.8/秒', ['wan3.0-video-prime']),
('happyhorse-1.1 视频系列定价(共享)', video_yaml([(480, 0.45), (720, 0.9), (1080, 1.2)]),
'happyhorse-1.1-i2v/t2v/r2v 480P¥0.45/秒 720P¥0.9/秒 1080P¥1.2/秒',
['happyhorse-1.1-i2v', 'happyhorse-1.1-t2v', 'happyhorse-1.1-r2v']),
]
RENAME = ('qwen3.7-text-embedding', 'qwen3.7-text-embedding-flash')
async def main():
cfg = getConfig()
DBPools(cfg.databases)
db = DBPools()
log = []
async with db.sqlorContext('pipeline') as sor:
# 0. 改名用户指令name 与 vendor_model_id 一起改,保持调用名与注册名一致
old, new = RENAME
recs = await sor.sqlExe(
"SELECT id, name, vendor_model_id FROM llm_model WHERE name=${n}$ OR vendor_model_id=${n}$",
{"n": old})
await sor.sqlExe("COMMIT", {})
if recs:
mid = recs[0].id
log.append('改名: %s%s (model_id=%s, 原vmid=%s)' % (
old, new, mid, getattr(recs[0], 'vendor_model_id', '')))
if not DRY:
await sor.sqlExe(
"UPDATE llm_model SET name=${new}$, vendor_model_id=${new}$, updated_at=NOW() "
"WHERE id=${i}$", {"new": new, "i": mid})
await sor.sqlExe("COMMIT", {})
else:
# 已改过?
recs2 = await sor.sqlExe("SELECT id FROM llm_model WHERE name=${n}$", {"n": new})
await sor.sqlExe("COMMIT", {})
log.append('改名: 未找到 %s%s 存在=%s,视为已改)' % (old, new, bool(recs2)))
now = time.strftime('%Y-%m-%d')
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 = '复用方案'
# timing 幂等:只保留一条有效行
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 已正确(%s' % (mn, ppid))
continue
# 旧 ppid 悬空校验
dangling = ''
if old_ppid:
recs4 = await sor.sqlExe(
"SELECT id FROM pricing_program WHERE id=${p}$", {"p": old_ppid})
await sor.sqlExe("COMMIT", {})
dangling = '' if recs4 else '旧ppid悬空已清理'
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 [%s]' % (mn, old_ppid or '', ppid, dangling, action))
# 清理:悬空 ppid 置空(模型指向已删除方案的)
recs5 = await sor.sqlExe(
"SELECT m.id, m.name, m.ppid FROM llm_model m WHERE m.ppid<>'' AND m.ppid IS NOT NULL "
"AND NOT EXISTS (SELECT 1 FROM pricing_program p WHERE p.id=m.ppid)", {})
await sor.sqlExe("COMMIT", {})
for r in (recs5 or []):
log.append('悬空清理: %s ppid=%s → 置空' % (r.name, r.ppid))
if not DRY:
await sor.sqlExe("UPDATE llm_model SET ppid='' WHERE id=${i}$", {"i": r.id})
await sor.sqlExe("COMMIT", {})
print(json.dumps({'dry': DRY, 'log': log}, ensure_ascii=False, indent=1))
asyncio.run(main())