feat: add model publish/unpublish (上架/下架) functionality

- llm table: add status field (published/unpublished, default unpublished)
- User-facing queries: filter by status='published' in 11 query points:
  - utils.py: get_llms_by_catelog_to_customer, get_llms_by_catelog,
    get_llm, get_llmproviders, get_llms_sort_by_provider
  - v1 endpoints: chat/completions, image/generations, video/generations
  - user pages: t2t, get_type_llms, list_catelog_models,
    list_paging_catelog_llms, llmcheck
- CRUD: status column visible/editable with select dropdown
- Admin CRUD list shows ALL models regardless of status
- Migration SQL: sql/add_status_field.sql (existing models set to published)
This commit is contained in:
yumoqing 2026-05-28 23:42:29 +08:00
parent cb5efd5550
commit d6e4221a7b
14 changed files with 50 additions and 9 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
__pycache__/

View File

@ -10,18 +10,28 @@
{"field": "name", "op": "LIKE", "var": "name_input"},
{"field": "model", "op": "LIKE", "var": "model_input"},
{"field": "providerid", "op": "=", "var": "providerid_input"},
{"field": "upappid", "op": "=", "var": "upappid_input"}
{"field": "upappid", "op": "=", "var": "upappid_input"},
{"field": "status", "op": "=", "var": "status_input"}
]
},
"filter_labels": {
"name_input": "名称",
"model_input": "识别名",
"providerid_input": "供应商",
"upappid_input": "上位系统"
"upappid_input": "上位系统",
"status_input": "上架状态"
},
"browserfields": {
"exclouded": ["id", "ownerid"],
"alters": {
"status": {
"uitype": "select",
"options": [
{"value": "", "text": "全部"},
{"value": "published", "text": "已上架"},
{"value": "unpublished", "text": "已下架"}
]
},
"ppid":{
"dataurl":"{{entire_url('/pricing/get_all_pricing_programs.dspy')}}",
"textField": "name",

View File

@ -154,6 +154,7 @@ async def get_llmproviders():
sql = """select a.providerid, a.iconid, b.orgname
from llm a, organization b
where a.providerid = b.id
and a.status = 'published'
group by a.providerid, a.iconid, b.orgname"""
return await sor.sqlExe(sql, {})
return []
@ -165,6 +166,7 @@ async def get_llms_sort_by_provider():
sql = """select a.*, b.orgname from llm a, organization b
where a.enabled_date <= ${today}$
and a.expired_date > ${today}$
and a.status = 'published'
and a.providerid = b.id
order by a.providerid, a.id
"""
@ -211,6 +213,7 @@ m.ppid
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.status = 'published'
and m.ppid is not null
and a.expired_date > ${today}$
"""
@ -250,6 +253,7 @@ async def get_llms_by_catelog(catelogid=None, orderby='providerid'):
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.status = 'published'
and a.expired_date > ${today}$"""
params = {'today': today, 'sort': orderby}
if catelogid:
@ -311,6 +315,7 @@ and c.id = e.upappid
and m.apiname = e.name
and e.ioid = f.id
and a.id = ${llmid}$
and a.status = 'published'
and a.expired_date > ${today}$
and a.enabled_date <= ${today}$
"""

View File

@ -74,6 +74,14 @@
"length": 20,
"default": 10,
"dec": 2
},
{
"name": "status",
"title": "上架状态",
"type": "str",
"length": 16,
"nullable": "no",
"default": "unpublished"
}
],
"codes": [

11
sql/add_status_field.sql Normal file
View File

@ -0,0 +1,11 @@
-- llmage: 添加模型上架/下架功能
-- 执行此 SQL 后,所有现有模型默认已上架,不影响线上使用
-- 1. 添加 status 字段
ALTER TABLE llm ADD COLUMN `status` VARCHAR(16) NOT NULL DEFAULT 'unpublished' COMMENT '上架状态: published/unpublished' AFTER `min_balance`;
-- 2. 现有模型全部设为已上架
UPDATE llm SET status = 'published';
-- 3. 添加索引(按状态筛选是高频操作)
ALTER TABLE llm ADD INDEX `idx_status` (`status`);

View File

@ -44,7 +44,7 @@ try:
# Paginated data
data_sql = f"""
select id, name, model, description, iconid, upappid, providerid,
ownerid, enabled_date, expired_date, min_balance
ownerid, enabled_date, expired_date, min_balance, status
from llm{where_clause}
order by model
limit ${limit}$ offset ${offset}$

View File

@ -12,6 +12,7 @@ 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 a.status = 'published'
and ppid is not NULL'''
biz_date = await get_business_date(sor)
recs = await sor.sqlExe(sql, {

View File

@ -3,7 +3,7 @@ db = DBPools()
async with db.sqlorContext(dbname) as sor:
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}$"""
where m.llmcatelogid = ${llmcatelogid}$ and a.id != ${llmid}$ and a.status = 'published'"""
ns = params_kw.copy()
recs = await sor.sqlExe(sql, ns)
for r in recs.get('rows', []):

View File

@ -18,6 +18,7 @@ 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
where a.status = 'published'
) x left join historyformat y on x.hfid = y.id
left join uapiio z on x.ioid = z.id
where m.llmcatelogid = ${llmcatelogid}$

View File

@ -2,7 +2,7 @@ llmid = params_kw.llmid
today= params_kw.today
msgs = []
async with get_sor_context(request._run_ns, 'llmage') as sor:
sql = "select * from llm where id=${llmid}$ and enabled_date <= ${today}$ and expired_date > ${today}$"
sql = "select * from llm where id=${llmid}$ and enabled_date <= ${today}$ and expired_date > ${today}$ and status = 'published'"
ns = {'llmid': llmid, 'today': today}
recs = await sor.sqlExe(sql, ns.copy())
if recs:

View File

@ -21,7 +21,8 @@ async with get_sor_context(env, 'llmage') as sor:
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}$"""
and a.model=${model}$
and a.status = 'published'"""
recs = await sor.sqlExe(sql, {
'lctype': lctype,
'model': params_kw.model or 'qwen3-max'

View File

@ -34,7 +34,8 @@ async with get_sor_context(env, 'llmage') as sor:
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}$"""
and a.model=${model}$
and a.status = 'published'"""
recs = await sor.sqlExe(sql, {
'lctype': lctype,
'model': params_kw.model or 'qwen3-max'

View File

@ -53,7 +53,8 @@ async with get_sor_context(env, 'llmage') as sor:
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}$"""
and a.model=${model}$
and a.status = 'published'"""
recs = await sor.sqlExe(sql, {
'lctype': lctype,
'model': params_kw.model

View File

@ -61,7 +61,8 @@ async with get_sor_context(env, 'llmage') as sor:
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}$"""
and a.model=${model}$
and a.status = 'published'"""
recs = await sor.sqlExe(sql, {
'lctype': lctype,
'model': params_kw.model