50 lines
1.3 KiB
PHP
50 lines
1.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace app\adminapi\service;
|
|
|
|
/**
|
|
* 诊单 AI 助手 SSE 事件状态机:start -> delta* -> done|error。
|
|
*/
|
|
final class AssistantSseProtocol
|
|
{
|
|
private int $seq = 0;
|
|
|
|
private bool $started = false;
|
|
|
|
private bool $terminal = false;
|
|
|
|
/** @param array<string,mixed> $payload */
|
|
public function encode(string $event, array $payload): ?string
|
|
{
|
|
if ($this->terminal || !in_array($event, ['start', 'delta', 'done', 'error'], true)) {
|
|
return null;
|
|
}
|
|
if ((!$this->started && $event !== 'start') || ($this->started && $event === 'start')) {
|
|
return null;
|
|
}
|
|
|
|
$nextSeq = $this->seq + 1;
|
|
$encoded = json_encode(
|
|
['seq' => $nextSeq] + $payload,
|
|
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE
|
|
);
|
|
if (!is_string($encoded)) {
|
|
return null;
|
|
}
|
|
|
|
$this->seq = $nextSeq;
|
|
$this->started = true;
|
|
if (in_array($event, ['done', 'error'], true)) {
|
|
$this->terminal = true;
|
|
}
|
|
return 'event: ' . $event . "\n" . 'data: ' . $encoded . "\n\n";
|
|
}
|
|
|
|
public function isTerminal(): bool
|
|
{
|
|
return $this->terminal;
|
|
}
|
|
}
|