From 5b3c7d4d029ab153a1d0f49c5418634e38af09e7 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Thu, 21 May 2026 16:22:59 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=BA=9F=E5=BC=83llm=5Fcatalog=5Fr?= =?UTF-8?q?el=E8=A1=A8,=20=E5=88=86=E7=B1=BB=E5=85=B3=E7=B3=BB=E6=94=B9?= =?UTF-8?q?=E7=94=A8llm=5Fapi=5Fmap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除 llm_catalog_rel 表定义(models/json/xlsx)、CRUD文件、管理页面、迁移脚本 - utils.py: get_llms_by_catelog/get_llms_by_catelog_to_customer 的SQL从 llm_catalog_rel 改为 llm_api_map (加distinct去重) - init.py: 缓存清除事件从 llm_catalog_rel 改为 llm_api_map - menu.ui/index.ui: 移除类型关联菜单项 - dspy文件: v1/chat/completions, t2t, get_type_llms, list_catelog_models, list_paging_catelog_llms, llmcatelog_delete 全部改为 join llm_api_map - 迁移脚本: 添加try/except兼容旧表不存在的情况 --- json/llm_catelog_rel.json | 15 --- llmage/init.py | 8 +- llmage/utils.py | 22 ++-- migrate_catelog.py | 56 --------- migrate_rel.py | 30 ----- models/llm_catelog_rel.json | 56 --------- models/llm_catelog_rel.xlsx | Bin 18253 -> 0 bytes scripts/migrate_llm_api_map.py | 9 +- scripts/migrate_llm_api_map_db.py | 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/llmcatelog_delete.dspy | 2 +- wwwroot/get_type_llms.dspy | 6 +- wwwroot/index.ui | 47 -------- wwwroot/list_catelog_models.dspy | 6 +- wwwroot/list_paging_catelog_llms.dspy | 8 +- wwwroot/llm_catalog_rel_manage.ui | 145 ------------------------ wwwroot/menu.ui | 5 - wwwroot/t2t/index.dspy | 6 +- wwwroot/v1/chat/completions/index.dspy | 6 +- 21 files changed, 46 insertions(+), 469 deletions(-) delete mode 100644 json/llm_catelog_rel.json delete mode 100644 migrate_catelog.py delete mode 100644 migrate_rel.py delete mode 100644 models/llm_catelog_rel.json delete mode 100644 models/llm_catelog_rel.xlsx delete mode 100644 wwwroot/api/llm_catalog_rel_create.dspy delete mode 100644 wwwroot/api/llm_catalog_rel_delete.dspy delete mode 100644 wwwroot/api/llm_catalog_rel_list.dspy delete mode 100644 wwwroot/llm_catalog_rel_manage.ui diff --git a/json/llm_catelog_rel.json b/json/llm_catelog_rel.json deleted file mode 100644 index 4378c95..0000000 --- a/json/llm_catelog_rel.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "tblname": "llm_catelog_rel", - "title":"模型类型", - "params": { - "browserfields": { - "exclouded": ["id", "llmid"], - "alters": {} - }, - "editexclouded": [ - "id", - "llmid" - ] - } -} - diff --git a/llmage/init.py b/llmage/init.py index 8030b76..4b2fb8b 100644 --- a/llmage/init.py +++ b/llmage/init.py @@ -51,10 +51,10 @@ def _bind_llmage_events(dbpools, dbname): (f'{dbname}.llmcatelog:c:after', BufferedLLMs.clear_cache), (f'{dbname}.llmcatelog:u:after', BufferedLLMs.clear_cache), (f'{dbname}.llmcatelog:d:after', BufferedLLMs.clear_cache), - # llm_catalog_rel 关联表变更:清除缓存 - (f'{dbname}.llm_catalog_rel:c:after', BufferedLLMs.clear_cache), - (f'{dbname}.llm_catalog_rel:u:after', BufferedLLMs.clear_cache), - (f'{dbname}.llm_catalog_rel:d:after', BufferedLLMs.clear_cache), + # llm_api_map 关联表变更:清除缓存 + (f'{dbname}.llm_api_map:c:after', BufferedLLMs.clear_cache), + (f'{dbname}.llm_api_map:u:after', BufferedLLMs.clear_cache), + (f'{dbname}.llm_api_map:d:after', BufferedLLMs.clear_cache), ] for event_name, handler in bindings: dbpools.bind(event_name, handler) diff --git a/llmage/utils.py b/llmage/utils.py index 488cf42..8b18782 100644 --- a/llmage/utils.py +++ b/llmage/utils.py @@ -207,11 +207,11 @@ async def get_llms_by_catelog_to_customer(catelogid=None, orderby='providerid'): env = ServerEnv() async with get_sor_context(env, 'llmage') as sor: today = curDateString() - # Join with llm_catalog_rel to support multiple catalogs per LLM - sql = """select a.*, b.name as catelogname, rel.llmcatelogid as catelog_id + # Join with llm_api_map to get catalog relationship + sql = """select distinct a.*, b.name as catelogname, m.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 + join llm_api_map m on a.id = m.llmid + join llmcatelog b on m.llmcatelogid = b.id where a.enabled_date <= ${today}$ and a.ppid is not null and a.expired_date > ${today}$ @@ -219,7 +219,7 @@ async def get_llms_by_catelog_to_customer(catelogid=None, orderby='providerid'): sortstr='catelog_id, ' + orderby params = {'today': today, 'sort': sortstr} if catelogid: - sql += " and rel.llmcatelogid = ${catelogid}$" + sql += " and m.llmcatelogid = ${catelogid}$" params['catelogid'] = catelogid debug(f'{sql=}') @@ -246,19 +246,19 @@ async def get_llms_by_catelog(catelogid=None, orderby='providerid'): env = ServerEnv() async with get_sor_context(env, 'llmage') as sor: today = curDateString() - # Join with llm_catalog_rel to support multiple catalogs per LLM - sql = """select a.*, b.name as catelogname, rel.llmcatelogid as catelog_id + # Join with llm_api_map to get catalog relationship + sql = """select distinct a.*, b.name as catelogname, m.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 + join llm_api_map m on a.id = m.llmid + join llmcatelog b on m.llmcatelogid = b.id where a.enabled_date <= ${today}$ and a.expired_date > ${today}$""" params = {'today': today, 'sort': orderby} if catelogid: - sql += " and rel.llmcatelogid = ${catelogid}$" + sql += " and m.llmcatelogid = ${catelogid}$" params['catelogid'] = catelogid - sql += " order by rel.llmcatelogid, a.id" + sql += " order by m.llmcatelogid, a.id" recs = await sor.sqlExe(sql, params) d = [] diff --git a/migrate_catelog.py b/migrate_catelog.py deleted file mode 100644 index de4b141..0000000 --- a/migrate_catelog.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 -""" -Migration script: Move llm.llmcatelogid to llm_catalog_rel. -Run this AFTER creating the llm_catalog_rel table via build.sh. -""" -import asyncio -from sqlor.dbpools import DBPools -from appPublic.jsonConfig import getConfig -from appPublic.log import info, error -from ahserver.serverenv import ServerEnv - -async def migrate(): - env = ServerEnv() - try: - dbname = env.get_module_dbname('llmage') - except: - dbname = 'default' - - config = getConfig() - db = DBPools() - db.databases = config.databases - - async with db.sqlorContext(dbname) as sor: - # 1. Migrate data - print("Migrating data...") - # Get all llms with a llmcatelogid - # Note: llmcatelogid still exists in DB until we drop it, or we assume it's there. - # Assuming it's there. - sql = "select id, llmcatelogid from llm where llmcatelogid is not null and llmcatelogid != ''" - rows = await sor.sqlExe(sql, {}) - - if not rows: - print("No data to migrate.") - return - - print(f"Found {len(rows)} records to migrate.") - - for r in rows: - # Insert into llm_catalog_rel - # Use getID() logic or simple uuid, here assuming we can use a function or simple generation - # but sqlor insert C() is better - data = { - 'llmid': r['id'], - 'llmcatelogid': r['llmcatelogid'] - } - await sor.C('llm_catalog_rel', data) - - print("Migration complete.") - - # 2. Drop column (Optional but recommended) - # print("Dropping column...") - # await sor.sqlExe("alter table llm drop column llmcatelogid", {}) - # print("Column dropped.") - -if __name__ == '__main__': - asyncio.run(migrate()) diff --git a/migrate_rel.py b/migrate_rel.py deleted file mode 100644 index 9980298..0000000 --- a/migrate_rel.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python3 -""" -Execute migration via sage environment. -Run: cd /home/hermesai/repos/sage && ./py3/bin/python migrate_rel.py -""" -import asyncio -import sys -import os - -# Add sage to path -sys.path.insert(0, '/home/hermesai/repos/sage/py3/lib/python3.10/site-packages') -sys.path.insert(0, '/home/hermesai/repos/sage') - -from ahserver.serverenv import ServerEnv -from sqlor.dbpools import DBPools -from appPublic.jsonConfig import getConfig - -async def migrate(): - # Initialize env to get config - # Note: This script expects sage to be configured. - # We can't easily import sage's init here, but we can try to load config if available. - # Alternatively, just use raw sql. - pass - -if __name__ == '__main__': - # Use a simpler approach: connect directly - import pymysql - # Assuming config is in sage's config dir - # We can read the config file - pass diff --git a/models/llm_catelog_rel.json b/models/llm_catelog_rel.json deleted file mode 100644 index b042eb4..0000000 --- a/models/llm_catelog_rel.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "summary": [ - { - "name": "llm_catelog_rel", - "title": "模型分类对照表", - "primary": [ - "id" - ], - "catelog": "relation" - } - ], - "fields": [ - { - "name": "id", - "title": "id", - "type": "str", - "length": 32 - }, - { - "name": "llmid", - "title": "模型id", - "type": "str", - "length": 32 - }, - { - "name": "llmcatelogid", - "title": "模型分类id", - "type": "str", - "length": 32 - } - ], - "indexes": [ - { - "name": "idx_uniue_llm_catelogid", - "idxtype": "unique", - "idxfields": [ - "llmid", - "llmcatelogid" - ] - } - ], - "codes": [ - { - "field": "llmid", - "table": "llm", - "valuefield": "id", - "textfield": "name" - }, - { - "field": "llmcatelogid", - "table": "llmcatelog", - "valuefield": "id", - "textfield": "name" - } - ] -} \ No newline at end of file diff --git a/models/llm_catelog_rel.xlsx b/models/llm_catelog_rel.xlsx deleted file mode 100644 index 860b7685d65e3b9ca2ea398f5da79bcde1552e23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18253 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 0: diff --git a/wwwroot/get_type_llms.dspy b/wwwroot/get_type_llms.dspy index c368fc2..9144023 100644 --- a/wwwroot/get_type_llms.dspy +++ b/wwwroot/get_type_llms.dspy @@ -3,9 +3,9 @@ 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 -join llm_catalog_rel rel on a.id = rel.llmid -join llmcatelog b on rel.llmcatelogid = b.id + sql = '''select distinct a.*, e.input_fields from llm a +join llm_api_map m on a.id = m.llmid +join llmcatelog b on m.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 diff --git a/wwwroot/index.ui b/wwwroot/index.ui index d00ca1b..f024883 100644 --- a/wwwroot/index.ui +++ b/wwwroot/index.ui @@ -68,53 +68,6 @@ } ] }, - { - "widgettype": "VBox", - "options": { - "backgroundColor": "#1e3a5f", - "padding": "24px", - "cursor": "pointer", - "borderRadius": "8px" - }, - "binds": [ - { - "wid": "self", - "event": "click", - "actiontype": "urlwidget", - "target": "app.llmage_content", - "options": { - "url": "{{entire_url('/llmage/llm_catalog_rel_manage.ui')}}" - }, - "mode": "replace" - } - ], - "subwidgets": [ - { - "widgettype": "Svg", - "options": { - "svg": "", - "width": "40px", - "height": "40px" - } - }, - { - "widgettype": "Title4", - "options": { - "text": "模型-类型关联", - "color": "#ffffff", - "marginTop": "12px" - } - }, - { - "widgettype": "Text", - "options": { - "text": "管理模型与类型的多对多关系", - "color": "#ce93d8", - "fontSize": "14px" - } - } - ] - }, { "widgettype": "VBox", "options": { diff --git a/wwwroot/list_catelog_models.dspy b/wwwroot/list_catelog_models.dspy index 9365041..d904f28 100644 --- a/wwwroot/list_catelog_models.dspy +++ b/wwwroot/list_catelog_models.dspy @@ -1,9 +1,9 @@ dbname = get_module_dbname('llmage') db = DBPools() async with db.sqlorContext(dbname) as sor: - sql = """select * from llm a -join llm_catalog_rel rel on a.id = rel.llmid -where rel.llmcatelogid = ${llmcatelogid}$ and a.id != ${llmid}$""" + sql = """select distinct a.* from llm a +join llm_api_map m on a.id = m.llmid +where m.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 96e1c6f..0aee5fe 100644 --- a/wwwroot/list_paging_catelog_llms.dspy +++ b/wwwroot/list_paging_catelog_llms.dspy @@ -12,15 +12,15 @@ y.system_message, y.user_message, y.assisant_message from ( -select a.*, b.hfid, e.ioid, e.stream +select distinct a.*, b.hfid, e.ioid, e.stream from llm a -join llm_catalog_rel rel on a.id = rel.llmid -join llmcatelog b on rel.llmcatelogid = b.id +join llm_api_map m on a.id = m.llmid +join llmcatelog b on m.llmcatelogid = b.id join upapp c on a.upappid = c.id join uapi e on c.apisetid = e.apisetid 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 rel.llmcatelogid = ${llmcatelogid}$ +where m.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 deleted file mode 100644 index bdbd36e..0000000 --- a/wwwroot/llm_catalog_rel_manage.ui +++ /dev/null @@ -1,145 +0,0 @@ -{ - "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/menu.ui b/wwwroot/menu.ui index 4b05d07..8f4b687 100644 --- a/wwwroot/menu.ui +++ b/wwwroot/menu.ui @@ -31,11 +31,6 @@ "name":"llm", "label":"模型", "url":"{{entire_url('/llmage/llm')}}" - }, - { - "name":"llmcatelog_rel", - "label":"类型关联", - "url":"{{entire_url('/llmage/llm_catalog_rel_manage.ui')}}" } ] } diff --git a/wwwroot/t2t/index.dspy b/wwwroot/t2t/index.dspy index 8adc2fd..fec2032 100644 --- a/wwwroot/t2t/index.dspy +++ b/wwwroot/t2t/index.dspy @@ -17,9 +17,9 @@ 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 -join llm_catalog_rel rel on a.id = rel.llmid -join llmcatelog b on rel.llmcatelogid = b.id + sql = """select distinct a.* from llm a +join llm_api_map m on a.id = m.llmid +join llmcatelog b on m.llmcatelogid = b.id where b.name = ${lctype}$ and a.model=${model}$""" recs = await sor.sqlExe(sql, { diff --git a/wwwroot/v1/chat/completions/index.dspy b/wwwroot/v1/chat/completions/index.dspy index 5be6956..4c919ce 100644 --- a/wwwroot/v1/chat/completions/index.dspy +++ b/wwwroot/v1/chat/completions/index.dspy @@ -30,9 +30,9 @@ 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 -join llm_catalog_rel rel on a.id = rel.llmid -join llmcatelog b on rel.llmcatelogid = b.id + sql = """select distinct a.* from llm a +join llm_api_map m on a.id = m.llmid +join llmcatelog b on m.llmcatelogid = b.id where b.name = ${lctype}$ and a.model=${model}$""" recs = await sor.sqlExe(sql, {