Files
zyt/server/tests/DiagnosisAiAssistantPreparationLifecycleTest.php
2026-10-23 10:17:09 +08:00

69 lines
4.1 KiB
PHP

<?php
declare(strict_types=1);
namespace app\adminapi\logic\firstvisit {
class MyPatientLogic {
public static bool $allowed = true;
public static function canAccessDiagnosis($id, $adminId, $adminInfo): bool {
$GLOBALS['lifecycle'][] = 'scope_checked';
return self::$allowed;
}
}
}
namespace app\adminapi\logic\tcm {
function config(string $key): array {
return ['timeout' => 5, 'models' => ['qwen' => ['name' => 'synthetic', 'label' => '合成模型']]];
}
class DiagnosisLogic {
public static function detail($params, $adminInfo): array {
$GLOBALS['lifecycle'][] = 'diagnosis_loaded';
return ['id' => $params['id'], 'patient_id' => 99, 'gender' => '女', 'age' => 42];
}
}
class PatientAiReportLogic {
public static function contextForAuthorizedDiagnosis($diagnosis, $adminId, $adminInfo): array {
$GLOBALS['lifecycle'][] = 'aggregate';
if (!empty($GLOBALS['cancelInAggregate'])) $GLOBALS['lifecycleCancelled'] = true;
return ['snapshot' => ['clinical_source' => '合成资料,无真实患者'],
'source_summary' => ['diagnosis_count' => 2, 'doctor_note_count' => 3, 'snapshot_complete' => true, 'may_be_truncated' => false],
'source_diagnosis_ids' => [11, 12], 'files' => []];
}
}
}
namespace {
require dirname(__DIR__) . '/vendor/autoload.php';
use app\adminapi\logic\tcm\DiagnosisAiLogic;
use app\adminapi\logic\firstvisit\MyPatientLogic;
function lifecycleExpect(bool $ok, string $message): void { if (!$ok) throw new RuntimeException($message); }
$lifecycle = []; $lifecycleCancelled = false; $cancelInAggregate = false;
$options = ['should_abort' => static fn (): bool => $GLOBALS['lifecycleCancelled'],
'on_authorized' => static function (array $metadata): bool {
$GLOBALS['lifecycle'][] = 'start';
lifecycleExpect($metadata === ['diagnosis_id' => 11, 'task' => 'summary', 'model_key' => 'qwen', 'required_sections' => []],
'early start exposes authorized identity and no unaggregated section claims');
return true;
},
'on_progress' => static function (array $event): void { $GLOBALS['lifecycle'][] = $event; }];
$prepared = DiagnosisAiLogic::prepareAssistant(11, 'summary', '', 7, ['root' => 1], null, $options);
lifecycleExpect(is_array($prepared), 'authorized synthetic preparation succeeds');
lifecycleExpect(array_slice($lifecycle, 0, 5) === ['scope_checked', 'diagnosis_loaded', 'start',
['phase' => 'preparing', 'status' => 'aggregating', 'message' => '正在聚合本次授权范围内的患者资料'], 'aggregate'], 'start and truthful preparation progress occur after scope but before aggregation');
lifecycleExpect($prepared['source_form'] === 'full_context' && $prepared['source_summary']['doctor_note_count'] === 3, 'real aggregate counts and full source form are preserved');
lifecycleExpect(end($lifecycle)['status'] === 'ready', 'ready occurs after successful aggregation');
$lifecycle = [];
MyPatientLogic::$allowed = false;
lifecycleExpect(DiagnosisAiLogic::prepareAssistant(11, 'summary', '', 7, ['root' => 1], null, $options) === null
&& $lifecycle === ['scope_checked'], 'denied DataScope produces no start/progress or aggregation');
lifecycleExpect(DiagnosisAiLogic::cancelAssistant(11, '12345678-1234-4234-8234-123456789abc', 7, ['root' => 1]) === null
&& DiagnosisAiLogic::getError() === '诊单不存在或无权访问', 'cancel has the same canonical DataScope restriction');
MyPatientLogic::$allowed = true;
$lifecycle = []; $cancelInAggregate = true;
lifecycleExpect(DiagnosisAiLogic::prepareAssistant(11, 'summary', '', 7, ['root' => 1], null, $options) === null
&& DiagnosisAiLogic::getAssistantErrorCode() === 'AI_ASSISTANT_CANCELLED', 'cancellation during aggregation blocks final prompt preparation');
lifecycleExpect(end($lifecycle) === 'aggregate', 'cancelled aggregation never claims prepared or submitted');
echo "Diagnosis AI assistant early start / DataScope / preparation lifecycle: OK\n";
}