/**
* @param $connection
* @param $options
* @param \Closure $dataHandler
* @return \support\Response
*/
private function handleStreamResponse($connection, $options, \Closure $dataHandler) {
try {
$messageId = uniqid('chatcmpl-');
$startTime = time();
$id = Timer::add(0.1, function () use ($connection, &$id, $messageId, $startTime, $options, $dataHandler) {
if ($connection->getStatus() !== TcpConnection::STATUS_ESTABLISHED) {
Timer::del($id);
return;
}
$dataHandler($connection, $messageId, $startTime, $options);
$endData = json_encode([
'id' => uniqid('chatcmpl-'),
'object' => 'chat.completion.chunk',
'created' => time(),
'model' => $options['model'],
'choices' => [[
'delta' => [],
'index' => 0,
'finish_reason' => 'stop'
]]
], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
$connection->send(new Chunk("data: {$endData}\n\n"));
$connection->send(new Chunk(""));
Timer::del($id);
});
} catch (\Throwable $e) {
$errorData = json_encode([
'error' => [
'message' => $e->getMessage(),
'type' => 'error',
'code' => $e->getCode()
]
]);
$connection->send(new Chunk("data: {$errorData}\n"));
}
return response()->withHeaders([
"Content-Type" => "application/json",
"Transfer-Encoding" => "chunked",
]);
}
使用方法(閉包函數(shù)是我這邊的業(yè)務(wù),實際自己看情況寫):
if ($stream) {
return $this->handleStreamResponse($connection, $options, function($connection, $messageId, $startTime, $options) use($service, $messages) {
foreach ($service->chatStream($messages, $options) as $chunk) {
if (!empty($chunk)) {
$data = json_encode([
'id' => $messageId,
'object' => 'chat.completion.chunk',
'created' => $startTime,
'model' => $options['model'],
'choices' => [[
'delta' => [
'role' => 'assistant',
'content' => $chunk
],
'index' => 0,
'finish_reason' => null
]]
], JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
echo "data: {$data}\n\n";
$connection->send(new Chunk("data: {$data}\n\n"));
}
}
});
}
在控制器中使用流式輸出。
嘗試了很多方法,在控制器中如果不使用Timer的話,無法正常即時輸出。
分享出來我的方法,有更好的方法也希望兄弟們讓我學(xué)習(xí)學(xué)習(xí)
為啥不用這種