pricing/pricing/pricing.py
2026-03-18 18:30:21 +08:00

246 lines
5.5 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.

import json
import yaml
from ahserver.serverenv import ServerEnv
from sqlor.dbpools import DBPools, get_sor_context
from appPublic.log import debug, exception
from appPublic.dictObject import DictObject
import yaml
"""
采用yaml描述定价策略
一下是一个例子
pricing_unit: 1000
- id: input_token_pricing_1
field: prompt_tokens
between: 0 ~= 1000
- id: input_token_pricing_2
- cnt_field: prompt_tokens
between: 1000 ~= 100000
- id: input_token_pricing_2
- cnt_field: prompt_tokens
between: 100000 ~=
- id: output_pricing
- cnt_field: completion_tokens
视频定价
fields:
resolution:
type: str
label: 分辨率
value_mode:
- between
- in
- =
- >
- >=
- <
- <=
duration:
type: int
label: 时长
audio:
type: boolean
label: 音频
pricings:
- resolution: 480p
duration: 4
audio: false
- resolution: 480p
duration: 8
audio: false
- resolution: 480p
duration: 12
audio: false
- resolution: 480p
duration: 4
audio: true
- resolution: 480p
duration: 8
audio: true
- resolution: 480p
duration: 12
audio: true
- resolution: 720p
duration: 4
audio: false
- resolution: 720p
duration: 8
audio: false
- resolution: 720p
duration: 12
audio: false
- resolution: 720p
duration: 4
audio: true
- resolution: 720p
duration: 8
audio: true
- resolution: 720p
duration: 12
audio: true
"""
"""
typefuncs = {
'int': int,
'float': float
}
def typevalue(v, t):
if not v:
return None
f = typefuncs.get(t)
if not f:
return v
return f(v)
def check_value(field, spec_value, data_value):
if field.value_mode == 'between':
arr = spec_value.split(' ')
if len(arr) < 2 or len(arr) > 3:
e = f'{spec_value=} error'
exception(e)
raise Exception(e)
if (arr[0] is None or arr[-1] is None) and field.type == 'str':
e = f'字符串类型between方法的两个值任何一个都不能为空')
exception(e)
raise e
else:
if arr[0] is None:
arr[0] = -float('inf')
if arr[-1] is None:
arr[-1] = float('inf')
if len(arr) == 2 or arr[1] == '=~' :
return arr[0] <= data_value and data_value < arr[-1]
if arr[1] == '~':
return arr[0] < data_value and data_value < arr[-1]
if arr[1] == '~=':
return arr[0] < data_value and data_value <= arr[-1]
e = f'{arr[1]}不认识的期间逻辑,只支持:~ =~ ~='
exception(e)
raise Exception(e)
if field.value_mode == 'in':
arr = spec_value.split(' ')
arr = [ typevalue(a, field.type) for a in arr ]
return data_value in arr
mode = field.value_mode
if not mode:
mode = '='
script = f'{data_value} {mode} {typevalue(spec_value, field.type)}'
x = eval(scrpt)
return x
class PricingProgram:
def parse_pricing_spec(self, yamlstr):
d = yaml.safe_load(yamlstr)
assert isinstance(d, list)
return d
async def add_pricing_program(self, sor,
name, ownerid,
description, pricing_spec, id=None):
env = ServerEnv()
if not id:
id = env.uuid()
yamlstr = yaml.dump(pricing_spec)
await sor.C('pricing_program', {
'id': id,
'name': name,
'ownerid': ownerid,
'description': description,
'pricing_spec': ymalstr
})
async def pp_db2app(self, pp):
try:
pp.pricing_spec = yaml.safe_load(pp.pricing_spec)
except Exception as e:
e = f'{pp.pricing_spec}:yaml数据格式错误'
exception(e)
raise Exception(e)
async def pp_app2db(self, pp):
try:
pp.pricing_spec = yaml.dump(pp.pricing_spec)
except Exception as e:
e = f'{pp.pricing_spec}:导出到yaml失败'
exception(e)
raise Exception(e)
async def ppt_db2app(self, ppt):
try:
ppt.pricing_data = yaml.safe_load(ppt.pricing_data)
except Exception as e:
e = f'{ppt.pricing_data}:yaml数据格式错误'
exception(e)
raise Exception(e)
async def ppt_app2db(self, ppt):
try:
ppt.pricing_data = yaml.dump(ppt.pricing_data)
except Exception as e:
e = f'{ppt.pricing_data}:yaml数据格式错误'
exception(e)
raise Exception(e)
def pricing(self, config_data, yamlstr):
"""
yamlstr是从
d = None
try:
d = yaml.safe_load(yamlstr)
except Exception as e:
exception(f'yaml.sage_load({yamlstr}) error: {e}')
raise e
if not d.fields:
exception(f'{d} has not "fields"')
raise Exception(f'定价定义中没有fields数据')
if not d.pricing:
exception(f'{d} has not "pricing"')
raise Exception(f'定价定义中没有pricing数据')
ret_items = []
for i, p in enumerate(d.pricings):
p_ok = True
times = 1
unit = 1
for k,spec_value in p.items():
f = d.fields.get(k)
if not f:
e = f'定价项({i})中的{k}在fields中没有定义'
exception(f'{e}')
raise Exception(e)
data_value = config_data.get(k)
if not value:
e = f'数据({config_data})没有({k})数据'
exception(e)
raise Exeption(e)
if f.type == 'unit':
unit = spec_value
elif f.type == 'times':
times = data_value
else:
f = check_value(f, spec_value, data_value)
if not f:
# 条件不满足
p_ok = False
break
if p_ok:
if not p.price:
e = f'{p} 没有价格属性')
exception(e)
raise Exception(e)
np = p.copy()
np.amount = p.price * float(times) / float(unit)
ret_items.append(np)
if len(ret_items) == 0:
e = f'{config_data=}{yamlstr=}没有找到合适的定价‘
exception(e)
raise Exception(e)
return ret_items