// 以流式方式请求LLM大模型接口,并打印流式返回内容 async function requestLLMStream({ apiKey, model, messages, onSegment }) { const response = await fetch('https://ark.cn-beijing.volces.com/api/v3/bots/chat/completions', { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json', 'Accept': 'text/event-stream', 'Cache-Control': 'no-cache', }, body: JSON.stringify({ model, stream: true, stream_options: { include_usage: true }, messages, }), }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const reader = response.body.getReader(); const decoder = new TextDecoder('utf-8'); let done = false; let buffer = ''; let content = ''; let pendingText = ''; // 待处理的文本片段 // 分段分隔符 const segmentDelimiters = /[,。:;!?,.:;!?]/; while (!done) { const { value, done: doneReading } = await reader.read(); done = doneReading; if (value) { const chunk = decoder.decode(value, { stream: true }); buffer += chunk; // 处理SSE格式的数据 const lines = buffer.split('\n'); buffer = lines.pop(); // 最后一行可能是不完整的,留到下次 for (const line of lines) { if (!line.trim()) continue; // 检查是否是SSE格式的数据行 if (line.startsWith('data:')) { const jsonStr = line.substring(5).trim(); // 移除 'data:' 前缀 if (jsonStr === '[DONE]') { console.log('LLM SSE流结束'); // 处理最后的待处理文本(无论长度是否大于5个字) if (pendingText.trim() && onSegment) { console.log('处理最后的待处理文本:', pendingText.trim()); await onSegment(pendingText.trim(), true); } continue; } try { const obj = JSON.parse(jsonStr); if (obj.choices && obj.choices[0] && obj.choices[0].delta && obj.choices[0].delta.content) { const deltaContent = obj.choices[0].delta.content; content += deltaContent; pendingText += deltaContent; console.log('LLM内容片段:', deltaContent); // 检查是否包含分段分隔符 if (segmentDelimiters.test(pendingText)) { // 按分隔符分割文本 const segments = pendingText.split(segmentDelimiters); // 重新组合处理:只处理足够长的完整段落 let accumulatedText = ''; let hasProcessed = false; for (let i = 0; i < segments.length - 1; i++) { const segment = segments[i].trim(); if (segment) { accumulatedText += segment; // 找到分隔符 const delimiterMatch = pendingText.match(segmentDelimiters); if (delimiterMatch) { accumulatedText += delimiterMatch[0]; } // 如果累积文本长度大于5个字,处理它 if (accumulatedText.length > 6 && onSegment) { console.log('检测到完整段落:', accumulatedText); await onSegment(accumulatedText, false); hasProcessed = true; accumulatedText = ''; // 重置 } } } // 更新pendingText if (hasProcessed) { // 保留未处理的累积文本和最后一个不完整段落 pendingText = accumulatedText + (segments[segments.length - 1] || ''); } } } } catch (e) { console.error('解析LLM SSE数据失败:', e, '原始数据:', jsonStr); } } else if (line.startsWith('event: ') || line.startsWith('id: ') || line.startsWith('retry: ')) { // 忽略SSE的其他字段 continue; } } } } // 返回完整内容 return content; } export { requestLLMStream };