diff --git a/src/services/deepseek.ts b/src/services/deepseek.ts index 945d5eb..b973906 100644 --- a/src/services/deepseek.ts +++ b/src/services/deepseek.ts @@ -112,29 +112,53 @@ export async function sendMessageStream( const decoder = new TextDecoder(); let fullContent = ""; + let buffer = ""; // Buffer for incomplete lines while (true) { const { done, value } = await reader.read(); if (done) break; - const chunk = decoder.decode(value, { stream: true }); - const lines = chunk.split("\n").filter((line) => line.trim() !== ""); + // Append new data to buffer + buffer += decoder.decode(value, { stream: true }); + + // Process complete lines only + const lines = buffer.split("\n"); + // Keep last incomplete line in buffer + buffer = lines.pop() || ""; for (const line of lines) { - if (line.startsWith("data: ")) { - const data = line.slice(6); - if (data === "[DONE]") continue; + const trimmed = line.trim(); + if (!trimmed || !trimmed.startsWith("data: ")) continue; + + const data = trimmed.slice(6); + if (data === "[DONE]") continue; - try { - const parsed = JSON.parse(data); - const content = parsed.choices?.[0]?.delta?.content || ""; - if (content) { - fullContent += content; - onChunk(content); - } - } catch { - // Ignore parse errors + try { + const parsed = JSON.parse(data); + const content = parsed.choices?.[0]?.delta?.content || ""; + if (content) { + fullContent += content; + onChunk(content); } + } catch { + // Incomplete JSON - will be handled in next chunk + } + } + } + + // Process any remaining buffer + if (buffer.trim().startsWith("data: ")) { + const data = buffer.trim().slice(6); + if (data !== "[DONE]") { + try { + const parsed = JSON.parse(data); + const content = parsed.choices?.[0]?.delta?.content || ""; + if (content) { + fullContent += content; + onChunk(content); + } + } catch { + // Ignore final parse error } } }