feat(uapi): MiniMax-H3 setup DSPY with pricing - uapiio, uapi x2, upapp, upappkey, pricing_program x2 (2K:0.80/s, 768P:0.50/s)
This commit is contained in:
parent
258b46e600
commit
148ce17f82
@ -1,123 +1,139 @@
|
|||||||
"""
|
"""
|
||||||
MiniMax-H3 uapi integration DSPY
|
MiniMax-H3 complete setup: uapi + pricing
|
||||||
部署到: uapi/wwwroot/api/minimax_h3_setup.dspy
|
POST /uapi/api/minimax_h3_setup.dspy
|
||||||
调用: POST /uapi/api/minimax_h3_setup.dspy
|
Body: {"apikey": "YOUR_MINIMAX_API_KEY"}
|
||||||
"""
|
"""
|
||||||
import json
|
import json
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
dbname = env.get_module_dbname('uapi')
|
dbname = env.get_module_dbname('uapi')
|
||||||
|
pricing_dbname = env.get_module_dbname('pricing')
|
||||||
db = DBPools()
|
db = DBPools()
|
||||||
|
|
||||||
results = {}
|
results = {}
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# PART 1: UAPI records
|
||||||
|
# ============================================================
|
||||||
async with db.sqlorContext(dbname) as sor:
|
async with db.sqlorContext(dbname) as sor:
|
||||||
# 1. uapiio
|
|
||||||
uapiio_id = 'm_h3_video_gen_io'
|
uapiio_id = 'm_h3_video_gen_io'
|
||||||
|
|
||||||
|
# uapiio
|
||||||
existing = await sor.R('uapiio', {'id': uapiio_id})
|
existing = await sor.R('uapiio', {'id': uapiio_id})
|
||||||
if not existing:
|
if not existing:
|
||||||
io_data = {
|
await sor.C('uapiio', {
|
||||||
'id': uapiio_id,
|
'id': uapiio_id,
|
||||||
'name': 'MiniMax-H3 视频生成',
|
'name': 'MiniMax-H3 视频生成',
|
||||||
'description': 'MiniMax-H3 视频生成v2接口输入输出定义。支持文生视频、图生视频(首尾帧)、多模态参考生视频。',
|
'description': 'MiniMax-H3 视频生成v2接口。支持文生视频、图生视频(首尾帧)、多模态参考生视频。',
|
||||||
'input_fields': json.dumps({
|
'input_fields': json.dumps({
|
||||||
"model": {"type": "string", "required": True, "title": "模型名称", "enum": ["MiniMax-H3"]},
|
"model": {"type": "string", "required": True, "title": "模型名称", "enum": ["MiniMax-H3"]},
|
||||||
"content": {"type": "array", "required": True, "title": "多模态输入内容"},
|
"content": {"type": "array", "required": True, "title": "多模态输入内容"},
|
||||||
"resolution": {"type": "string", "required": True, "title": "分辨率", "enum": ["768P", "2K"]},
|
"resolution": {"type": "string", "required": True, "title": "分辨率", "enum": ["768P", "2K"]},
|
||||||
"duration": {"type": "integer", "required": True, "title": "时长(秒)", "enum": [4,5,6,7,8,9,10,11,12,13,14,15]},
|
"duration": {"type": "integer", "required": True, "title": "时长(秒)", "enum": [4,5,6,7,8,9,10,11,12,13,14,15]},
|
||||||
"ratio": {"type": "string", "title": "宽高比", "enum": ["adaptive","21:9","16:9","4:3","1:1","3:4","9:16"]},
|
"ratio": {"type": "string", "title": "宽高比", "enum": ["adaptive","21:9","16:9","4:3","1:1","3:4","9:16"]},
|
||||||
"callback_url": {"type": "string", "title": "回调地址"},
|
|
||||||
"aigc_watermark": {"type": "boolean", "title": "AIGC水印"}
|
|
||||||
}, ensure_ascii=False)
|
}, ensure_ascii=False)
|
||||||
}
|
})
|
||||||
await sor.C('uapiio', io_data)
|
|
||||||
results['uapiio'] = 'created'
|
results['uapiio'] = 'created'
|
||||||
else:
|
else:
|
||||||
results['uapiio'] = 'exists'
|
results['uapiio'] = 'exists'
|
||||||
|
|
||||||
# 2. uapi - create task
|
# uapi - create
|
||||||
create_id = 'm_h3_create_task'
|
cid = 'm_h3_create_task'
|
||||||
existing = await sor.R('uapi', {'id': create_id})
|
if not await sor.R('uapi', {'id': cid}):
|
||||||
if not existing:
|
|
||||||
await sor.C('uapi', {
|
await sor.C('uapi', {
|
||||||
'id': create_id,
|
'id': cid, 'upappid': 'minimax', 'name': 'video_generation_v2',
|
||||||
'upappid': 'minimax',
|
'title': 'MiniMax-H3 创建视频任务', 'description': '创建 MiniMax-H3 视频生成任务',
|
||||||
'name': 'video_generation_v2',
|
'need_auth': '0', 'stream': 'async', 'path': '/v2/video_generation',
|
||||||
'title': 'MiniMax-H3 创建视频任务',
|
'httpmethod': 'POST', 'chunk_match': 'task_id',
|
||||||
'description': '创建 MiniMax-H3 视频生成任务。返回 task_id,用查询接口轮询结果。',
|
|
||||||
'need_auth': '0',
|
|
||||||
'stream': 'async',
|
|
||||||
'path': '/v2/video_generation',
|
|
||||||
'httpmethod': 'POST',
|
|
||||||
'chunk_match': 'task_id',
|
|
||||||
'headers': '{"Content-Type": "application/json", "Authorization": "Bearer {{apikey}}"}',
|
'headers': '{"Content-Type": "application/json", "Authorization": "Bearer {{apikey}}"}',
|
||||||
'params': None,
|
'data': '{{jsondata}}', 'response': '{{response}}', 'ioid': uapiio_id,
|
||||||
'data': '{{jsondata}}',
|
|
||||||
'response': '{{response}}',
|
|
||||||
'ioid': uapiio_id,
|
|
||||||
})
|
})
|
||||||
results['uapi_create'] = 'created'
|
results['uapi_create'] = 'created'
|
||||||
else:
|
else:
|
||||||
results['uapi_create'] = 'exists'
|
results['uapi_create'] = 'exists'
|
||||||
|
|
||||||
# 3. uapi - query task
|
# uapi - query
|
||||||
query_id = 'm_h3_query_task'
|
qid = 'm_h3_query_task'
|
||||||
existing = await sor.R('uapi', {'id': query_id})
|
if not await sor.R('uapi', {'id': qid}):
|
||||||
if not existing:
|
|
||||||
await sor.C('uapi', {
|
await sor.C('uapi', {
|
||||||
'id': query_id,
|
'id': qid, 'upappid': 'minimax', 'name': 'query_video_generation',
|
||||||
'upappid': 'minimax',
|
'title': 'MiniMax-H3 查询视频任务', 'description': '按task_id查询任务状态',
|
||||||
'name': 'query_video_generation',
|
'need_auth': '0', 'stream': 'sync', 'path': '/v2/query/video_generation/{{task_id}}',
|
||||||
'title': 'MiniMax-H3 查询视频任务',
|
'httpmethod': 'GET', 'chunk_match': '',
|
||||||
'description': '按 task_id 查询 MiniMax-H3 视频生成任务状态与结果。',
|
|
||||||
'need_auth': '0',
|
|
||||||
'stream': 'sync',
|
|
||||||
'path': '/v2/query/video_generation/{{task_id}}',
|
|
||||||
'httpmethod': 'GET',
|
|
||||||
'chunk_match': '',
|
|
||||||
'headers': '{"Authorization": "Bearer {{apikey}}"}',
|
'headers': '{"Authorization": "Bearer {{apikey}}"}',
|
||||||
'params': None,
|
'data': None, 'response': '{{response}}', 'ioid': uapiio_id,
|
||||||
'data': None,
|
|
||||||
'response': '{{response}}',
|
|
||||||
'ioid': uapiio_id,
|
|
||||||
})
|
})
|
||||||
results['uapi_query'] = 'created'
|
results['uapi_query'] = 'created'
|
||||||
else:
|
else:
|
||||||
results['uapi_query'] = 'exists'
|
results['uapi_query'] = 'exists'
|
||||||
|
|
||||||
# 4. upapp
|
# upapp
|
||||||
existing = await sor.R('upapp', {'id': 'minimax'})
|
if not await sor.R('upapp', {'id': 'minimax'}):
|
||||||
if not existing:
|
|
||||||
await sor.C('upapp', {
|
await sor.C('upapp', {
|
||||||
'id': 'minimax',
|
'id': 'minimax', 'name': 'minimax', 'baseurl': 'https://api.minimax.chat',
|
||||||
'name': 'minimax',
|
'myappid': 'minimax', 'ownerid': 'platform',
|
||||||
'baseurl': 'https://api.minimax.chat',
|
|
||||||
'myappid': 'minimax',
|
|
||||||
'ownerid': 'platform',
|
|
||||||
'description': 'MiniMax 视频生成平台。提供 H3 视频生成模型。',
|
'description': 'MiniMax 视频生成平台。提供 H3 视频生成模型。',
|
||||||
})
|
})
|
||||||
results['upapp'] = 'created'
|
results['upapp'] = 'created'
|
||||||
else:
|
else:
|
||||||
results['upapp'] = 'exists'
|
results['upapp'] = 'exists'
|
||||||
|
|
||||||
# 5. upappkey — placeholder, fill real key later
|
# upappkey
|
||||||
existing = await sor.R('upappkey', {'id': 'mk_minimax_default'})
|
apikey_val = params_kw.get('apikey', '')
|
||||||
if not existing:
|
if apikey_val:
|
||||||
apikey_value = params_kw.get('apikey', '')
|
existing = await sor.R('upappkey', {'id': 'mk_minimax_default'})
|
||||||
if not apikey_value:
|
if not existing:
|
||||||
results['upappkey'] = 'skipped (no apikey provided)'
|
|
||||||
else:
|
|
||||||
encoded = env.password_encode(apikey_value)
|
|
||||||
await sor.C('upappkey', {
|
await sor.C('upappkey', {
|
||||||
'id': 'mk_minimax_default',
|
'id': 'mk_minimax_default', 'upappid': 'minimax', 'orgid': 'platform',
|
||||||
'upappid': 'minimax',
|
'apikey': env.password_encode(apikey_val),
|
||||||
'orgid': 'platform',
|
'enabled_date': '2025-01-01', 'expired_date': '9999-12-31',
|
||||||
'apikey': encoded,
|
|
||||||
'enabled_date': '2025-01-01',
|
|
||||||
'expired_date': '9999-12-31',
|
|
||||||
})
|
})
|
||||||
results['upappkey'] = 'created'
|
results['upappkey'] = 'created'
|
||||||
|
else:
|
||||||
|
results['upappkey'] = 'exists'
|
||||||
else:
|
else:
|
||||||
results['upappkey'] = 'exists'
|
results['upappkey'] = 'skipped (no apikey)'
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# PART 2: Pricing records
|
||||||
|
# ============================================================
|
||||||
|
async with db.sqlorContext(pricing_dbname) as sor:
|
||||||
|
# Inspect table structure
|
||||||
|
cols = await sor.I('pricing_program')
|
||||||
|
results['pp_cols'] = [c.get('Field') + ' ' + c.get('Type') for c in cols[:15]]
|
||||||
|
|
||||||
|
# Insert 2 pricing programs: 2K and 768P
|
||||||
|
programs = [
|
||||||
|
{
|
||||||
|
'id': 'minimax_h3_2k',
|
||||||
|
'name': 'MiniMax-H3-2K',
|
||||||
|
'description': 'MiniMax-H3 2K分辨率视频生成',
|
||||||
|
'unit': 'second',
|
||||||
|
'unit_price': 0.80,
|
||||||
|
'currency': 'CNY',
|
||||||
|
'category': 'video_generation',
|
||||||
|
'provider': 'minimax',
|
||||||
|
'model': 'MiniMax-H3',
|
||||||
|
'resolution': '2K',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'minimax_h3_768p',
|
||||||
|
'name': 'MiniMax-H3-768P',
|
||||||
|
'description': 'MiniMax-H3 768P分辨率视频生成',
|
||||||
|
'unit': 'second',
|
||||||
|
'unit_price': 0.50,
|
||||||
|
'currency': 'CNY',
|
||||||
|
'category': 'video_generation',
|
||||||
|
'provider': 'minimax',
|
||||||
|
'model': 'MiniMax-H3',
|
||||||
|
'resolution': '768P',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
for prog in programs:
|
||||||
|
existing = await sor.R('pricing_program', {'id': prog['id']})
|
||||||
|
if not existing:
|
||||||
|
await sor.C('pricing_program', prog)
|
||||||
|
results['pricing_' + prog['id']] = 'created'
|
||||||
|
else:
|
||||||
|
results['pricing_' + prog['id']] = 'exists'
|
||||||
|
|
||||||
return {'status': 'ok', 'results': results}
|
return {'status': 'ok', 'results': results}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user