69 lines
4.1 KiB
PHP
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";
|
|
}
|