From 6cc3986a2dcf44a642e4bc7f7b02c285a7d54eac Mon Sep 17 00:00:00 2001 From: yumoqing Date: Sat, 16 May 2026 21:31:19 +0800 Subject: [PATCH] feat: support multi-catalog for LLMs - Create llm_catalog_rel model for one-to-many relationship - Remove llmcatelogid from llm model - Update SQL queries in utils.py and dspy files to use join - Add maintenance UI (llm_catalog_rel_manage.ui) and API endpoints - Filter options by user's orgid --- llmage/utils.py | 30 +++-- models/llm.xlsx | Bin 17344 -> 10142 bytes models/llm_catalog_rel.xlsx | 11 ++ wwwroot/api/llm_catalog_rel_create.dspy | 32 ++++++ wwwroot/api/llm_catalog_rel_delete.dspy | 20 ++++ wwwroot/api/llm_catalog_rel_list.dspy | 25 ++++ wwwroot/api/llm_catelog_options.dspy | 30 +++++ wwwroot/get_type_llms.dspy | 16 +-- wwwroot/list_catelog_models.dspy | 4 +- wwwroot/list_paging_catelog_llms.dspy | 14 +-- wwwroot/llm_catalog_rel_manage.ui | 145 ++++++++++++++++++++++++ wwwroot/llm_dialog.ui | 1 - wwwroot/t2t/index.dspy | 9 +- wwwroot/v1/chat/completions/index.dspy | 9 +- 14 files changed, 310 insertions(+), 36 deletions(-) create mode 100644 models/llm_catalog_rel.xlsx create mode 100644 wwwroot/api/llm_catalog_rel_create.dspy create mode 100644 wwwroot/api/llm_catalog_rel_delete.dspy create mode 100644 wwwroot/api/llm_catalog_rel_list.dspy create mode 100644 wwwroot/api/llm_catelog_options.dspy create mode 100644 wwwroot/llm_catalog_rel_manage.ui diff --git a/llmage/utils.py b/llmage/utils.py index 78a8cb0..61db282 100644 --- a/llmage/utils.py +++ b/llmage/utils.py @@ -141,29 +141,37 @@ async def get_llmcatelogs(): return [] -async def get_llms_by_catelog(): +async def get_llms_by_catelog(catelogid=None): env = ServerEnv() async with get_sor_context(env, 'llmage') as sor: today = curDateString() - sql = """select a.*, b.name as catelogname from llm a, llmcatelog b -where a.llmcatelogid = b.id - and enabled_date <= ${today}$ - and expired_date > ${today}$ - order by a.llmcatelogid, a.id - """ - recs = await sor.sqlExe(sql, {'today': today}) + # Join with llm_catalog_rel to support multiple catalogs per LLM + sql = """select a.*, b.name as catelogname, rel.llmcatelogid as catelog_id + from llm a + join llm_catalog_rel rel on a.id = rel.llmid + join llmcatelog b on rel.llmcatelogid = b.id + where a.enabled_date <= ${today}$ + and a.expired_date > ${today}$""" + params = {'today': today} + if catelogid: + sql += " and rel.llmcatelogid = ${catelogid}$" + params['catelogid'] = catelogid + + sql += " order by rel.llmcatelogid, a.id" + + recs = await sor.sqlExe(sql, params) d = [] cid = '' x = None for r in recs: - if cid != r.llmcatelogid: + if cid != r.catelog_id: x = { - 'catelogid': r.llmcatelogid, + 'catelogid': r.catelog_id, 'catelogname': r.catelogname, 'llms': [r] } d.append(x) - cid = r.llmcatelogid + cid = r.catelog_id else: x['llms'].append(r) return d diff --git a/models/llm.xlsx b/models/llm.xlsx index 5b849abc8596bcd85b73e37f829b8adeeb9d9c54..68bcc0d608d41556015d2f0e52ebc9962f6b9753 100644 GIT binary patch literal 10142 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∓ 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 iFMz&JzrKV2A0I6*1qN^tKtM= ${today}$ + and ownerid = ${ownerid}$ + order by name""" + llms = await sor.sqlExe(llms_sql, {'today': today, 'ownerid': user_orgid}) + result['data']['llms'] = [{'id': r['id'], 'text': r['name']} for r in (llms or [])] + + # Get all catalogs (assuming catalogs are global or filtered similarly if needed) + catelogs = await sor.sqlExe("select id, name from llmcatelog order by name", {}) + result['data']['catelogs'] = [{'id': r['id'], 'text': r['name']} for r in (catelogs or [])] + + result['success'] = True + +except Exception as e: + result['error'] = str(e) + +return json.dumps(result, ensure_ascii=False, default=str) diff --git a/wwwroot/get_type_llms.dspy b/wwwroot/get_type_llms.dspy index b92c861..c368fc2 100644 --- a/wwwroot/get_type_llms.dspy +++ b/wwwroot/get_type_llms.dspy @@ -3,16 +3,16 @@ lt = '文生视频' if params_kw.type in ['文生视频', '参考生视频', '图生视频']: lt = params_kw.type async with get_sor_context(request._run_ns, 'llmage') as sor: - sql = '''select a.*, e.input_fields from llm a, llmcatelog b, upapp c, uapi d, uapiio e -where a.llmcatelogid = b.id - and a.upappid = c.id - and c.apisetid = d.apisetid - and a.apiname = d.name - and d.ioid = e.id + sql = '''select a.*, e.input_fields from llm a +join llm_catalog_rel rel on a.id = rel.llmid +join llmcatelog b on rel.llmcatelogid = b.id +join upapp c on a.upappid = c.id +join uapi d on c.apisetid = d.apisetid and a.apiname = d.name +join uapiio e on d.ioid = e.id +where b.name=${lt}$ and a.enabled_date <= ${biz_date}$ and ${biz_date}$ < a.expired_date - and ppid is not NULL - and b.name=${lt}$''' + and ppid is not NULL''' biz_date = await get_business_date(sor) recs = await sor.sqlExe(sql, { 'biz_date': biz_date, diff --git a/wwwroot/list_catelog_models.dspy b/wwwroot/list_catelog_models.dspy index e07f5f4..9365041 100644 --- a/wwwroot/list_catelog_models.dspy +++ b/wwwroot/list_catelog_models.dspy @@ -1,7 +1,9 @@ dbname = get_module_dbname('llmage') db = DBPools() async with db.sqlorContext(dbname) as sor: - sql = """select * from llm where llmcatelogid = ${llmcatelogid}$ and id != ${llmid}$""" + sql = """select * from llm a +join llm_catalog_rel rel on a.id = rel.llmid +where rel.llmcatelogid = ${llmcatelogid}$ and a.id != ${llmid}$""" ns = params_kw.copy() recs = await sor.sqlExe(sql, ns) for r in recs.get('rows', []): diff --git a/wwwroot/list_paging_catelog_llms.dspy b/wwwroot/list_paging_catelog_llms.dspy index 6298cbc..8c3f106 100644 --- a/wwwroot/list_paging_catelog_llms.dspy +++ b/wwwroot/list_paging_catelog_llms.dspy @@ -13,15 +13,15 @@ y.user_message, y.assisant_message from ( select a.*, b.hfid, e.ioid, e.stream -from llm a, llmcatelog b,upapp c, uapiset d, uapi e -where a.llmcatelogid = b.id - and a.upappid = c.id - and c.apisetid = d.id - and e.apisetid = d.id - and a.apiname = e.name +from llm a +join llm_catalog_rel rel on a.id = rel.llmid +join llmcatelog b on rel.llmcatelogid = b.id +join upapp c on a.upappid = c.id +join uapiset d on c.apisetid = d.id +join uapi e on e.apisetid = d.id and a.apiname = e.name ) x left join historyformat y on x.hfid = y.id left join uapiio z on x.ioid = z.id -where llmcatelogid = ${llmcatelogid}$ +where rel.llmcatelogid = ${llmcatelogid}$ and x.id != ${llmid}$ """ ns = params_kw.copy() diff --git a/wwwroot/llm_catalog_rel_manage.ui b/wwwroot/llm_catalog_rel_manage.ui new file mode 100644 index 0000000..bdbd36e --- /dev/null +++ b/wwwroot/llm_catalog_rel_manage.ui @@ -0,0 +1,145 @@ +{ + "widgettype": "VBox", + "options": { + "width": "100%", + "height": "100%", + "spacing": 16 + }, + "subwidgets": [ + { + "widgettype": "Title2", + "options": { + "text": "LLM 目录关联管理", + "halign": "left" + } + }, + { + "widgettype": "VBox", + "options": { + "width": "calc(100% - 40px)", + "margin": "0 20px", + "padding": "16px", + "bgcolor": "#f5f5f5", + "spacing": 12 + }, + "subwidgets": [ + { + "widgettype": "Text", + "options": { + "text": "添加新关联", + "fontSize": "16px", + "fontWeight": "bold" + } + }, + { + "widgettype": "Form", + "id": "add_form", + "options": { + "layout": "horizontal", + "cols": 3, + "fields": [ + { + "name": "llmid", + "label": "选择模型", + "uitype": "select", + "dataurl": "{{entire_url('./api/llm_catelog_options.dspy')}}", + "data_field": "llms", + "placeholder": "请选择模型" + }, + { + "name": "llmcatelogid", + "label": "选择目录", + "uitype": "select", + "dataurl": "{{entire_url('./api/llm_catelog_options.dspy')}}", + "data_field": "catelogs", + "placeholder": "请选择目录" + } + ], + "buttons": [ + { + "name": "add_btn", + "label": "添加关联", + "variant": "primary" + } + ] + }, + "binds": [ + { + "wid": "add_btn", + "event": "click", + "actiontype": "urlwidget", + "target": "PopupWindow", + "popup_options": {"archor": "cc", "width": "30%", "height": "20%"}, + "options": { + "url": "{{entire_url('./api/llm_catalog_rel_create.dspy')}}", + "params": { + "llmid": "$[add_form.llmid]$", + "llmcatelogid": "$[add_form.llmcatelogid]$" + } + } + } + ] + } + ] + }, + { + "widgettype": "VBox", + "options": { + "width": "calc(100% - 40px)", + "margin": "0 20px", + "spacing": 12 + }, + "subwidgets": [ + { + "widgettype": "Text", + "options": { + "text": "当前关联列表", + "fontSize": "16px", + "fontWeight": "bold" + } + }, + { + "widgettype": "Tabular", + "id": "rel_table", + "options": { + "width": "100%", + "height": "400px", + "data_url": "{{entire_url('./api/llm_catalog_rel_list.dspy')}}", + "data_method": "GET", + "page_rows": 20, + "row_options": { + "fields": [ + {"name": "llm_name", "title": "模型名称", "width": 200}, + {"name": "catelog_name", "title": "目录名称", "width": 150}, + { + "name": "actions", + "title": "操作", + "width": 100, + "uitype": "button", + "data": [ + {"text": "删除", "event": "delete_rel"} + ] + } + ] + } + }, + "binds": [ + { + "wid": "self", + "event": "delete_rel", + "actiontype": "urlwidget", + "target": "PopupWindow", + "popup_options": {"archor": "cc", "width": "30%", "height": "20%"}, + "options": { + "url": "{{entire_url('./api/llm_catalog_rel_delete.dspy')}}", + "params": { + "id": "$[event.params.id]$" + } + } + } + ] + } + ] + } + ] +} diff --git a/wwwroot/llm_dialog.ui b/wwwroot/llm_dialog.ui index c2efdcd..fc9e007 100644 --- a/wwwroot/llm_dialog.ui +++ b/wwwroot/llm_dialog.ui @@ -22,7 +22,6 @@ "models":[ { "llmid":"{{llm.id}}", - "llmcatelogid":"{{llm.llmcatelogid}}", "response_mode": "{{llm.stream}}", "icon":"{{entire_url('/appbase/show_icon.dspy')}}?id={{llm.iconid}}", "url":"{{entire_url('/llmage/llminference.dspy')}}", diff --git a/wwwroot/t2t/index.dspy b/wwwroot/t2t/index.dspy index 428d7e0..8adc2fd 100644 --- a/wwwroot/t2t/index.dspy +++ b/wwwroot/t2t/index.dspy @@ -17,10 +17,11 @@ if not params_kw.prompt: return json_response(d, status=400) env = request._run_ns async with get_sor_context(env, 'llmage') as sor: - sql = """select a.* from llm a, llmcatelog b -where a.llmcatelogid=b.id - and a.model=${model}$ - and b.name = ${lctype}$""" + sql = """select a.* from llm a +join llm_catalog_rel rel on a.id = rel.llmid +join llmcatelog b on rel.llmcatelogid = b.id +where b.name = ${lctype}$ + and a.model=${model}$""" recs = await sor.sqlExe(sql, { 'lctype': lctype, 'model': params_kw.model or 'qwen3-max' diff --git a/wwwroot/v1/chat/completions/index.dspy b/wwwroot/v1/chat/completions/index.dspy index e806caa..d247ca0 100644 --- a/wwwroot/v1/chat/completions/index.dspy +++ b/wwwroot/v1/chat/completions/index.dspy @@ -30,10 +30,11 @@ if not params_kw.prompt and not params_kw.messages: return json_response(d, status=400) env = request._run_ns async with get_sor_context(env, 'llmage') as sor: - sql = """select a.* from llm a, llmcatelog b -where a.llmcatelogid=b.id - and a.model=${model}$ - and b.name = ${lctype}$""" + sql = """select a.* from llm a +join llm_catalog_rel rel on a.id = rel.llmid +join llmcatelog b on rel.llmcatelogid = b.id +where b.name = ${lctype}$ + and a.model=${model}$""" recs = await sor.sqlExe(sql, { 'lctype': lctype, 'model': params_kw.model or 'qwen3-max'