feat(followup-audio): confirm role corrections and reextract cached transcripts

This commit is contained in:
2026-10-12 12:24:34 +08:00
parent 2dfec801e7
commit 9e3aa9fc61
15 changed files with 660 additions and 16 deletions
@@ -160,6 +160,8 @@ final class FollowupAudioStore
$result['error_code'] = 'FOLLOWUP_AUDIO_EXPIRED';
$result['error_message'] = '录音及审阅已到保留期限,不能采用';
}
$result['extraction_revision'] = (int) ($task['extraction_revision'] ?? 0);
$result['extraction_channel_roles'] = FollowupAudioReextract::roles($task);
$result['preview_only'] = FollowupAudioGate::previewOnly() || FollowupAudioGate::taskPreview($task);
$result['can_retry'] = self::enabled() && self::ready((string) $task['model_key'])
&& FollowupAudioGate::scopeAllowed((int) $task['diagnosis_id'], (int) $task['actor_id']) && $alive && $task['status'] === 'failed'
@@ -200,6 +202,8 @@ final class FollowupAudioStore
$data['applied_items'] = $applied['items'];
if (isset($applied['channel_roles']) && in_array($applied['channel_roles'], self::CHANNEL_ROLES, true)) { $data['channel_roles'] = $applied['channel_roles']; }
}
if ($data['channel_roles'] === 'unconfirmed' && $task['extraction_cipher'] === '' && (int) ($task['extraction_revision'] ?? 0) > 0) { $data['channel_roles'] = FollowupAudioReextract::roles($task); }
$data['role_check'] = FollowupAudioReextract::roleCheck($data['transcript_segments'], FollowupAudioReextract::roles($task));
return $data;
}
@@ -449,10 +453,15 @@ final class FollowupAudioStore
$items = FollowupAudioApply::refresh($task, $normalized['items'], $diagnosis, true);
$review = ['items' => $items];
if (self::hasStereo($normalized)) {
$review['channel_roles'] = self::taskChannelRoles($task);
$review['channel_roles'] = FollowupAudioReextract::roles($task);
if ($review['channel_roles'] !== 'unconfirmed') {
$review['channel_roles_annotation'] = ['value' => $review['channel_roles'], 'actor_id' => (int) $task['actor_id'],
'updated_at' => (int) $task['created_at'], 'review_version' => (int) $task['version'] + 1, 'source' => 'task_create'];
if ($binding = FollowupAudioReextract::binding($task)) {
$review['channel_roles_annotation'] = ['value' => $review['channel_roles'], 'actor_id' => $binding['actor_id'],
'updated_at' => $binding['confirmed_at'], 'review_version' => (int) $task['version'] + 1,
'source' => 'reextract', 'extraction_revision' => $binding['revision']];
}
}
}
Db::name('followup_audio_task')->where('id', $id)->update([
@@ -501,6 +510,9 @@ final class FollowupAudioStore
$task = self::lockTask((int) $id);
if ((int) $task['lease_until'] > time()) { $counts['active_skipped']++; return null; }
if (!(int) $task['purged_at']) {
if ((int) ($task['extraction_revision'] ?? 0) > 0) {
Db::name('followup_audio_extraction_history')->where('task_id', $id)->update(['snapshot_cipher' => null, 'purged_at' => time()]);
}
Db::name('followup_audio_task')->where('id', $id)->update([
'extraction_cipher' => '', 'review_cipher' => '', 'pipeline_cipher' => null, 'file_name' => '已清理录音', 'purged_at' => time(),
'status' => in_array($task['status'], ['applied', 'deleted'], true) ? $task['status'] : 'expired',