55 lines
2.5 KiB
PHP
55 lines
2.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace app\common\service\followupaudio;
|
|
|
|
use app\common\service\prescriptionai\PrescriptionAiAccess;
|
|
|
|
final class FollowupAudioWorker
|
|
{
|
|
private FollowupAudioDify $dify;
|
|
|
|
public function __construct(?FollowupAudioDify $dify = null)
|
|
{
|
|
$this->dify = $dify ?? new FollowupAudioDify();
|
|
}
|
|
|
|
public function runOnce(): bool
|
|
{
|
|
if (!FollowupAudioStore::enabled() || !($task = FollowupAudioStore::claim())) {
|
|
return false;
|
|
}
|
|
$id = (int) $task['id'];
|
|
$token = (string) $task['lease_token'];
|
|
$started = (int) ($task['upstream_started_at'] ?? 0) > 0;
|
|
try {
|
|
FollowupAudioStore::assertTaskProvider($task);
|
|
if (!FollowupAudioStore::ready((string) $task['model_key'])) { throw new FollowupAudioException('AUDIO_NOT_VERIFIED'); }
|
|
$heartbeat = function (array $fields = []) use ($task, $id, $token, &$started): bool {
|
|
FollowupAudioStore::assertTaskProvider($task);
|
|
if (!FollowupAudioStore::enabled() || !FollowupAudioStore::ready((string) $task['model_key'])) { return false; }
|
|
$actor = PrescriptionAiAccess::actor((int) $task['actor_id']);
|
|
if (!$actor) { return false; }
|
|
FollowupAudioAccess::task($id, (int) $task['actor_id'], $actor);
|
|
if (!FollowupAudioStore::heartbeat($id, $token)) { return false; }
|
|
if ($fields !== [] && !FollowupAudioStore::checkpoint($id, $token, $fields)) { return false; }
|
|
if (!empty($fields['upstream_started_at'])) { $started = true; }
|
|
return true;
|
|
};
|
|
if (!$heartbeat()) { throw new FollowupAudioException('ACCESS_REVOKED', $started); }
|
|
$extraction = $this->dify->analyze($task, $heartbeat);
|
|
if (!$heartbeat()) { throw new FollowupAudioException('LEASE_LOST', true); }
|
|
if (!FollowupAudioStore::complete($id, $token, $extraction)) {
|
|
throw new FollowupAudioException('LEASE_LOST', true);
|
|
}
|
|
} catch (FollowupAudioException $e) {
|
|
FollowupAudioStore::fail($id, $token, $e->errorCode, $e->getMessage(), $e->uncertain || $started);
|
|
} catch (\Throwable $e) {
|
|
// The exception may contain SQL, names, transcript, credentials or a signed URL.
|
|
FollowupAudioStore::fail($id, $token, 'INTERNAL_ERROR', '音频任务执行异常,请核对任务状态', $started);
|
|
}
|
|
return true;
|
|
}
|
|
}
|