鸿蒙智能体开发实战:39.鸿蒙壁纸大师 - 前端卡片显示与交互优化

📅 2026/7/13 1:48:26 👁️ 阅读次数 📝 编程学习
鸿蒙智能体开发实战:39.鸿蒙壁纸大师 - 前端卡片显示与交互优化

引言

在前端展示层面,鸿蒙壁纸大师充分利用了鸿蒙 A2A 协议的卡片能力,通过DisplayFaCard实现丰富的交互式 UI,而非简单的文本对话。整个壁纸创作流程中,用户看到的是可点击的选择列表生动的进度提示精美的壁纸展示卡片

本文将深入解析前端的卡片交互设计,涵盖selectList选择卡片、wallpaper展示卡片、SSE 事件驱动的前端更新以及内容安全策略。

上图展示了鸿蒙壁纸大师中的两种核心卡片类型:selectList 选择卡片和 wallpaper 壁纸展示卡片,以及它们在交互流程中的切换关系

一、卡片体系总览

1.1 三种卡片类型

鸿蒙壁纸大师使用了三种卡片类型:

卡片类型用途展示阶段
selectList交互式选择列表风格选择、主题选择、场景选择
wallpaper壁纸结果展示壁纸生成完成
text文本消息闲聊、进度提示

核心概念DisplayFaCard是鸿蒙 A2A 协议中卡片展示的统一入口,通过cardName字段区分不同卡片类型,前端根据cardName渲染对应的 UI 组件。

1.2 卡片 JSON 结构规范

所有卡片都通过 A2A 协议的artifact-update事件的parts字段传递:

{"jsonrpc":"2.0","id":"request_id","result":{"taskId":"task_id","kind":"artifact-update","append":false,"lastChunk":true,"final":true,"artifact":{"artifactId":"task_id-options","parts":[{"kind":"data","data":{"cardsInfo":[{"cardName":"selectList","cardData":{...},"displayType":"DisplayFaCard"}]}}]}},"error":{"code":0,"message":"success"}}

二、selectList 选择卡片

2.1 卡片构建函数

# agent_routes.pydefbuild_style_options_card(title:str,options:List[str],task_id:str,request_id:str,has_next_batch:bool=True,can_replay:bool=True,)->dict:"""构建风格/主题选项的卡片 SSE 事件"""items=[{"text":opt,"value":opt}foroptinoptions]return{"jsonrpc":"2.0","id":request_id,"result":{"taskId":task_id,"kind":"artifact-update","append":False,"lastChunk":True,"final":True,"artifact":{"artifactId":f"{task_id}-options","parts":[{"kind":"data","data":{"cardsInfo":[{"cardName":"selectList","cardData":{"title":title,"items":items,"canReplay":can_replay,},"displayType":"DisplayFaCard"}]}}]}},"error":{"code":0,"message":"success"}}

2.2 三级选择流程的卡片展示

第一级:风格选择

{"cardName":"selectList","cardData":{"title":"你可以从下面挑选喜欢的风格,也可以直接告诉我你想要的其他风格。","items":[{"text":"极简主义","value":"极简主义"},{"text":"弥散风","value":"弥散风"},{"text":"水墨国风","value":"水墨国风"},{"text":"莫兰迪风","value":"莫兰迪风"}],"canReplay":true}}

第二级:主题选择

{"cardName":"selectList","cardData":{"title":"选一个喜欢的主题,打造你的专属壁纸。","items":[{"text":"青峦远山","value":"青峦远山"},{"text":"寒梅疏枝","value":"寒梅疏枝"},{"text":"江上孤舟","value":"江上孤舟"},{"text":"竹林清风","value":"竹林清风"}],"canReplay":true}}

第三级:场景选择

{"cardName":"selectList","cardData":{"title":"最后,选择你的壁纸尺寸和使用场景。","items":[{"text":"竖屏 · 锁屏","value":"竖屏 · 锁屏"},{"text":"竖屏 · 主屏","value":"竖屏 · 主屏"},{"text":"横屏 · 锁屏","value":"横屏 · 锁屏"},{"text":"横屏 · 主屏","value":"横屏 · 主屏"}],"canReplay":false}}

2.3 卡片交互的用户体验

阶段卡片标题选项数支持换一批支持重选
选择风格引导选择风格4
选择主题引导选择主题4
选择场景引导选择场景4

交互流程

用户看到 selectList 卡片 ↓ 点击某个选项(如"水墨国风") ↓ 前端将选项文本作为用户消息发送 ↓ 服务端识别关键词,跳过 LLM 意图识别 ↓ 构建下一级 selectList 卡片并推送 ↓ 前端自动刷新卡片

2.4 快捷命令与卡片的联动

当用户输入"换一批"时,服务端重新生成当前级别的选项并重新推送卡片:

# agent_routes.py - 换一批处理if"换一批"inuser_text:ifflow_manager.current_step==FlowStep.SELECT_STYLE:flow_result=flow_manager.handle_style_batch_refresh()elifflow_manager.current_step==FlowStep.SELECT_THEME:flow_result=awaitflow_manager.handle_theme_batch_refresh()# 重新构建并推送 selectList 卡片batch_event=build_style_options_card(title=flow_result["guidance"],options=flow_result["options"],# 新的随机选项task_id=task_id,request_id=request_id,has_next_batch=True,can_replay=True,)yieldf"data:{json.dumps(batch_event,ensure_ascii=False)}\n\n"

三、wallpaper 展示卡片

3.1 壁纸结果卡片

壁纸生成完成后,服务端推送wallpaper卡片展示结果:

# services/wallpaper_service.py# 步骤 5: 发送完成状态(卡片格式)text_event={"jsonrpc":"2.0","id":task_id,"result":{"taskId":task_id,"kind":"artifact-update","append":False,"lastChunk":True,"final":True,"artifact":{"artifactId":f"{task_id}-complete","parts":[{"kind":"data","data":{"cardsInfo":[{"cardName":"wallpaper","cardData":{"title":"壁纸生成完成","imageUrl":image_url,},"displayType":"DisplayFaCard"}]}}]}},"error":{"code":0,"message":"success"}}

3.2 壁纸卡片的呈现

生成的 JSON 使前端呈现类似以下效果:

┌─────────────────────────┐ │ ✨ 壁纸生成完成 │ │ │ │ ┌───────────────┐ │ │ │ │ │ │ │ 壁纸图片 │ │ │ │ │ │ │ └───────────────┘ │ │ │ │ 风格:水墨国风 │ │ 主题:青峦远山 │ │ │ │ [换一张] [重新开始] │ └─────────────────────────┘

3.3 与流程管理器的状态同步

# wallpaper_flow_service.pydefhandle_generate_complete(self,image_urls:List[str])->Dict[str,Any]:"""处理生成完成"""self.current_step=FlowStep.RESULT# 记录生成的壁纸forurlinimage_urls:self.generated_wallpapers.append({"url":url,"style":self.selected_style,"theme":self.selected_theme,})# 扣除免费次数ifself.free_credits_remaining>0:self.free_credits_remaining-=1return{"step":"result","message":"你的专属艺术壁纸已生成完成!","wallpapers":[{"url":url,"style":self.selected_style,"theme":self.selected_theme}forurlinimage_urls],"credits_remaining":self.free_credits_remaining,"has_regenerate":self.free_credits_remaining>0,}

四、SSE 事件驱动的前端更新

4.1 完整事件序列

从前端视角看,一次完整的壁纸生成过程如下:

前端发送 message/stream 请求 ↓(后端返回 SSE 流) 事件1: status-update → state: submitted → "正在理解您的需求..." 事件2: status-update → state: working → "正在优化描述..." 事件3: status-update → state: working → "正在生成图片..." 事件4: status-update → state: working → "正在构思画面构图..." 事件5: status-update → state: working → "正在勾勒轮廓..." ... 事件N: artifact-update → final: true → wallpaper 卡片

4.2 前端处理逻辑(示意)

// 前端 SSE 事件处理示意代码consteventSource=newEventSource('/agent/message');eventSource.onmessage=(event)=>{constdata=JSON.parse(event.data);constresult=data.result;switch(result.kind){case'status-update':// 更新进度状态updateProgress(result.status.message.parts[0].text);break;case'artifact-update':// 处理最终产物constcardsInfo=result.artifact.parts[0].data.cardsInfo;cardsInfo.forEach(card=>{switch(card.cardName){case'selectList':renderSelectListCard(card.cardData);break;case'wallpaper':renderWallpaperCard(card.cardData);break;}});break;}};

4.3 卡片替换逻辑

每次推送新的selectList卡片时,前端需要替换上一张卡片:

  • append: false:替换上一张卡片(风格→主题→场景的步骤推进)
  • append: true:追加到已有内容(闲聊的逐 token 输出)
风格选择卡片 (append: false) ↓ 用户选择风格 主题选择卡片 (append: false) → 替换风格卡片 ↓ 用户选择主题 场景选择卡片 (append: false) → 替换主题卡片 ↓ 用户选择场景 进度文本 (append: false) ↓ 逐条追加 进度文本 (append: true) ... ↓ 壁纸卡片 (append: false) → 替换所有内容

五、内容安全策略

5.1 肖像检测

# wallpaper_flow_service.pydefcheck_content_policy(user_text:str)->Tuple[bool,Optional[str]]:"""检查内容是否符合规范(肖像、文字等限制)"""# 肖像检测关键词portrait_keywords=["我","自己","本人","照片","肖像","人脸","头像","明星","网红","模特","人物","人像","自拍",]# 文字/水印检测关键词text_keywords=["文字","字体","写字","名字","姓名","签名","水印","logo","LOGO","标志","品牌",]# 检测肖像请求forkeywordinportrait_keywords:ifkeywordinuser_text:ifany(phraseinuser_textforphrasein["像我","我的照片","加入","添加","包含"]):returnFalse,"抱歉呀,为了版权和隐私安全,我暂时不能生成包含人物肖像的壁纸哦~"# 检测文字/水印请求forkeywordintext_keywords:ifkeywordinuser_text:ifany(phraseinuser_textforphrasein["添加","写上","显示","包含","要有"]):returnFalse,"抱歉,目前暂时无法在壁纸上添加文字、水印或 LOGO~"returnTrue,None

5.2 无关话题检测

# wallpaper_flow_service.pydefis_irrelevant_topic(user_text:str)->bool:"""判断是否是无关话题(闲聊、知识问答等)"""# 壁纸相关关键词wallpaper_keywords=["壁纸","背景","桌面","风格","主题","画面","图片","生成","创作","设计","图案","色彩","色调","锁屏","主屏","横屏","竖屏","尺寸","分辨率",]# 检查是否包含壁纸相关关键词forkeywordinwallpaper_keywords:ifkeywordinuser_text:returnFalse# 常见的无关问题类型irrelevant_patterns=["你是谁","你能做什么","天气","新闻","股票","帮我","写代码","翻译","计算",]forpatterninirrelevant_patterns:ifpatterninuser_text:returnTruereturnFalsedefget_irrelevant_response()->str:"""获取无关问题的统一回应"""return"我是你的专属壁纸创作助手,只专注于为你生成精美鸿蒙壁纸哦~我们继续设计你的专属壁纸吧!"

5.3 安全策略在流程中的位置

# agent_routes.py - generate_sse() 中的安全检查# 1. 内容政策检查(肖像、文字等)policy_passed,policy_reject_reason=check_content_policy(user_text)ifnotpolicy_passed:# 返回拒绝卡片reject_event={..."text":policy_reject_reason}yieldf"data:{json.dumps(reject_event)}\n\n"return# 2. 无关话题检查(闲聊、知识问答等)ifis_irrelevant_topic(user_text):# 引导回壁纸主题irrelevant_event={..."text":get_irrelevant_response()}yieldf"data:{json.dumps(irrelevant_event)}\n\n"return# 3. 通过检查后,继续处理正常流程

5.4 内容安全的交互设计

安全策略被触发时,用户看到的是友好的引导信息而非冷冰冰的错误提示:

违规类型用户输入示例系统回复
肖像请求“加入我的照片”“为了版权和隐私安全,不能生成包含人物肖像的壁纸哦~”
文字请求“写上’我爱你’”“暂时无法在壁纸上添加文字、水印或 LOGO~”
无关话题“帮我写代码”“只专注于为你生成精美鸿蒙壁纸哦~”

安全设计原则:内容安全策略应始终返回友好的引导信息而非冷冰冰的错误码,让用户感受到智能体的温度。同时,所有安全检查必须在进入主流程之前完成,避免浪费 API 调用资源。

六、卡片的扩展设计

6.1 卡片数据的可扩展性

当前cardData结构预留了扩展字段:

cardData={"title":"标题文本","items":[{"text":"选项","value":"value"}],# selectList"canReplay":True,# 支持重新选择# 可扩展字段"imageUrl":"...",# 壁纸展示卡片"style":"水墨国风",# 壁纸元信息"theme":"青峦远山","credits_remaining":5,# 剩余免费次数"has_regenerate":True,# 是否支持重新生成}

6.2 未来可扩展的卡片类型

卡片类型用途状态
imageGrid多张壁纸网格展示未实现
colorPicker颜色选择器未实现
progressBar自定义进度条未实现
shareCard壁纸分享卡片未实现

七、常见问题与解决方案

在前端卡片开发中,常见问题及解决方案如下:

问题原因解决方案
卡片不显示cardNamedisplayType字段错误检查 JSON 结构,确保使用DisplayFaCard
卡片重叠append设置为true多级选择流程中使用false
选项点击无响应前端未正确处理点击事件确保将选项文本作为用户消息发送
SSE 连接断开网络超时或服务端异常前端实现自动重连机制
图片加载失败imageUrl无效或过期检查图片 URL 的有效期

八、最佳实践总结

在鸿蒙壁纸大师的前端卡片交互开发中,以下最佳实践值得参考:

最佳实践说明收益
三级选择流程风格→主题→场景的渐进式引导降低用户决策成本
卡片替换机制使用append: false替换上一张卡片保持界面简洁
SSE 事件驱动实时推送进度和卡片更新提升用户体验
内容安全前置在主流程前完成安全检查避免 API 资源浪费
友好引导设计违规请求返回引导提示提升用户满意度
卡片可扩展性预留字段支持未来扩展降低维护成本

开发建议:卡片交互设计应以用户为中心,每一步的选择都应有明确的引导和反馈。同时,合理使用append字段控制卡片的替换与追加,避免界面混乱。

九、总结

本文深入解析了鸿蒙壁纸大师的前端卡片交互体系,核心要点:

  1. 三种卡片类型selectList(选择)、wallpaper(展示)、text(文本)
  2. 三级选择流程:风格→主题→场景,每级通过卡片替换推进
  3. SSE 事件驱动:status-update 推送进度,artifact-update 推送卡片
  4. 内容安全策略:肖像检测、文字检测、无关话题过滤,确保合规
  5. 友好的交互设计:违规请求返回引导提示而非错误信息
  6. 卡片可扩展性:预留字段支持未来更多交互类型

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!

相关资源

  • 华为 A2A DisplayFaCard 卡片规范
  • 华为智能体交互设计指南
  • A2A 协议规范 - 华为
  • 华为开发者联盟 - 文档中心
  • JSON-RPC 2.0 规范
  • FastAPI 官方文档
  • 火山引擎 - 豆包大模型
  • Python asyncio 官方文档