diff --git a/json/pricing_program.json b/json/pricing_program.json index c465a16..f120724 100644 --- a/json/pricing_program.json +++ b/json/pricing_program.json @@ -6,7 +6,11 @@ "logined_userorgid": "ownerid", "browserfields": { "exclouded": ["id", "ownerid" ], - "alters": {} + "alters": { + "providerid":{ + "dataurl":"{{entire_url('/rbac/get_provider.dspy')}}" + } + } }, "editexclouded": [ "id", "ownerid" diff --git a/models/pricing_program.xlsx b/models/pricing_program.xlsx index 6c713aa..ae33fc2 100644 Binary files a/models/pricing_program.xlsx and b/models/pricing_program.xlsx differ diff --git a/pricing/init.py b/pricing/init.py index 0f1e8d8..c7f7367 100644 --- a/pricing/init.py +++ b/pricing/init.py @@ -1,8 +1,10 @@ from pricing.pricing import ( PricingProgram ) +from write_pattern import write_pattern_xlsx from ahserver.serverenv import ServerEnv def load_pricing(): env = ServerEnv() + env.write_patten = PricingProgram.write_patten env.calculate_prices = PricingProgram.pricing diff --git a/pricing/pricing.py b/pricing/pricing.py index 361d65e..eb184d7 100644 --- a/pricing/pricing.py +++ b/pricing/pricing.py @@ -4,46 +4,66 @@ from ahserver.serverenv import ServerEnv from sqlor.dbpools import DBPools, get_sor_context from appPublic.log import debug, exception from appPublic.dictObject import DictObject - +from .write_pattern import write_pattern_xlsx 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 +在pricing_program的pricing_spec表中定义定价的数据字段 +遵循一下规格: +字典结构,key是字段名,需定义字段的type(类型),label(标题),value_mode(值方式)(可选),options(可选项)(可选) +必须要有一个price字段,其type: float -视频定价 -fields: - resolution: - type: str - label: 分辨率 - value_mode: - - between - - in - - = - - > - - >= - - < - - <= +value_mode 有下列可能的取值 +between # 定价表中此字段以如此格式给出: + # "小值 ~ 大值", "~"的前面或后面可以加"=", + # 表示含小值,或含大值 +in # 定价表中此字段值有如下格式:值1 值2 ... += # 缺省,给定单一值 +> # +>= +< +<= - duration: - type: int - label: 时长 - audio: - type: boolean - label: 音频 +例子(vidu定价字段): +''' +model: + type: str + label: "模型" + options: + - "viduq3-pro" + - "viduq3-turbo" + +resolution: + type: str + label: "分辨率" + options: + - "1024p" + - "720p" + - "540p" + +duration: + type: int # 建议改为 int 或 str,times 不是标准类型 + label: "时长" + # 如果时长也有选项,需要补全,例如: + # options: + # - 5 + # - 10 + +off_peak: + type: int # 建议改为 int 或 str,因为值是 0 和 1 + label: "错峰执行" + options: + - off_peak # 正常时段 + - normal # 错峰 +price: + type: float + label: 单价 +''' + +pricing_program_timing表中的pricing_data字段的数据是一个只有一个属性"pricings"的字典 +其值为定价条目列表,每个定价条目是个字典,key值为pricing_spec字段定义的字段, pricings: - resolution: 480p duration: 4 @@ -81,11 +101,8 @@ pricings: - resolution: 720p duration: 12 audio: true - - """ -""" typefuncs = { 'int': int, 'float': float @@ -139,6 +156,22 @@ def check_value(field, spec_value, data_value): return x class PricingProgram: + @staticmethod + async def load_pricing(ppid, webpath_xlsx): + pass + @staticmethod + async def write_patten(request, ppid): + async with get_sor_context(request._run_ns, 'pricing') as sor: + env = request._run_ns + recs = await sor.R('pricing_program', {'id': ppid}) + if not recs: + debug(f'id={ppid} pricing_program not found') + r = recs[0] + PricingProgram.pp_db2app(r) + x = [ DictObject(**f) for f in r.pricing_spec ] + webpath = env.quote(write_pattern_xlsx(x)) + return entire_url(f'/idfile?path={webpath}') + @staticmethod def pp_db2app(pp): try: diff --git a/pricing/test.xlsx b/pricing/test.xlsx new file mode 100644 index 0000000..77b092a Binary files /dev/null and b/pricing/test.xlsx differ diff --git a/pricing/write_pattern.py b/pricing/write_pattern.py new file mode 100644 index 0000000..4786783 --- /dev/null +++ b/pricing/write_pattern.py @@ -0,0 +1,112 @@ +import yaml +from openpyxl import Workbook +from openpyxl import load_workbook +from openpyxl.worksheet.datavalidation import DataValidation +from appPublic.dictObject import DictObject +from appPublic.uniqueID import getID +from ahserver.filestorage import FileStorage + +def create_colnames(): + r = {} + fls = ['', 'A', 'B'] + i = 1 + for fl in fls: + for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ": + r[f'{fl}{c}'] = i + i = i + 1 + return r + +colnames = create_colnames() +reverse_colnames = {v:k for k,v in colnames.items()} + +def write_pattern_xlsx(fields: dict) -> str: + wb = Workbook() + ws_data = wb.active + hidden = wb.create_sheet('dict') + hidden.sheet_status = 'hidden' + # 3. 写入表头 + headers = [] + c = 1 + opt_id = 0 + for f in fields.values(): + ws_data.cell(row=1, column=c, value=f.label or f.name) + if f.options: + create_options(ws_data, c, hidden, opt_id, f.options) + opt_id = opt_id + 1 + c += 1 + fs = FileStorage() + fp = fs._name2path(f'pricing_{getID}.xlsx') + wb.save(fp) + webpath = fs.webpath(fp) + return webpath + +def create_options(ws, dcol, sheet, opt_id, options): + r = 2 + vc = opt_id + 1 + for v in options: + sheet.cell(row=r, column=vc, value=v) + r = r + 1 + colname = reverse_colnames[vc] + dv = DataValidation(type="list", + formula1=f'dict!${colname}$1:${colname}$4', + allow_blank=True) + dv.error = '请选择下拉菜单中的有效职位。' + dv.errorTitle = '输入无效' + ws.add_data_validation(dv) + cn = reverse_colnames[dcol] + dv.add(f'{cn}2:{cn}1048576') + +def load_xlsx_pricing(xlsxpath): + wb = load_workbook(xlsxpath) + ws = wb.active + d = [] + for row in ws.iter_rows(min_row=2, values_only=True): + r = {} + for c, cell in enumerate(row): + r.update({ws.cell(row=1, column=c+1).value:cell}) + d.append(r) + print(d) + return d + +if __name__ == '__main__': + fields_str = """model: + type: str + label: "模型" + options: + - "viduq3-pro" + - "viduq3-turbo" + +resolution: + type: str + label: "分辨率" + options: + - "1024p" + - "720p" + - "540p" + +duration: + type: int # 建议改为 int 或 str,times 不是标准类型 + label: "时长" + # 如果时长也有选项,需要补全,例如: + # options: + # - 5 + # - 10 + +off_peak: + type: int # 建议改为 int 或 str,因为值是 0 和 1 + label: "错峰执行" + options: + - off_peak # 正常时段 + - normal # 错峰 +price: + type: float + label: 单价 + +""" + """ + fields = DictObject(**yaml.safe_load(fields_str)) + print(f'{fields=}, {type(fields)=}') + write_pattern_xlsx(fields) + """ + load_xlsx_pricing('./test.xlsx') +