- init.py: 新增6个虚拟人函数(create/list/upload/sync等),注册到ServerEnv - api_mapping: 新增create_group→CreateAssetGroup映射 - 外部API: 5个rl_virtual_*.dspy端点(创建组合/列表/上传/素材列表/状态) - 前端API: 4个submit/get dspy端点(UI表单提交和数据获取) - UI页面: 3个页面(创建组合/上传素材/查看素材) - index.ui: 左侧导航新增虚拟人素材分区(3个按钮) - load_path.py: RBAC新增virtual页面和api/%路径 - docs: api_downapp.md新增虚拟人API文档(5个端点)
89 lines
3.7 KiB
Plaintext
89 lines
3.7 KiB
Plaintext
|
||
import os
|
||
|
||
vendor_group_id = params_kw.get('vendor_group_id', '')
|
||
source_url = params_kw.get('source_url', '')
|
||
asset_type = params_kw.get('asset_type', '')
|
||
name = params_kw.get('name', '')
|
||
|
||
if not vendor_group_id or not source_url:
|
||
return json.dumps({
|
||
"widgettype": "Error",
|
||
"options": {"title": "错误", "message": "请选择素材组合并上传素材文件", "anchor": "cc"}
|
||
})
|
||
|
||
# Validate media file type from path extension
|
||
ext = os.path.splitext(source_url.split('?')[0])[1].lower() if source_url else ''
|
||
media_map = {
|
||
'.jpg': 'Image', '.jpeg': 'Image', '.png': 'Image', '.gif': 'Image', '.bmp': 'Image', '.webp': 'Image', '.svg': 'Image', '.tiff': 'Image', '.heic': 'Image',
|
||
'.mp4': 'Video', '.avi': 'Video', '.mov': 'Video', '.wmv': 'Video', '.flv': 'Video', '.mkv': 'Video', '.webm': 'Video',
|
||
'.mp3': 'Audio', '.wav': 'Audio', '.aac': 'Audio', '.flac': 'Audio', '.ogg': 'Audio', '.wma': 'Audio', '.m4a': 'Audio',
|
||
}
|
||
detected_type = media_map.get(ext, '')
|
||
if ext and not detected_type:
|
||
return json.dumps({
|
||
"widgettype": "Error",
|
||
"options": {"title": "错误", "message": f"不支持的文件类型: {ext},请上传图片、音频或视频文件", "anchor": "cc"}
|
||
})
|
||
if not asset_type and detected_type:
|
||
asset_type = detected_type
|
||
if not asset_type:
|
||
asset_type = 'Image'
|
||
|
||
# Convert base64 / local path to public URL
|
||
if source_url.startswith('data:') or (not source_url.startswith('http') and len(source_url) < 8000):
|
||
source_url = await b64media2url(request, source_url)
|
||
if not source_url:
|
||
return json.dumps({
|
||
"widgettype": "Error",
|
||
"options": {"title": "错误", "message": "素材文件转换失败", "anchor": "cc"}
|
||
})
|
||
|
||
org_id = (await get_userorgid()) or '0'
|
||
user_id = (await get_user()) or ''
|
||
|
||
result = await rl_upload_virtual_asset(org_id, vendor_group_id, source_url, asset_type, name, user_id)
|
||
|
||
if result.get('success'):
|
||
asset_id = result.get('id', '')
|
||
vendor_asset_id = result.get('vendor_asset_id', '')
|
||
status_text = result.get('status', 'Processing')
|
||
msg = f"虚拟人素材已提交,当前状态:{status_text}\n素材ID:{asset_id}\n供应商资产ID:{vendor_asset_id}"
|
||
|
||
base_path = request.path.rsplit('/', 1)[0]
|
||
check_url = base_path + '/submit_query_status.dspy'
|
||
|
||
return json.dumps({
|
||
"widgettype": "Message",
|
||
"id": "virtual_upload_result_popup",
|
||
"options": {"title": "上传成功", "message": "", "anchor": "cc"},
|
||
"subwidgets": [
|
||
{
|
||
"widgettype": "VBox",
|
||
"options": {"padding": "8px", "gap": "12px"},
|
||
"subwidgets": [
|
||
{"widgettype": "Text", "options": {"text": msg}},
|
||
{
|
||
"widgettype": "Button",
|
||
"options": {"label": "查询处理状态"},
|
||
"binds": [{
|
||
"wid": "self", "event": "click",
|
||
"actiontype": "script", "target": "self",
|
||
"script": "(async function(){"
|
||
"var url='" + check_url + "?_webbricks_=1&asset_id=" + asset_id + "';"
|
||
"var r=await fetch(url);"
|
||
"var j=await r.json();"
|
||
"await bricks.show_resp_message_or_error({json:async function(){return j}});"
|
||
"})()"
|
||
}]
|
||
}
|
||
]
|
||
}
|
||
]
|
||
})
|
||
else:
|
||
return json.dumps({
|
||
"widgettype": "Error",
|
||
"options": {"title": "上传失败", "message": result.get('message', '未知错误'), "anchor": "cc"}
|
||
})
|