模仿ai数据流 开箱即用

17 阅读1分钟
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>AI 流式输出 + Markdown渲染</title>
  <style>
    body { max-width: 800px; margin: 20px auto; padding: 0 20px; }
    #result {
      white-space: pre-wrap;
      border: 1px solid #eee;
      padding: 16px;
      min-height: 200px;
      margin-top: 20px;
      line-height: 1.6;
    }
    #result h1, #result h2, #result h3 { margin: 10px 0; }
    #result strong { color: #007bff; }
    #result code { background: #f4f4f4; padding: 2px 4px; border-radius: 4px; }
    #result pre { background: #f4f4f4; padding: 10px; overflow-x: auto; }
    #btn { padding: 10px 20px; font-size: 16px; cursor: pointer; }
  </style>
</head>
<body>
  <h3>AI 流式输出演示(渲染Markdown)</h3>
  <button id="btn">开始提问:介绍一下JavaScript</button>
  <div id="result"></div>

  <!-- 👇 加这一行:引入 Markdown 渲染库(和豆包用的一样) -->
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>

  <script>
    const btn = document.getElementById('btn');
    const result = document.getElementById('result');

    // 👇 用来存完整的回答文本
    let fullText = '';

    btn.onclick = async () => {
      btn.disabled = true;
      btn.innerText = 'AI 正在流式输出...';
      result.innerText = '';
      fullText = '';

      try {
        const response = await fetch("https://open.bigmodel.cn/api/paas/v4/chat/completions", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            "Authorization": "96f0813aca214bb486892a55f7148622.oQFhjTVnwDHvmnEC",
          },
          body: JSON.stringify({
            model: "glm-4-flash",
            messages: [{ role: "user", content: "介绍一下JavaScript" }],
            stream: true
          })
        });

        const reader = response.body.getReader();
        const decoder = new TextDecoder();

        while (true) {
          const { done, value } = await reader.read();
          if (done) break;

          const chunk = decoder.decode(value, { stream: true });
          const lines = chunk.split("\n").filter(i => i);

          for (let line of lines) {
            if (line.startsWith("data: ")) {
              const jsonStr = line.replace("data: ", "");
              if (jsonStr === "[DONE]") continue;

              try {
                const data = JSON.parse(jsonStr);
                const text = data.choices[0]?.delta?.content || "";

                // 👇 拼接完整文本
                fullText += text;

                // 👇 关键:把 Markdown 渲染成 HTML(豆包就是这么做的!)
                result.innerHTML = marked.parse(fullText);

              } catch (e) {}
            }
          }
        }
      } catch (err) {
        result.innerText = "错误:" + err.message;
      } finally {
        btn.innerText = "重新提问";
        btn.disabled = false;
      }
    };
  </script>
</body>
</html>


总结:

  • fetch 发请求 → stream: true

  • reader.read() 接收二进制流

  • 转字符串 → 按行拆分

  • data: 后面的 JSON

  • choices[0].delta.content 拼文字 → 渲染页面

备注:

Markdown:带「排版标记」的纯文本字符串

直接复制到.html,然后到open.bigmodel.cn/apikey/plat… 平台拿取一个api的key值

这段代码,就是豆包 /chat/completion 接口的工作方式 + 渲染方式