diff --git a/json/llm_api_profile_list.json b/json/llm_api_profile_list.json index 069135b..5ca3209 100644 --- a/json/llm_api_profile_list.json +++ b/json/llm_api_profile_list.json @@ -6,6 +6,7 @@ "browserfields": { "exclouded": [ "id", + "headers", "request_template", "response_template", "param_schema" @@ -28,6 +29,12 @@ "dataurl": "{{entire_url('../api/get_llm_status_options.dspy')}}", "valueField": "value", "textField": "text" + }, + "path": { + "placeholder": "请求路径(相对端点base_url),如 /chat/completions" + }, + "headers": { + "placeholder": "请求头JSON,如 {\"Authorization\": \"Bearer {{api_key}}\", \"Content-Type\": \"application/json\"}" } } }, diff --git a/json/llm_model_list.json b/json/llm_model_list.json index 62fda2f..0e2d714 100644 --- a/json/llm_model_list.json +++ b/json/llm_model_list.json @@ -5,7 +5,8 @@ "sortby": "name", "browserfields": { "exclouded": [ - "id" + "id", + "query_profile_ids" ], "alters": { "vendor_id": { @@ -37,6 +38,16 @@ "dataurl": "{{entire_url('../api/get_llm_ppid_options.dspy')}}", "valueField": "value", "textField": "text" + }, + "sync_mode": { + "uitype": "code", + "data": [ + {"value": "sync", "text": "同步"}, + {"value": "async", "text": "异步(提交后轮询)"} + ] + }, + "query_profile_ids": { + "placeholder": "后续步骤模板ID的JSON数组(异步模型:提交后顺序执行 查询→[下载]),如 [\"模板ID1\",\"模板ID2\"]" } } }, @@ -46,9 +57,9 @@ "updated_at" ], "editable": { - "new_data_url": "{{entire_url('./add_llm_model.dspy')}}", - "update_data_url": "{{entire_url('./update_llm_model.dspy')}}", - "delete_data_url": "{{entire_url('./delete_llm_model.dspy')}}" + "new_data_url": "{{entire_url('../api/add_llm_model.dspy')}}", + "update_data_url": "{{entire_url('../api/update_llm_model.dspy')}}", + "delete_data_url": "{{entire_url('../api/delete_llm_model.dspy')}}" } } } diff --git a/models/llm_api_profile.json b/models/llm_api_profile.json index 3b1742a..07da2a0 100644 --- a/models/llm_api_profile.json +++ b/models/llm_api_profile.json @@ -39,6 +39,17 @@ "nullable": "no", "default": "'t2t'" }, + { + "name": "path", + "title": "请求路径", + "type": "str", + "length": 200 + }, + { + "name": "headers", + "title": "请求头(JSON)", + "type": "text" + }, { "name": "request_template", "title": "请求模板(Jinja2)", diff --git a/models/llm_model.json b/models/llm_model.json index 54072a2..d69ee4e 100644 --- a/models/llm_model.json +++ b/models/llm_model.json @@ -65,6 +65,11 @@ "type": "str", "length": 32 }, + { + "name": "query_profile_ids", + "title": "后续步骤模板链(JSON)", + "type": "text" + }, { "name": "ppid", "title": "定价项目ID", diff --git a/mysql.ddl.sql b/mysql.ddl.sql index a602a19..2c5f1b9 100644 --- a/mysql.ddl.sql +++ b/mysql.ddl.sql @@ -41,6 +41,7 @@ CREATE TABLE IF NOT EXISTS llm_model ( `capability` varchar(20) NOT NULL DEFAULT 't2t' comment '能力类型', `sync_mode` varchar(10) NOT NULL DEFAULT 'sync' comment '同步性', `profile_id` varchar(32) comment '适配模板ID', + `query_profile_ids` text comment '后续步骤模板链(JSON数组,异步模型提交后顺序执行:查询/下载)', `ppid` varchar(32) comment '定价项目ID(pricing_program)', `price_input` decimal(12,6) NOT NULL DEFAULT 0 comment '输入单价(元/千token)', `price_output` decimal(12,6) NOT NULL DEFAULT 0 comment '输出单价(元/千token)', @@ -62,6 +63,8 @@ CREATE TABLE IF NOT EXISTS llm_api_profile ( `name` varchar(100) NOT NULL comment '模板名称', `protocol` varchar(20) NOT NULL comment '协议类型', `capability` varchar(20) NOT NULL DEFAULT 't2t' comment '能力类型', + `path` varchar(200) comment '请求路径(相对端点base_url,如/chat/completions)', + `headers` text comment '请求头(JSON,含认证头模板)', `request_template` text comment '请求模板(Jinja2)', `response_template` text comment '响应模板(Jinja2)', `param_schema` text comment '参数Schema(bricks input_fields)', diff --git a/pipeline_llm/init.py b/pipeline_llm/init.py index c659185..c107db2 100644 --- a/pipeline_llm/init.py +++ b/pipeline_llm/init.py @@ -277,6 +277,15 @@ async def create_llm_model(params_kw): if dp.strip(): json.loads(dp) # 校验合法 data['default_params'] = dp + # 后续步骤模板链:JSON 数组校验 + qp = data.get('query_profile_ids', '') or '' + if isinstance(qp, (list, dict)): + qp = json.dumps(qp, ensure_ascii=False) + if qp.strip(): + ql = json.loads(qp) + if not isinstance(ql, list): + raise ValueError('query_profile_ids 必须是 JSON 数组') + data['query_profile_ids'] = qp data['id'] = getID() db, dbname = _get_sor() async with db.sqlorContext(dbname) as sor: @@ -303,6 +312,15 @@ async def update_llm_model(params_kw): if dp.strip(): json.loads(dp) data['default_params'] = dp + if 'query_profile_ids' in data: + qp = data.get('query_profile_ids', '') or '' + if isinstance(qp, (list, dict)): + qp = json.dumps(qp, ensure_ascii=False) + if qp.strip(): + ql = json.loads(qp) + if not isinstance(ql, list): + raise ValueError('query_profile_ids 必须是 JSON 数组') + data['query_profile_ids'] = qp db, dbname = _get_sor() async with db.sqlorContext(dbname) as sor: await sor.U('llm_model', data) diff --git a/wwwroot/api/add_llm_model.dspy b/wwwroot/api/add_llm_model.dspy new file mode 100644 index 0000000..0fc2c96 --- /dev/null +++ b/wwwroot/api/add_llm_model.dspy @@ -0,0 +1,5 @@ +# add_llm_model.dspy — 薄封装:走模块 helper(注册名唯一+JSON字段校验) +r = json.loads(await create_llm_model(dict(params_kw or {}))) +if r.get('success'): + return {"widgettype": "Message", "options": {"title": "Success", "message": r.get('message') or 'ok', "timeout": 3, "cwidth": 16, "cheight": 9}} +return {"widgettype": "Error", "options": {"title": "Error", "message": r.get('message') or 'failed', "timeout": 3, "cwidth": 16, "cheight": 9}} diff --git a/wwwroot/api/delete_llm_model.dspy b/wwwroot/api/delete_llm_model.dspy new file mode 100644 index 0000000..64ab21f --- /dev/null +++ b/wwwroot/api/delete_llm_model.dspy @@ -0,0 +1,5 @@ +# delete_llm_model.dspy — 薄封装:走模块 helper(被组织策略引用时禁止删除) +r = json.loads(await delete_llm_model(dict(params_kw or {}))) +if r.get('success'): + return {"widgettype": "Message", "options": {"title": "Success", "message": r.get('message') or 'ok', "timeout": 3, "cwidth": 16, "cheight": 9}} +return {"widgettype": "Error", "options": {"title": "Error", "message": r.get('message') or 'failed', "timeout": 3, "cwidth": 16, "cheight": 9}} diff --git a/wwwroot/api/update_llm_model.dspy b/wwwroot/api/update_llm_model.dspy new file mode 100644 index 0000000..5aa5cca --- /dev/null +++ b/wwwroot/api/update_llm_model.dspy @@ -0,0 +1,5 @@ +# update_llm_model.dspy — 薄封装:走模块 helper(JSON字段校验) +r = json.loads(await update_llm_model(dict(params_kw or {}))) +if r.get('success'): + return {"widgettype": "Message", "options": {"title": "Success", "message": r.get('message') or 'ok', "timeout": 3, "cwidth": 16, "cheight": 9}} +return {"widgettype": "Error", "options": {"title": "Error", "message": r.get('message') or 'failed', "timeout": 3, "cwidth": 16, "cheight": 9}}