HarmonyOS 鸿蒙Next 6如何渲染扣子智能体的流式富文本回答(含 markdown / 代码块 / 图片)?

HarmonyOS 鸿蒙Next 6如何渲染扣子智能体的流式富文本回答(含 markdown / 代码块 / 图片)? 问题描述:扣子智能体返回流式 markdown 回答(含代码块、图片、列表),需在鸿蒙侧实时拼接流式片段,解析 markdown 并渲染为原生组件,避免渲染卡顿,如何实现? 关键字:鸿蒙 6、扣子智能体、流式富文本、markdown 解析、实时渲染

3 回复

鸿蒙 6 渲染扣子智能体流式富文本的核心是「流式片段补全 + 轻量 Markdown 解析 + 原生组件分段渲染」,以下是极简实战方案,兼顾流畅性和易实现性:

一、核心步骤(极简版)

1. 前置准备

  • 安装鸿蒙适配的轻量 Markdown 解析库:ohpm install @ohos/marked --save
  • 配置网络权限(INTERNET)用于加载图片。

2. 核心代码(一站式实现)

import marked from '@ohos/marked';
import webSocket from '@ohos.net.webSocket';
import { LazyImage } from '@ohos/components';

@Entry
@Component
struct KouziRichText {
  @State renderList: Array<{ type: string; content: any }> = []; // 渲染列表
  private unclosedCode: string = ''; // 缓存未闭合的代码块
  private ws: webSocket.WebSocket | null = null;

  // 1. 解析Markdown片段为原生组件配置
  parseMarkdown(chunk: string) {
    // 补全未闭合的代码块
    let fullChunk = this.unclosedCode + chunk;
    const codeEndIndex = fullChunk.lastIndexOf('```');
    if (fullChunk.includes('```') && codeEndIndex === fullChunk.length - 3) {
      this.unclosedCode = ''; // 代码块闭合,清空缓存
    } else if (fullChunk.includes('```')) {
      this.unclosedCode = fullChunk.slice(codeEndIndex); // 缓存未闭合部分
      fullChunk = fullChunk.slice(0, codeEndIndex);
    }

    // 自定义解析规则:映射Markdown到原生组件类型
    const renderer = new marked.Renderer();
    renderer.code = (code, lang) => ({ type: 'code', content: { code, lang } });
    renderer.image = (url) => ({ type: 'image', content: url });
    renderer.listitem = (text) => ({ type: 'list', content: text });
    renderer.paragraph = (text) => ({ type: 'text', content: text });

    // 解析并合并到渲染列表(微任务执行,不卡UI)
    queueMicrotask(() => {
      const parsed = marked.parse(fullChunk, { renderer });
      this.renderList = [...this.renderList, ...(Array.isArray(parsed) ? parsed : [parsed])];
    });
  }

  // 2. 连接扣子智能体流式接口
  connectAgent() {
    this.ws = webSocket.createWebSocket();
    this.ws.connect('wss://www.kuaishou.com/openapi/v1/agent/streamChat');
    this.ws.on('open', () => {
      this.ws?.send(JSON.stringify({
        agent_id: '你的智能体ID',
        token: '你的智能体token',
        query: '讲解鸿蒙图片上传,含代码和列表'
      }));
    });
    // 接收流式片段并解析
    this.ws.on('message', (chunk) => {
      const text = new TextDecoder().decode(chunk);
      this.parseMarkdown(text);
    });
  }

  build() {
    Column() {
      // 3. 渲染原生组件
      Scroll() {
        Column() {
          ForEach(this.renderList, (item) => {
            MatchCase(item.type) {
              case 'text': Text(item.content).fontSize(14).lineHeight(24);
              case 'code': Text(`【${item.content.lang}代码】点击查看`).backgroundColor('#f5f5f5').padding(8).onClick(() => {
                // 代码块弹窗展示
                AlertDialog.show({ message: item.content.code });
              });
              case 'image': LazyImage({ src: item.content }).width('100%').height(200).objectFit(ImageFit.Contain);
              case 'list': Row().children([Text('• '), Text(item.content)]);
            }
          });
        }.padding(10);
      }.flexGrow(1);

      Button('发送提问').onClick(() => this.connectAgent()).margin(10);
    }.width('100%').height('100%');
  }
}

二、关键说明(避坑核心)

  1. 流式片段补全:仅缓存未闭合的代码块(```),避免解析出畸形内容;
  2. 轻量解析:用marked将 Markdown 转为「文本 / 代码 / 图片 / 列表」类型,直接映射鸿蒙原生组件;
  3. 性能优化
    • 解析逻辑放queueMicrotask,不阻塞流式接收;
    • 图片用LazyImage懒加载,代码块弹窗展示(避免大段代码卡 UI);
  4. 极简适配:无需复杂工具类,所有逻辑一站式实现,新手也能快速上手。

三、核心避坑点

  1. Authorization/agent_id需替换为自己的扣子智能体配置;
  2. 流式片段解码用TextDecoder('utf-8'),避免中文乱码;
  3. 代码块 / 列表等特殊元素需自定义解析规则,不能直接渲染 HTML。

更多关于HarmonyOS 鸿蒙Next 6如何渲染扣子智能体的流式富文本回答(含 markdown / 代码块 / 图片)?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next 6中,渲染扣子智能体的流式富文本内容,主要使用ArkUI的Web组件或自定义组件实现。对于Markdown和代码块,可通过集成第三方解析库(如markdown-it)将文本转换为HTML,再由Web组件渲染。图片渲染则使用Image组件,根据流式数据中的URL动态加载。整个过程需结合数据监听和组件动态更新机制,以实现流式内容的逐段渲染。

在HarmonyOS Next中渲染扣子智能体的流式富文本,关键在于结合ArkUI的声明式UI与动态更新能力。以下是核心实现方案:

  1. 流式数据拼接与状态管理

    • 使用@State@Link装饰器管理文本内容字符串,流式数据到达时直接追加。
    • 建议采用StringBuilder或数组缓存片段,避免频繁触发UI更新。
  2. Markdown解析与组件映射

    • 集成轻量级Markdown解析库(如commonmark-java的ArkTS移植版),将流式文本转换为结构化数据(AST)。
    • 建立AST节点到ArkUI组件的映射规则:
      • 标题/段落 → Text组件配合字体样式
      • 代码块 → Text + TextDecorationType.Underline + 等宽字体,或自定义[@Component](/user/Component)实现语法高亮
      • 图片 → Image组件,通过PixelMap或网络链接加载
      • 列表 → Row + Text组合
  3. 实时渲染优化

    • 使用LazyForEach按片段增量渲染,避免长文本全量刷新。
    • 对图片实现懒加载,监听VisibleAreaChange事件控制加载时机。
    • 复杂代码块采用异步解析,防止阻塞主线程。
  4. 流式处理架构示例

    [@Component](/user/Component)
    struct StreamRenderer {
      @State segments: string[] = []
    
      build() {
        List() {
          ForEach(this.segments, (segment) => {
            MarkdownBlock({ content: segment })
          })
        }
      }
    
      // 流式数据入口
      appendStreamData(chunk: string) {
        this.segments.push(chunk)
      }
    }
    
  5. 性能关键点

    • 解析与渲染分离:在后台线程完成Markdown到AST的转换,仅将AST结果交主线程渲染。
    • 组件复用:对相同类型的富文本节点(如连续段落)启用组件复用机制。
    • 避免深层嵌套:控制Markdown转换后的组件层级,减少布局计算开销。

此方案通过动态组件生成与增量更新平衡了实时性要求与渲染性能,可直接应用于智能对话、实时日志等流式富文本场景。

回到顶部