vendor_group_id = params_kw.get('vendor_group_id', '') if not vendor_group_id: return json.dumps({ "widgettype": "Error", "options": {"title": "错误", "message": "请选择素材组合"} }) org_id = (await get_userorgid()) or '0' result = await rl_list_virtual_assets_client(org_id, vendor_group_id) if not result.get('success'): return json.dumps({ "widgettype": "Error", "options": {"title": "查询失败", "message": result.get('message', '未知错误')} }) assets = result.get('assets', []) if not assets: return json.dumps({ "widgettype": "VBox", "options": {"padding": "16px", "gap": "12px"}, "subwidgets": [ { "widgettype": "Text", "options": {"text": "该素材组合下暂无素材,请先上传虚拟人素材。"} } ] }) # Build asset cards cards = [] for a in assets: status = a.get('status', '') name = a.get('name', '') url = a.get('url', '') atype = a.get('asset_type', '') create_time = str(a.get('create_time', ''))[:16] asset_id = a.get('id', '') vendor_asset_id = a.get('vendor_asset_id', '') s_lower = status.lower() if status else '' if s_lower in ('active', 'available', 'ready'): status_icon = "✅" elif s_lower in ('processing', 'pending', 'submitted'): status_icon = "⏳" elif s_lower in ('failed', 'error'): status_icon = "❌" else: status_icon = "📋" card_subs = [ { "widgettype": "HBox", "options": {"gap": "8px", "alignItems": "center", "marginBottom": "4px"}, "subwidgets": [ {"widgettype": "Text", "options": {"text": name or "未命名", "fontWeight": "bold"}}, {"widgettype": "Text", "options": {"text": f"{status_icon} {status}", "cfontsize": 0.9}} ] }, { "widgettype": "Text", "options": {"text": f"类型: {atype} 创建: {create_time}", "cfontsize": 0.9} }, { "widgettype": "Text", "options": {"text": f"Asset URI: asset://{vendor_asset_id}", "cfontsize": 0.85} } ] # Media preview if url: if atype == 'Image': card_subs.append({ "widgettype": "Image", "options": {"url": url, "cwidth": 15, "cheight": 10, "objectFit": "cover", "borderRadius": "4px", "marginTop": "8px"} }) elif atype == 'Video': card_subs.append({ "widgettype": "VideoPlayer", "options": {"url": url, "cwidth": 20, "cheight": 12, "marginTop": "8px"} }) elif atype == 'Audio': card_subs.append({ "widgettype": "AudioPlayer", "options": {"url": url, "marginTop": "8px"} }) # Buttons check_url = request.path.rsplit('/', 1)[0] + '/submit_query_status.dspy' btn_subs = [ { "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}});" \ "})()" }] } ] if url: btn_subs.append({ "widgettype": "Button", "options": {"label": "下载"}, "binds": [{ "wid": "self", "event": "click", "actiontype": "script", "target": "self", "script": "window.open('" + url + "', '_blank')" }] }) card_subs.append({ "widgettype": "HBox", "options": {"gap": "8px", "marginTop": "8px"}, "subwidgets": btn_subs }) cards.append({ "widgettype": "VBox", "options": {"css": "card", "padding": "12px", "borderRadius": "8px"}, "subwidgets": card_subs }) result_widget = { "widgettype": "VBox", "options": {"padding": "16px", "gap": "12px"}, "subwidgets": [ {"widgettype": "Text", "options": {"text": f"共 {len(assets)} 个虚拟人素材", "fontWeight": "bold"}}, { "widgettype": "ResponsableBox", "options": {"gap": "12px", "minWidth": "300px"}, "subwidgets": cards } ] } return json.dumps(result_widget, ensure_ascii=False)