@@ -104,7 +104,7 @@ export function* createChatCompletionStream(request: ChatCompletionRequest): Gen
104
104
// 验证模型
105
105
const model = findModelById ( request . model ) ;
106
106
if ( ! model ) {
107
- const errorChunk = `data: ${ JSON . stringify ( formatErrorResponse ( `模型 '${ request . model } ' 不存在` ) ) } \\n\ \n` ;
107
+ const errorChunk = `data: ${ JSON . stringify ( formatErrorResponse ( `模型 '${ request . model } ' 不存在` ) ) } \n \n` ;
108
108
yield errorChunk ;
109
109
return ;
110
110
}
@@ -116,7 +116,7 @@ export function* createChatCompletionStream(request: ChatCompletionRequest): Gen
116
116
. find ( msg => msg . role === 'user' ) ;
117
117
118
118
if ( ! lastUserMessage ) {
119
- const errorChunk = `data: ${ JSON . stringify ( formatErrorResponse ( '未找到用户消息' ) ) } \\n\ \n` ;
119
+ const errorChunk = `data: ${ JSON . stringify ( formatErrorResponse ( '未找到用户消息' ) ) } \n \n` ;
120
120
yield errorChunk ;
121
121
return ;
122
122
}
@@ -126,21 +126,31 @@ export function* createChatCompletionStream(request: ChatCompletionRequest): Gen
126
126
127
127
const id = generateChatCompletionId ( ) ;
128
128
const timestamp = getCurrentTimestamp ( ) ;
129
+ const systemFingerprint = `fp_${ Math . random ( ) . toString ( 36 ) . substr ( 2 , 10 ) } _mock` ;
129
130
130
- // 发送开始chunk
131
+ // 发送第一个chunk - role 和空 content
131
132
const startChunk : ChatCompletionStreamChunk = {
132
133
id,
133
134
object : 'chat.completion.chunk' ,
134
135
created : timestamp ,
135
136
model : request . model ,
137
+ system_fingerprint : systemFingerprint ,
136
138
choices : [ {
137
139
index : 0 ,
138
- delta : { role : 'assistant' } ,
139
- finish_reason : undefined
140
- } ]
140
+ delta : {
141
+ role : 'assistant' ,
142
+ content : ''
143
+ } ,
144
+ logprobs : null ,
145
+ finish_reason : null
146
+ } ] ,
147
+ usage : null
141
148
} ;
142
149
143
- yield `data: ${ JSON . stringify ( startChunk ) } \\n\\n` ;
150
+ yield `data: ${ JSON . stringify ( startChunk ) } \n\n` ;
151
+
152
+ let totalTokens = 0 ;
153
+ let completionTokens = 0 ;
144
154
145
155
// 如果有预定义的流式chunk,使用它们
146
156
if ( testCase . streamChunks && testCase . streamChunks . length > 0 ) {
@@ -150,34 +160,42 @@ export function* createChatCompletionStream(request: ChatCompletionRequest): Gen
150
160
object : 'chat.completion.chunk' ,
151
161
created : timestamp ,
152
162
model : request . model ,
163
+ system_fingerprint : systemFingerprint ,
153
164
choices : [ {
154
165
index : 0 ,
155
166
delta : { content : chunkContent } ,
156
- finish_reason : undefined
157
- } ]
167
+ logprobs : null ,
168
+ finish_reason : null
169
+ } ] ,
170
+ usage : null
158
171
} ;
159
172
160
- yield `data: ${ JSON . stringify ( chunk ) } \\n\\n` ;
173
+ completionTokens += calculateTokens ( chunkContent ) ;
174
+ yield `data: ${ JSON . stringify ( chunk ) } \n\n` ;
161
175
}
162
176
} else {
163
177
// 否则将完整响应分割成chunks
164
178
const words = testCase . response . split ( ' ' ) ;
165
- for ( let i = 0 ; i < words . length ; i += 3 ) {
166
- const chunkContent = words . slice ( i , i + 3 ) . join ( ' ' ) + ( i + 3 < words . length ? ' ' : '' ) ;
179
+ for ( let i = 0 ; i < words . length ; i += 1 ) {
180
+ const chunkContent = words [ i ] + ( i < words . length - 1 ? ' ' : '' ) ;
167
181
168
182
const chunk : ChatCompletionStreamChunk = {
169
183
id,
170
184
object : 'chat.completion.chunk' ,
171
185
created : timestamp ,
172
186
model : request . model ,
187
+ system_fingerprint : systemFingerprint ,
173
188
choices : [ {
174
189
index : 0 ,
175
190
delta : { content : chunkContent } ,
176
- finish_reason : undefined
177
- } ]
191
+ logprobs : null ,
192
+ finish_reason : null
193
+ } ] ,
194
+ usage : null
178
195
} ;
179
196
180
- yield `data: ${ JSON . stringify ( chunk ) } \\n\\n` ;
197
+ completionTokens += calculateTokens ( chunkContent ) ;
198
+ yield `data: ${ JSON . stringify ( chunk ) } \n\n` ;
181
199
}
182
200
}
183
201
@@ -188,6 +206,7 @@ export function* createChatCompletionStream(request: ChatCompletionRequest): Gen
188
206
object : 'chat.completion.chunk' ,
189
207
created : timestamp ,
190
208
model : request . model ,
209
+ system_fingerprint : systemFingerprint ,
191
210
choices : [ {
192
211
index : 0 ,
193
212
delta : {
@@ -196,28 +215,46 @@ export function* createChatCompletionStream(request: ChatCompletionRequest): Gen
196
215
arguments : JSON . stringify ( testCase . functionCall . arguments )
197
216
}
198
217
} ,
199
- finish_reason : undefined
200
- } ]
218
+ logprobs : null ,
219
+ finish_reason : null
220
+ } ] ,
221
+ usage : null
201
222
} ;
202
223
203
- yield `data: ${ JSON . stringify ( functionChunk ) } \\n\ \n` ;
224
+ yield `data: ${ JSON . stringify ( functionChunk ) } \n \n` ;
204
225
}
205
226
206
- // 发送结束chunk
227
+ // 计算 token 使用量
228
+ const promptTokens = calculateTokens ( lastUserMessage . content ) ;
229
+ totalTokens = promptTokens + completionTokens ;
230
+
231
+ // 发送最后一个chunk - 包含 finish_reason 和 usage
207
232
const endChunk : ChatCompletionStreamChunk = {
208
233
id,
209
234
object : 'chat.completion.chunk' ,
210
235
created : timestamp ,
211
236
model : request . model ,
237
+ system_fingerprint : systemFingerprint ,
212
238
choices : [ {
213
239
index : 0 ,
214
- delta : { } ,
240
+ delta : { content : '' } ,
241
+ logprobs : null ,
215
242
finish_reason : model . type === 'function' && testCase . functionCall ? 'function_call' : 'stop'
216
- } ]
243
+ } ] ,
244
+ usage : {
245
+ prompt_tokens : promptTokens ,
246
+ completion_tokens : completionTokens ,
247
+ total_tokens : totalTokens ,
248
+ prompt_tokens_details : {
249
+ cached_tokens : 0
250
+ } ,
251
+ prompt_cache_hit_tokens : 0 ,
252
+ prompt_cache_miss_tokens : promptTokens
253
+ }
217
254
} ;
218
255
219
- yield `data: ${ JSON . stringify ( endChunk ) } \\n\ \n` ;
220
- yield ' data: [DONE]\\n\\n' ;
256
+ yield `data: ${ JSON . stringify ( endChunk ) } \n \n` ;
257
+ yield ` data: [DONE]\n\n` ;
221
258
}
222
259
223
260
/**
0 commit comments