+
32
-

为啥浏览器中js请求gemini兼容openai的api出现断句?

为啥浏览器中js请求gemini兼容openai的api出现断句?是不是const chunk = decoder.decode(value);有问题?

800_auto

实际获得数据eventstream是

data: {"choices":[{"delta":{"content":"我","role":"assistant"},"index":0}],"created":1750638999,"id":"l6FYaK3oJv_bgLUPvdfCsQU","model":"gemini-2.0-flash","object":"chat.completion.chunk"}

data: {"choices":[{"delta":{"content":"是一个大型语言","role":"assistant"},"index":0}],"created":1750638999,"id":"l6FYaK3oJv_bgLUPvdfCsQU","model":"gemini-2.0-flash","object":"chat.completion.chunk"}

data: {"choices":[{"delta":{"content":"模型,由 Google 训练。\n","role":"assistant"},"finish_reason":"stop","index":0}],"created":1750638999,"id":"l6FYaK3oJv_bgLUPvdfCsQU","model":"gemini-2.0-flash","object":"chat.completion.chunk"}

data: [DONE]


try {
                // 3. 发送请求到后端(即当前PHP文件)
                const response = await fetch("https://generativelanguage.googleapis.com/v1beta/openai", {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body:JSON.stringify(resdata.postdata) ,
                });

                if (!response.ok) {
                    throw new Error(`HTTP error! status: ${response.status}`);
                }

                // 4. 处理流式响应
                const reader = response.body.getReader();
                const decoder = new TextDecoder();
                let assistantResponse = '';
                

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

                    const chunk = decoder.decode(value);
                    const lines = chunk.split('\n');

                    for (const line of lines) {
                        if (line.startsWith('data: ')) {
                            const jsonStr = line.substring(6);
                            if (jsonStr.trim() === '[DONE]') {
                                break;
                            }
                            try {
                                const parsed = JSON.parse(jsonStr);
                                const content = parsed.choices[0]?.delta?.content || '';
                                if (content) {
                                    assistantResponse += content;
                                    assistantMessageDiv.innerText = assistantResponse; // 使用innerText防止XSS
                                    scrollToBottom();
                                }
                            } catch (e) {
                                console.error('Error parsing stream JSON:', e);
                            }
                        }
                    }
                }

                // 将完整的AI回复添加到历史记录
                chatHistory.push({
                    role: 'assistant', content: assistantResponse
                });

            } catch (error) {
                console.error('Fetch error:', error);
                assistantMessageDiv.innerText = '抱歉,我好像出错了。请稍后再试。';
            } finally {
                // 重新启用按钮
                sendButton.disabled = false;
                messageInput.focus();
            }
      
    } else {
      console.error('请求失败:', responseurl.status);
    }

           


网友回复

+
2
-

主要问题:未处理不完整的消息块:

你的代码 const chunk = decoder.decode(value); const lines = chunk.split('\n'); 是在拿到一个数据块后立即按换行符分割。

如果一个数据块是 data: {"choices":[{"delta":{"content":"我是一个 (注意,JSON 在这里被截断了),你的代码会尝试解析 {"choices":[{"delta":{"content":"我是一个,这必然导致 JSON.parse 失败,然后这个 "我是一个" 的内容就永久丢失了。

次要问题:对 [DONE] 的处理逻辑有误:

在你的 for 循环中,当遇到 data: [DONE] 时,你使用了 break;

修复后

try {
    // 3. 发送请求到后端
    const response = await fetch(resdata.url, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(resdata.postdata),
    });

    if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }

    // 4. 处理流式响应
    const reader = response.body.getReader();
    const decoder = new TextDecoder("utf-8");
    let assistantResponse = '';
    assistantMessageDiv.innerHTML = ''; // 清除“思考中”动画

    // --- 新增代码:缓冲区 ---
    let buffer = ''; 

    while (true) {
        const { value, done } = await reader.read();
        
        // 当流结束时,done 为 true
        if (done) {
            // 在退出前,检查缓冲区是否还有剩余的、未处理的数据
            if (buffer.length > 0) {
                 // 这种情况不常见,但为了健壮性最好加上
                 console.warn('Stream ended with unprocessed data in buffer:', buffer);
            }
            break; // 正常退出循环
        }

        // 将新收到的数据块解码并追加到缓冲区
        // 使用 { stream: true } 可以更好地处理多字节字符(如中文)被截断的情况
        const chunk = decoder.decode(value, { stream: true });
        buffer += chunk;

        // -...

点击查看剩余70%

我知道答案,我要回答