@lobehub/chat
Version:
Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.
132 lines (126 loc) • 4.25 kB
text/typescript
import OpenAI from 'openai';
/**
* make the OpenAI response data as a stream
*/
export const transformResponseToStream = (data: OpenAI.ChatCompletion) =>
new ReadableStream({
start(controller) {
const choices = data.choices || [];
const first = choices[0];
// 兼容:非流式里 DeepSeek 等会把“深度思考”放在 message.reasoning_content
const message: any = first?.message ?? {};
const reasoningText =
typeof message.reasoning_content === 'string' && message.reasoning_content.length > 0
? message.reasoning_content
: null;
if (reasoningText) {
controller.enqueue({
choices: [
{
delta: { content: null, reasoning_content: reasoningText, role: 'assistant' },
finish_reason: null,
index: first?.index ?? 0,
logprobs: first?.logprobs ?? null,
},
],
created: data.created,
id: data.id,
model: data.model,
object: 'chat.completion.chunk',
} as unknown as OpenAI.ChatCompletionChunk);
}
const chunk: OpenAI.ChatCompletionChunk = {
choices: choices.map((choice: OpenAI.ChatCompletion.Choice) => ({
delta: {
content: choice.message.content,
role: choice.message.role,
tool_calls: choice.message.tool_calls?.map(
(tool, index): OpenAI.ChatCompletionChunk.Choice.Delta.ToolCall => ({
function: tool.function,
id: tool.id,
index,
type: tool.type,
}),
),
},
finish_reason: null,
index: choice.index,
logprobs: choice.logprobs,
})),
created: data.created,
id: data.id,
model: data.model,
object: 'chat.completion.chunk',
};
controller.enqueue(chunk);
if (data.usage) {
controller.enqueue({
choices: [],
created: data.created,
id: data.id,
model: data.model,
object: 'chat.completion.chunk',
usage: data.usage,
} as unknown as OpenAI.ChatCompletionChunk);
}
controller.enqueue({
choices: choices.map((choice: OpenAI.ChatCompletion.Choice) => ({
delta: {
content: null,
role: choice.message.role,
},
finish_reason: choice.finish_reason,
index: choice.index,
logprobs: choice.logprobs,
})),
created: data.created,
id: data.id,
model: data.model,
object: 'chat.completion.chunk',
system_fingerprint: data.system_fingerprint,
} as OpenAI.ChatCompletionChunk);
controller.close();
},
});
/**
* transform the OpenAI Response API data to stream format for non-streaming responses
*/
export const transformResponseAPIToStream = (data: OpenAI.Responses.Response) =>
new ReadableStream({
start(controller) {
// Check if output exists and is an array
if (data.output && Array.isArray(data.output)) {
data.output.forEach((output) => {
switch (output.type) {
case 'message': {
// Check if content exists and is an array
if (output.content && Array.isArray(output.content)) {
output.content.forEach((content) => {
switch (content.type) {
case 'output_text': {
// Only emit delta if text exists
if (content.text) {
controller.enqueue({
delta: content.text,
type: 'response.output_text.delta',
});
}
break;
}
}
});
}
break;
}
}
});
}
// Always send response.completed event
controller.enqueue({
response: data,
sequence_number: 999,
type: 'response.completed',
} as OpenAI.Responses.ResponseStreamEvent);
controller.close();
},
});