From d5770915d27583c192629f7bab476fa93c0356d5 Mon Sep 17 00:00:00 2001
From: ping <1017253325@qq.com>
Date: Mon, 25 May 2026 19:36:34 +0800
Subject: [PATCH 1/7] update
---
b/user/loginUser.dspy | 2 +-
b/user/logintype.dspy | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/b/user/loginUser.dspy b/b/user/loginUser.dspy
index 8f98f93..5efdb04 100644
--- a/b/user/loginUser.dspy
+++ b/b/user/loginUser.dspy
@@ -152,7 +152,7 @@ async def loginUser(ns):
type = 0
if type1 == 1:
# 手机号验证码登录
- userreacs = await sor.R('users', {'mobile': ns.get('username')})
+ userreacs = await sor.R('users', {'mobile': ns.get('mobile')})
if not userreacs:
userreacs = await sor.R('users', {'username': ns.get('username')})
diff --git a/b/user/logintype.dspy b/b/user/logintype.dspy
index 5d71bde..8151223 100644
--- a/b/user/logintype.dspy
+++ b/b/user/logintype.dspy
@@ -199,7 +199,7 @@ async def logintype(ns):
return {'status': False, 'msg': '验证码不正确'}
if type == 1:
# 手机号登录
- users = await sor.R('users', {'mobile': ns.get('username')})
+ users = await sor.R('users', {'mobile': ns.get('mobile')})
if not users:
users = await sor.R('users', {'username': ns.get('username')})
else:
From f064f3f861de3a00750bdd121143ac230d92e9f5 Mon Sep 17 00:00:00 2001
From: hrx <18603305412@163.com>
Date: Tue, 26 May 2026 10:02:36 +0800
Subject: [PATCH 2/7] updata
---
f/web-kboss/src/router/index.js | 46 ++++++++++----------
f/web-kboss/src/views/homePage/indexLast.vue | 4 +-
2 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/f/web-kboss/src/router/index.js b/f/web-kboss/src/router/index.js
index e877b3b..2582f79 100644
--- a/f/web-kboss/src/router/index.js
+++ b/f/web-kboss/src/router/index.js
@@ -513,29 +513,29 @@ export const asyncRoutes = [
]
},
// Token用量 - 一级菜单(所有登录用户都能看到)
- {
- path: "/tokenUsage",
- component: Layout,
- meta: {
- title: "Token用量",
- fullPath: "/tokenUsage",
- noCache: true,
- icon: "el-icon-data-line"
- },
- children: [
- {
- path: "",
- component: () => import('@/views/tokenUsage/index.vue'),
- name: 'TokenUsage',
- meta: {
- title: "Token用量",
- fullPath: "/tokenUsage",
- noCache: true,
- icon: "el-icon-data-line"
- }
- },
- ]
- },
+ // {
+ // path: "/tokenUsage",
+ // component: Layout,
+ // meta: {
+ // title: "Token用量",
+ // fullPath: "/tokenUsage",
+ // noCache: true,
+ // icon: "el-icon-data-line"
+ // },
+ // children: [
+ // {
+ // path: "",
+ // component: () => import('@/views/tokenUsage/index.vue'),
+ // name: 'TokenUsage',
+ // meta: {
+ // title: "Token用量",
+ // fullPath: "/tokenUsage",
+ // noCache: true,
+ // icon: "el-icon-data-line"
+ // }
+ // },
+ // ]
+ // },
// 模型体验
{
path: "/modelExperience",
diff --git a/f/web-kboss/src/views/homePage/indexLast.vue b/f/web-kboss/src/views/homePage/indexLast.vue
index 93dbcff..9b36df7 100644
--- a/f/web-kboss/src/views/homePage/indexLast.vue
+++ b/f/web-kboss/src/views/homePage/indexLast.vue
@@ -16,8 +16,8 @@
地址:{{ logoInfoNew.home.adress }}
邮箱:{{logoInfoNew.home.email}}
- 电话: {{logoInfoNew.home.mobile}}
-
+
+
From dac9cea1b5723c880cabb0d65e1788c063ae8dd7 Mon Sep 17 00:00:00 2001
From: ping <1017253325@qq.com>
Date: Tue, 26 May 2026 17:25:37 +0800
Subject: [PATCH 3/7] update
---
b/cntoai/model_management_add.dspy | 55 ++++++++++++++++-----
b/cntoai/model_management_update.dspy | 69 +++++++++++++++++++++++----
2 files changed, 104 insertions(+), 20 deletions(-)
diff --git a/b/cntoai/model_management_add.dspy b/b/cntoai/model_management_add.dspy
index a9c0312..09a74f4 100644
--- a/b/cntoai/model_management_add.dspy
+++ b/b/cntoai/model_management_add.dspy
@@ -1,12 +1,15 @@
-# 可写入/更新的字段(不含 id、created_at、updated_at)
+# model_management 可写入字段(不含 id、created_at、updated_at)
_MODEL_FIELDS = (
'llmid', 'provider', 'model_name', 'display_name', 'model_type',
'context_length', 'input_token_price', 'output_token_price',
'cache_hit_input_price', 'billing_method', 'billing_unit',
'capabilities', 'limitations', 'highlights', 'is_active',
- 'description', 'listing_status',
+ 'description', 'listing_status', 'sort_order', 'experience',
)
+# model_api_doc 可写入字段(不含 id、model_id、created_at、updated_at)
+_API_DOC_FIELDS = ('api_url', 'curl_code', 'python_code')
+
def _escape(value):
if value is None:
@@ -24,26 +27,54 @@ def _build_model_dict(ns, include_listing_status=False):
return data
+def _build_api_doc_dict(ns):
+ data = {}
+ for field in _API_DOC_FIELDS:
+ if field in ns and ns.get(field) is not None:
+ data[field] = ns.get(field)
+ return data
+
+
async def model_management_add(ns={}):
- """新增模型,默认待上架 listing_status=0"""
+ """新增模型及 API 文档,provider、model_name 必传"""
if not ns.get('provider') or not ns.get('model_name'):
return {'status': False, 'msg': 'provider and model_name are required'}
- ns_dic = _build_model_dict(ns, include_listing_status=True)
- if 'listing_status' not in ns_dic:
- ns_dic['listing_status'] = 0
- if 'is_active' not in ns_dic:
- ns_dic['is_active'] = 1
+ model_dic = _build_model_dict(ns, include_listing_status=True)
+ if 'listing_status' not in model_dic:
+ model_dic['listing_status'] = 0
+ if 'is_active' not in model_dic:
+ model_dic['is_active'] = 1
+
+ api_doc_dic = _build_api_doc_dict(ns)
+ if api_doc_dic and not api_doc_dic.get('api_url'):
+ return {'status': False, 'msg': 'api_url is required when creating api doc'}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
- await sor.C('model_management', ns_dic)
- return {'status': True, 'msg': 'create model success', 'data': ns_dic}
+ await sor.C('model_management', model_dic)
+
+ id_rows = await sor.sqlExe('SELECT LAST_INSERT_ID() AS id;', {})
+ model_id = id_rows[0]['id'] if id_rows else None
+ if not model_id:
+ await sor.rollback()
+ return {'status': False, 'msg': 'create model failed, missing model id'}
+
+ result_data = dict(model_dic)
+ result_data['id'] = model_id
+
+ if api_doc_dic:
+ create_dic = dict(api_doc_dic)
+ create_dic['model_id'] = str(model_id)
+ await sor.C('model_api_doc', create_dic)
+ result_data['api_doc'] = create_dic
+
+ return {'status': True, 'msg': 'create model success', 'data': result_data}
except Exception as e:
await sor.rollback()
return {'status': False, 'msg': 'create model failed, %s' % str(e)}
-
+
ret = await model_management_add(params_kw)
-return ret
\ No newline at end of file
+return ret
diff --git a/b/cntoai/model_management_update.dspy b/b/cntoai/model_management_update.dspy
index 854de52..c28d5b5 100644
--- a/b/cntoai/model_management_update.dspy
+++ b/b/cntoai/model_management_update.dspy
@@ -1,12 +1,15 @@
-# 可写入/更新的字段(不含 id、created_at、updated_at)
+# model_management 可写入字段(不含 id、created_at、updated_at)
_MODEL_FIELDS = (
'llmid', 'provider', 'model_name', 'display_name', 'model_type',
'context_length', 'input_token_price', 'output_token_price',
'cache_hit_input_price', 'billing_method', 'billing_unit',
'capabilities', 'limitations', 'highlights', 'is_active',
- 'description', 'listing_status',
+ 'description', 'listing_status', 'sort_order', 'experience',
)
+# model_api_doc 可写入字段(不含 id、model_id、created_at、updated_at)
+_API_DOC_FIELDS = ('api_url', 'curl_code', 'python_code')
+
def _escape(value):
if value is None:
@@ -23,23 +26,73 @@ def _build_model_dict(ns, include_listing_status=False):
data['listing_status'] = ns.get('listing_status', 0)
return data
+
+def _build_api_doc_dict(ns):
+ """构建 API 文档更新字典;字段在 ns 中即参与更新(含空字符串)"""
+ data = {}
+ for field in _API_DOC_FIELDS:
+ if field in ns and ns.get(field) is not None:
+ data[field] = ns.get(field)
+ return data
+
+
async def model_management_update(ns={}):
- """编辑模型,id 必传"""
+ """编辑模型及 API 文档,id(model_management 主键)必传"""
model_id = ns.get('id')
if not model_id:
return {'status': False, 'msg': 'id is required'}
- ns_dic = _build_model_dict(ns)
- ns_dic['id'] = model_id
+ model_dic = _build_model_dict(ns)
+ api_doc_dic = _build_api_doc_dict(ns)
+ has_model_update = bool(model_dic)
+ has_api_doc_update = bool(api_doc_dic)
+
+ if not has_model_update and not has_api_doc_update:
+ return {'status': False, 'msg': 'no fields to update'}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
- await sor.U('model_management', ns_dic)
+ if has_model_update:
+ model_dic['id'] = model_id
+ await sor.U('model_management', model_dic)
+
+ if has_api_doc_update:
+ api_doc_id = ns.get('api_doc_id')
+ existing = None
+ if api_doc_id:
+ find_sql = (
+ "SELECT id FROM model_api_doc WHERE id = '%s' AND model_id = '%s' LIMIT 1;"
+ % (_escape(api_doc_id), _escape(str(model_id)))
+ )
+ existing = await sor.sqlExe(find_sql, {})
+ if not existing:
+ find_sql = (
+ "SELECT id FROM model_api_doc WHERE model_id = '%s' LIMIT 1;"
+ % _escape(str(model_id))
+ )
+ existing = await sor.sqlExe(find_sql, {})
+
+ if existing:
+ doc_update = dict(api_doc_dic)
+ doc_update['id'] = existing[0]['id']
+ await sor.U('model_api_doc', doc_update)
+ else:
+ if not api_doc_dic.get('api_url'):
+ await sor.rollback()
+ return {
+ 'status': False,
+ 'msg': 'api_url is required when creating api doc',
+ }
+ create_dic = dict(api_doc_dic)
+ create_dic['model_id'] = str(model_id)
+ await sor.C('model_api_doc', create_dic)
+
return {'status': True, 'msg': 'update model success'}
except Exception as e:
await sor.rollback()
return {'status': False, 'msg': 'update model failed, %s' % str(e)}
-
+
+
ret = await model_management_update(params_kw)
-return ret
\ No newline at end of file
+return ret
From 1086d69419f469409050c3f83da76509ef2dfb15 Mon Sep 17 00:00:00 2001
From: ping <1017253325@qq.com>
Date: Tue, 26 May 2026 17:33:37 +0800
Subject: [PATCH 4/7] update
---
b/cntoai/model_management_add.dspy | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/b/cntoai/model_management_add.dspy b/b/cntoai/model_management_add.dspy
index 09a74f4..6ff492d 100644
--- a/b/cntoai/model_management_add.dspy
+++ b/b/cntoai/model_management_add.dspy
@@ -61,6 +61,15 @@ async def model_management_add(ns={}):
await sor.rollback()
return {'status': False, 'msg': 'create model failed, missing model id'}
+ # 未传 sort_order 时,默认与新建主键 id 相同
+ if not (
+ 'sort_order' in ns
+ and ns.get('sort_order') is not None
+ and ns.get('sort_order') != ''
+ ):
+ await sor.U('model_management', {'id': model_id, 'sort_order': model_id})
+ model_dic['sort_order'] = model_id
+
result_data = dict(model_dic)
result_data['id'] = model_id
From 85630c726912aabce8ec078429990be3b4ec3574 Mon Sep 17 00:00:00 2001
From: ping <1017253325@qq.com>
Date: Wed, 27 May 2026 14:25:10 +0800
Subject: [PATCH 5/7] update
---
b/cntoai/model_management_search_doc.dspy | 153 ++++++++++++++++++++++
1 file changed, 153 insertions(+)
create mode 100644 b/cntoai/model_management_search_doc.dspy
diff --git a/b/cntoai/model_management_search_doc.dspy b/b/cntoai/model_management_search_doc.dspy
new file mode 100644
index 0000000..0f12510
--- /dev/null
+++ b/b/cntoai/model_management_search_doc.dspy
@@ -0,0 +1,153 @@
+# 可写入/更新的字段(不含 id、created_at、updated_at)
+_MODEL_FIELDS = (
+ 'llmid', 'provider', 'model_name', 'display_name', 'model_type',
+ 'context_length', 'input_token_price', 'output_token_price',
+ 'cache_hit_input_price', 'billing_method', 'billing_unit',
+ 'capabilities', 'limitations', 'highlights', 'is_active',
+ 'description', 'listing_status', 'sort_order',
+)
+
+
+def _escape(value):
+ if value is None:
+ return None
+ return str(value).replace("'", "''")
+
+
+def _build_model_dict(ns, include_listing_status=False):
+ data = {}
+ for field in _MODEL_FIELDS:
+ if field in ns and ns.get(field) is not None and ns.get(field) != '':
+ data[field] = ns.get(field)
+ if include_listing_status and 'listing_status' not in data:
+ data['listing_status'] = ns.get('listing_status', 0)
+ return data
+
+
+def _build_where_conditions(ns, table_alias='m'):
+ """构建 model_management 筛选条件(带表别名,用于 JOIN 查询)"""
+ prefix = '%s.' % table_alias
+ conditions = ['1=1']
+ if ns.get('display_name'):
+ display_name = _escape(ns.get('display_name'))
+ conditions.append("%sdisplay_name LIKE '%%%%%s%%%%'" % (prefix, display_name))
+ if ns.get('model_type'):
+ conditions.append("%smodel_type = '%s'" % (prefix, _escape(ns.get('model_type'))))
+ if ns.get('provider'):
+ conditions.append("%sprovider = '%s'" % (prefix, _escape(ns.get('provider'))))
+ if ns.get('listing_status') is not None and ns.get('listing_status') != '':
+ conditions.append("%slisting_status = '%s'" % (prefix, _escape(ns.get('listing_status'))))
+ return ' AND '.join(conditions)
+
+
+def _attach_api_doc(row):
+ """将 JOIN 出的 API 文档字段整理为 api_doc 子对象"""
+ api_doc_id = row.pop('api_doc_id', None)
+ api_url = row.pop('api_url', None)
+ curl_code = row.pop('curl_code', None)
+ python_code = row.pop('python_code', None)
+ api_doc_created_at = row.pop('api_doc_created_at', None)
+ api_doc_updated_at = row.pop('api_doc_updated_at', None)
+
+ if api_doc_id:
+ row['api_doc'] = {
+ 'id': api_doc_id,
+ 'model_id': str(row.get('id', '')),
+ 'api_url': api_url,
+ 'curl_code': curl_code,
+ 'python_code': python_code,
+ 'created_at': api_doc_created_at,
+ 'updated_at': api_doc_updated_at,
+ }
+ else:
+ row['api_doc'] = None
+ return row
+
+
+async def model_management_search_doc(ns={}):
+ """
+ 分页查询模型列表(含 API 文档),支持按 display_name / model_type / provider / listing_status 筛选。
+ model_management LEFT JOIN model_api_doc(model_id = model_management.id)。
+ 返回模型总数、待上架总数、已上架总数,以及厂商列表、模型类型列表;每条模型含 api_doc。
+ """
+ import traceback
+
+ page_size = int(ns.get('page_size', 1000))
+ current_page = int(ns.get('current_page', 1))
+ offset = (current_page - 1) * page_size
+ where_clause = _build_where_conditions(ns)
+
+ db = DBPools()
+ async with db.sqlorContext('kboss') as sor:
+ try:
+ stats_sql = """
+ SELECT COUNT(*) AS total_count,
+ SUM(CASE WHEN listing_status = 0 THEN 1 ELSE 0 END) AS pending_count,
+ SUM(CASE WHEN listing_status = 1 THEN 1 ELSE 0 END) AS listed_count
+ FROM model_management;
+ """
+ stats_li = await sor.sqlExe(stats_sql, {})
+ stats = stats_li[0] if stats_li else {}
+
+ provider_sql = """
+ SELECT DISTINCT provider FROM model_management
+ WHERE provider IS NOT NULL AND provider != ''
+ ORDER BY provider;
+ """
+ model_type_sql = """
+ SELECT DISTINCT model_type FROM model_management
+ WHERE model_type IS NOT NULL AND model_type != ''
+ ORDER BY model_type;
+ """
+
+ count_sql = """
+ SELECT COUNT(*) AS total_count
+ FROM model_management m
+ WHERE %s;
+ """ % where_clause
+
+ find_sql = """
+ SELECT m.*,
+ d.id AS api_doc_id,
+ d.api_url,
+ d.curl_code,
+ d.python_code,
+ d.created_at AS api_doc_created_at,
+ d.updated_at AS api_doc_updated_at
+ FROM model_management m
+ LEFT JOIN model_api_doc d ON d.model_id = CAST(m.id AS CHAR)
+ WHERE %s
+ ORDER BY m.sort_order ASC
+ LIMIT %s OFFSET %s;
+ """ % (where_clause, page_size, offset)
+
+ provider_rows = await sor.sqlExe(provider_sql, {})
+ model_type_rows = await sor.sqlExe(model_type_sql, {})
+ filter_total = (await sor.sqlExe(count_sql, {}))[0]['total_count']
+ model_rows = await sor.sqlExe(find_sql, {})
+ model_list = [_attach_api_doc(row) for row in model_rows]
+
+ return {
+ 'status': True,
+ 'msg': 'search model with api doc success',
+ 'data': {
+ 'total_count': stats.get('total_count', 0),
+ 'pending_count': int(stats.get('pending_count') or 0),
+ 'listed_count': int(stats.get('listed_count') or 0),
+ 'provider_list': [r['provider'] for r in provider_rows],
+ 'model_type_list': [r['model_type'] for r in model_type_rows],
+ 'filter_total': filter_total,
+ 'page_size': page_size,
+ 'current_page': current_page,
+ 'model_list': model_list,
+ },
+ }
+ except Exception as e:
+ return {
+ 'status': False,
+ 'msg': 'search model with api doc failed, %s' % traceback.format_exc(),
+ }
+
+
+ret = await model_management_search_doc(params_kw)
+return ret
From ba8e46bd042238e1a59341a3db82926653d246ef Mon Sep 17 00:00:00 2001
From: hrx <18603305412@163.com>
Date: Wed, 27 May 2026 17:24:07 +0800
Subject: [PATCH 6/7] updata
---
f/web-kboss/src/api/model/model.js | 28 +
f/web-kboss/src/router/index.js | 26 +
f/web-kboss/src/store/modules/permission.js | 2 +-
f/web-kboss/src/views/homePage/indexLast.vue | 2 +-
.../modelInfoConfig/ModelInfoDetailDialog.vue | 323 +++++++
.../modelInfoConfig/ModelInfoEditDialog.vue | 899 ++++++++++++++++++
.../views/operation/modelInfoConfig/index.vue | 309 ++++++
7 files changed, 1587 insertions(+), 2 deletions(-)
create mode 100644 f/web-kboss/src/views/operation/modelInfoConfig/ModelInfoDetailDialog.vue
create mode 100644 f/web-kboss/src/views/operation/modelInfoConfig/ModelInfoEditDialog.vue
create mode 100644 f/web-kboss/src/views/operation/modelInfoConfig/index.vue
diff --git a/f/web-kboss/src/api/model/model.js b/f/web-kboss/src/api/model/model.js
index c6287ad..65e0b79 100644
--- a/f/web-kboss/src/api/model/model.js
+++ b/f/web-kboss/src/api/model/model.js
@@ -121,4 +121,32 @@ export const reqTokenUsage = (params = {}) => {
method: 'post',
params
})
+}
+
+
+// 模型信息配置添加
+export const reqModelInfoConfig = (params = {}) => {
+ return request({
+ url: '/cntoai/model_management_add.dspy',
+ method: 'get',
+ params
+ })
+}
+
+// 模型信息配置编辑(编辑时需要额外传 id)
+export const reqModelInfoConfigEdit = (params = {}) => {
+ return request({
+ url: '/cntoai/model_management_update.dspy',
+ method: 'get',
+ params
+ })
+}
+
+// 模型信息配置列表
+export const reqModelInfoConfigList = (params = {}) => {
+ return request({
+ url: '/cntoai/model_management_search_doc.dspy',
+ method: 'get',
+ params
+ })
}
\ No newline at end of file
diff --git a/f/web-kboss/src/router/index.js b/f/web-kboss/src/router/index.js
index 2582f79..c3f628c 100644
--- a/f/web-kboss/src/router/index.js
+++ b/f/web-kboss/src/router/index.js
@@ -464,6 +464,32 @@ export const asyncRoutes = [
]
},
+ // 运营——模型信息配置
+ {
+ path: "/modelInfoConfig",
+ component: Layout,
+ meta: {
+ title: "模型信息配置",
+ fullPath: "/modelInfoConfig",
+ noCache: true,
+ icon: "el-icon-setting",
+ roles: ["运营"]
+ },
+ children: [
+ {
+ path: "",
+ component: () => import('@/views/operation/modelInfoConfig/index.vue'),
+ name: 'ModelInfoConfig',
+ meta: {
+ title: "模型信息配置",
+ fullPath: "/modelInfoConfig",
+ noCache: true,
+ roles: ["运营"]
+ }
+ },
+ ]
+ },
+
// token市集 - 一级菜单(所有登录用户都能看到)
{
diff --git a/f/web-kboss/src/store/modules/permission.js b/f/web-kboss/src/store/modules/permission.js
index 6becf7a..719ba05 100644
--- a/f/web-kboss/src/store/modules/permission.js
+++ b/f/web-kboss/src/store/modules/permission.js
@@ -17,7 +17,7 @@ const SUPER_ADMIN_ROUTE_PATH = '/superAdministrator';
const COMMON_ROUTE_PATHS = ['/product', '/tokenManagement', '/tokenUsage', '/modelExperience', '/modelDetail', '/modelApiDocument'];
// 运营角色需要额外补出来的菜单。
-const OPERATION_EXTRA_ROUTE_PATHS = ['/modelManagement', '/operationReport'];
+const OPERATION_EXTRA_ROUTE_PATHS = ['/modelManagement', '/modelInfoConfig', '/operationReport'];
// 普通客户账号默认要补出来的基础菜单。
const BASE_USER_ROUTE_PATHS = ['/orderManagement', '/resourceManagement'];
diff --git a/f/web-kboss/src/views/homePage/indexLast.vue b/f/web-kboss/src/views/homePage/indexLast.vue
index 9b36df7..facb57e 100644
--- a/f/web-kboss/src/views/homePage/indexLast.vue
+++ b/f/web-kboss/src/views/homePage/indexLast.vue
@@ -17,7 +17,7 @@
邮箱:{{logoInfoNew.home.email}}
-
+
diff --git a/f/web-kboss/src/views/operation/modelInfoConfig/ModelInfoDetailDialog.vue b/f/web-kboss/src/views/operation/modelInfoConfig/ModelInfoDetailDialog.vue
new file mode 100644
index 0000000..1939aaa
--- /dev/null
+++ b/f/web-kboss/src/views/operation/modelInfoConfig/ModelInfoDetailDialog.vue
@@ -0,0 +1,323 @@
+
+
+
+
+
+ 模型ID
+ {{ displayValue(detail.id) }}
+
+
+ 模型名称/版本
+ {{ displayValue(detail.model_name || detail.display_name) }}
+
+
+ 展示名称
+ {{ displayValue(detail.display_name) }}
+
+
+ 模型类型
+ {{ displayValue(detail.model_type) }}
+
+
+ 供应商
+ {{ displayValue(detail.provider) }}
+
+
+ 接入ID
+ {{ displayValue(detail.llmid) }}
+
+
+ 上下文长度
+ {{ displayValue(detail.context_length) }}
+
+
+ 输入token单价
+ {{ displayValue(detail.input_token_price) }}
+
+
+ 输出token单价
+ {{ displayValue(detail.output_token_price) }}
+
+
+ 输入缓存命中token单价
+ {{ displayValue(detail.cache_hit_input_price) }}
+
+
+ 计费方式
+ {{ displayValue(detail.billing_method) }}
+
+
+ 计费单位
+ {{ displayValue(detail.billing_unit) }}
+
+
+ 是否支持体验
+
+ {{ Number(detail.experience) === 1 ? '是' : '否' }}
+
+
+
+ {{ item.name }}
+ {{ item.value }}
+ {{ displayValue(item.value) }}
+
+
+
+
+ 模型限制
+
+
+ {{ item.name }}
+ {{ displayValue(item.value) }}
+
+
+
+
+
+ 模型亮点
+
+
+ {{ item.value || item.name }}
+
+
+
+
+
+
+ 状态
+
+ {{ detail.listing_status === 1 ? '已上架' : '待上架' }}
+
+
+
+
模型简介
+
{{ displayValue(detail.description) }}
+
+
+
+
+
+ curl代码
+ {{ displayValue(apiDoc.curl_code || detail.curl_code) }}
+
+
+
+ Python代码
+ {{ displayValue(apiDoc.python_code || detail.python_code) }}
+
+
+
+
+
+ 更新时间
+ {{ displayValue(detail.updated_at || detail.updatedAt) }}
+
+
+
+
+
+
+
+
diff --git a/f/web-kboss/src/views/operation/modelInfoConfig/ModelInfoEditDialog.vue b/f/web-kboss/src/views/operation/modelInfoConfig/ModelInfoEditDialog.vue
new file mode 100644
index 0000000..90823b8
--- /dev/null
+++ b/f/web-kboss/src/views/operation/modelInfoConfig/ModelInfoEditDialog.vue
@@ -0,0 +1,899 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/f/web-kboss/src/views/operation/modelInfoConfig/index.vue b/f/web-kboss/src/views/operation/modelInfoConfig/index.vue
new file mode 100644
index 0000000..faa41f0
--- /dev/null
+++ b/f/web-kboss/src/views/operation/modelInfoConfig/index.vue
@@ -0,0 +1,309 @@
+
+
+
模型信息配置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 查询
+ 重置
+
+
+ 添加
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ scope.row.listing_status === 1 ? '已上架' : '待上架' }}
+
+
+
+
+
+
+ 详情
+ 编辑模型信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 42f7d0c663b896533752ea6fb167eae42b6044c5 Mon Sep 17 00:00:00 2001
From: ping <1017253325@qq.com>
Date: Wed, 27 May 2026 17:24:20 +0800
Subject: [PATCH 7/7] update
---
b/cntoai/sync_model_to_llm.dspy | 77 +++++++++++++++++++++++++++++++++
1 file changed, 77 insertions(+)
create mode 100644 b/cntoai/sync_model_to_llm.dspy
diff --git a/b/cntoai/sync_model_to_llm.dspy b/b/cntoai/sync_model_to_llm.dspy
new file mode 100644
index 0000000..ac187af
--- /dev/null
+++ b/b/cntoai/sync_model_to_llm.dspy
@@ -0,0 +1,77 @@
+async def sync_model_to_llm(ns={}):
+ import aiohttp
+
+ # 从数据库读取domain和Bearer token
+ db = DBPools()
+ async with db.sqlorContext('kboss') as sor:
+ domain_li = await sor.R('params', {'pname': 'cntoai_domain'})
+ user_key = await sor.R('params', {'pname': 'cntoai_already_sync_user_key'})
+ if not domain_li or not user_key:
+ return {
+ 'status': False,
+ 'msg': '未找到params domain或Bearer token'
+ }
+ domain = domain_li[0]['pvalue']
+ bearer_token = user_key[0]['pvalue']
+
+ url = f"{domain}/llmage/list_llms"
+ header = {
+ 'Authorization': f'Bearer {bearer_token}',
+ 'Content-Type': 'application/json',
+ }
+ try:
+ async with aiohttp.ClientSession() as session:
+ async with session.get(url, headers=header) as response:
+ result = await response.json()
+ if not result:
+ return {
+ 'status': False,
+ 'msg': '没有找到模型列表'
+ }
+
+ # 插入数据库
+ db = DBPools()
+ async with db.sqlorContext('kboss') as sor:
+ new_llms_count = 0
+ new_llms_list = []
+ for category_list in result:
+ for item in category_list.get('llms', []):
+ # 查找数据库中是否已经存在,不存在就插入
+ exist_llm = await sor.R('llm', {'model': item.get('model')})
+ if exist_llm:
+ continue
+ new_llms = {
+ 'id': item.get('id'),
+ 'name': item.get('name'),
+ 'model': item.get('model'),
+ 'description': item.get('description'),
+ 'llmcatelogid': item.get('catelog_id') or item.get('catelogid'),
+ 'iconid': item.get('iconid'),
+ 'upappid': item.get('upappid'),
+ 'apiname': item.get('apiname'),
+ 'providerid': item.get('providerid'),
+ 'ownerid': item.get('ownerid') or '0',
+ 'enabled_date': item.get('enabled_date'),
+ 'expired_date': item.get('expired_date'),
+ 'query_apiname': item.get('query_apiname') or '',
+ 'query_period': item.get('query_period'),
+ 'ppid': item.get('ppid'),
+ }
+ new_llms_count += 1
+ new_llms_list.append(new_llms.get('model'))
+ await sor.C('llm', new_llms)
+
+ return {
+ 'status': True,
+ 'msg': f"sync_llm_list同步模型成功,共插入{new_llms_count}个模型,模型列表: {new_llms_list}"
+ }
+
+ except Exception as e:
+ return {
+ 'status': False,
+ 'msg': f"sync_llm_list同步模型失败, {domain}, {bearer_token}: {e}"
+ }
+
+
+ret = await sync_model_to_llm(params_kw)
+return ret