Skip to content

Commit b1d4357

Browse files
committed
feat: Log condensed streaming responses for chat completions
1 parent f334308 commit b1d4357

File tree

2 files changed

+51
-12
lines changed

2 files changed

+51
-12
lines changed

src/routes/chat-completions/handler.ts

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,74 @@ import type { Context } from "hono"
33
import { streamSSE, type SSEMessage } from "hono/streaming"
44

55
import type { ChatCompletionsPayload } from "~/services/copilot/chat-completions/types"
6+
import type { ChatCompletionChunk } from "~/services/copilot/chat-completions/types-streaming"
67

78
import { logger } from "~/lib/logger"
89
import { chatCompletions } from "~/services/copilot/chat-completions/service"
910
import { chatCompletionsStream } from "~/services/copilot/chat-completions/service-streaming"
1011

12+
function createCondensedStreamingResponse(
13+
finalChunk: ChatCompletionChunk,
14+
collectedContent: string,
15+
) {
16+
return {
17+
id: finalChunk.id,
18+
model: finalChunk.model,
19+
created: finalChunk.created,
20+
object: "chat.completion",
21+
system_fingerprint: finalChunk.system_fingerprint,
22+
usage: finalChunk.usage,
23+
choices: [
24+
{
25+
index: 0,
26+
finish_reason: finalChunk.choices[0].finish_reason,
27+
message: {
28+
role: "assistant",
29+
content: collectedContent,
30+
},
31+
content_filter_results: finalChunk.choices[0].content_filter_results,
32+
},
33+
],
34+
}
35+
}
36+
1137
export async function handlerStreaming(c: Context) {
1238
const payload = await c.req.json<ChatCompletionsPayload>()
1339

14-
// Log the request
40+
// Log the request at the beginning for both streaming and non-streaming cases
1541
await logger.logRequest("/chat/completions", "POST", payload)
1642

1743
if (payload.stream) {
1844
const response = await chatCompletionsStream(payload)
1945

20-
// For streaming responses, we'll log the initial response setup
21-
await logger.logResponse("/chat/completions", {
22-
type: "stream",
23-
timestamp: new Date().toISOString(),
24-
model: payload.model,
25-
})
46+
// For collecting the complete streaming response
47+
let collectedContent = ""
48+
let finalChunk: ChatCompletionChunk | null = null
2649

2750
return streamSSE(c, async (stream) => {
2851
for await (const chunk of response) {
52+
const data = JSON.parse(chunk.data ?? "{}") as ChatCompletionChunk
53+
54+
// Keep track of the latest chunk for metadata
55+
finalChunk = data
56+
57+
// Accumulate content from each delta
58+
if (data.choices[0].delta.content) {
59+
collectedContent += data.choices[0].delta.content
60+
}
61+
2962
await stream.writeSSE(chunk as SSEMessage)
3063
}
64+
65+
// After streaming completes, log the condensed response
66+
if (finalChunk) {
67+
const condensedResponse = createCondensedStreamingResponse(
68+
finalChunk,
69+
collectedContent,
70+
)
71+
72+
await logger.logResponse("/chat/completions", condensedResponse)
73+
}
3174
})
3275
}
3376

src/services/copilot/chat-completions/types-streaming.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ interface Usage {
5151
total_tokens: number
5252
}
5353

54-
interface ChatCompletionResponse {
54+
export interface ChatCompletionChunk {
5555
choices: [Choice]
5656
created: number
5757
object: "chat.completion.chunk"
@@ -61,7 +61,3 @@ interface ChatCompletionResponse {
6161
prompt_filter_results?: Array<PromptFilterResult>
6262
usage?: Usage | null
6363
}
64-
65-
export interface ChatCompletionsChunk {
66-
data: ChatCompletionResponse
67-
}

0 commit comments

Comments
 (0)