You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解析OpenAIStream以消除空格并正确格式化列表?

问题修复方案

针对你遇到的流式返回结果多余空格、列表解析失败问题,以下是具体修复步骤:

核心问题分析

  1. 流式传输时对每个chunk单独trim,破坏了原始文本的换行和空格结构
  2. 格式化函数提前将所有空白字符替换为单个空格,丢失了列表依赖的换行符
  3. OpenAIStream中过滤了早期包含换行的chunk,导致列表开头内容丢失
  4. 中间消息更新时额外添加空格,造成冗余空格堆积

具体修复代码

1. 修正generateText中的chunk传递

移除chunk的trim操作,保留原始文本结构:

// 原代码
onUpdate(text.trim(), isFirstChunk, false);
// 修改为
onUpdate(text, isFirstChunk, false);

2. 调整handleSubmit中的chunk积累方式

存储原始chunk,不再提前trim:

// 原代码
messageChunks.push(chunk.trim());
// 修改为
messageChunks.push(chunk);

同时修正中间消息更新逻辑,避免额外添加空格:

// 原代码
text: prevMessages[lastSystemMessageIndex].text + ' ' + chunk.trim(),
// 修改为
text: prevMessages[lastSystemMessageIndex].text + chunk,

3. 删除OpenAIStream中的换行过滤逻辑

移除导致早期列表内容丢失的代码块:

// 删除以下代码
if (counter < 2 && text.includes("\n")) {
    return;
}

4. 重写formatText函数,正确解析列表

保留换行符先处理列表,再清理冗余空格:

const formatText = (text) => {
    // 按换行分割文本,过滤空行
    const lines = text.split('\n').map(line => line.trim()).filter(line => line);
    let formattedParts = [];
    let currentList = [];

    // 判断是否为有序列表项
    const isNumberedListItem = (line) => /^\d+\.\s+/.test(line);

    for (const line of lines) {
        if (isNumberedListItem(line)) {
            // 提取列表项编号和内容
            const [, number, content] = line.match(/^(\d+)\.\s+(.*)$/);
            currentList.push(`<li>${number}. ${content.replace(/\s+/g, ' ')}</li>`);
        } else {
            // 如果正在构建列表,先闭合列表
            if (currentList.length > 0) {
                formattedParts.push(`<ol>${currentList.join('')}</ol>`);
                currentList = [];
            }
            // 清理普通文本中的冗余空格
            formattedParts.push(line.replace(/\s+/g, ' '));
        }
    }

    // 添加剩余的列表项
    if (currentList.length > 0) {
        formattedParts.push(`<ol>${currentList.join('')}</ol>`);
    }

    // 拼接所有内容,修正标点符号前后的空格
    let formattedText = formattedParts.join(' ');
    formattedText = formattedText
        .replace(/\s+([.,!?:;])/g, '$1')
        .replace(/([.,!?:;])\s+/g, '$1 ');
    
    // 解码HTML实体
    formattedText = he.decode(formattedText);
    return formattedText;
};

5. 修正最终消息格式化逻辑

直接拼接原始chunk,不再提前替换空格:

// 原代码
const formattedMessage = formatText(messageChunks.join(' ').replace(/\s+/g, ' '));
// 修改为
const fullText = messageChunks.join('');
const formattedMessage = formatText(fullText);

修复原理说明

  • 保留原始chunk的换行和空格结构,确保列表的格式信息不丢失
  • 先按行解析列表项,再清理冗余空格,避免破坏列表结构
  • 移除不必要的chunk过滤,确保所有返回内容都被处理
  • 修正中间消息的空格添加逻辑,避免冗余空格堆积

内容的提问来源于stack exchange,提问作者Unnamed Mistress

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 22:32:47