59 lines
3.8 KiB
PHP
59 lines
3.8 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require dirname(__DIR__) . '/app/adminapi/service/TcmClinicalEvidenceIndex.php';
|
|
use app\adminapi\service\TcmClinicalEvidenceIndex as Index;
|
|
|
|
$count = 0;
|
|
$expect = static function (bool $ok, string $message) use (&$count): void {
|
|
++$count;
|
|
if (!$ok) throw new RuntimeException($message);
|
|
};
|
|
$source = static fn (string $id, string $scope, string $path, string $quote): array => [
|
|
'id' => $id, 'scope' => $scope, 'path' => $path, 'date' => '2026-04-02',
|
|
'field' => 'allergy_history', 'quote' => $quote,
|
|
];
|
|
$sources = [
|
|
's1' => $source('s1', 'current', 'current.allergy_history', '本次询问无已知药物过敏史'),
|
|
's2' => $source('s2', 'historical', 'history.0.allergy_history', '当时询问无已知药物过敏史'),
|
|
's3' => $source('s3', 'current', 'chat.0.text', '自述无已知药物过敏史'),
|
|
's4' => $source('s4', 'current', 'current.family_history', '未记录'),
|
|
's5' => $source('s5', 'current', 'current.present_illness', '自述乏力'),
|
|
];
|
|
$assertions = [];
|
|
foreach (['s1', 's2', 's3'] as $id) {
|
|
$assertions[] = ['source_id' => $id, 'state' => 'negative', 'quote' => '无已知药物过敏史',
|
|
'scope' => $sources[$id]['scope'], 'date' => '2026-04-02'];
|
|
}
|
|
$assertions[] = ['source_id' => 's4', 'state' => 'unknown', 'quote' => '未记录'];
|
|
$assertions[] = ['source_id' => 's5', 'state' => 'positive', 'quote' => '自述乏力'];
|
|
$ledger = ['sources' => $sources, 'assertions' => $assertions];
|
|
$index = Index::build($ledger);
|
|
$before = $index;
|
|
$prompt = Index::prompt($index);
|
|
$expect($index === $before, 'Input formatting cannot mutate the source index.');
|
|
$expect(preg_match('~<CURRENT_SIX_EXAM_SELECTION_MAP>\n(.*?)\n</CURRENT_SIX_EXAM_SELECTION_MAP>~s', $prompt, $match) === 1, 'Selection map exists.');
|
|
$map = json_decode($match[1], true, 512, JSON_THROW_ON_ERROR);
|
|
$expect(count($map['roles']) === 6, 'Six original role entries remain.');
|
|
$expect($map['current_source_reference_texts'] === [[
|
|
'source_id' => 's1', 'date' => '2026-04-02', 'reference_text' => '相关原文见s1',
|
|
]], 'Only an actual typed current denial receives a neutral reference; history, remote, unknown and positive are distinct.');
|
|
$expect(!isset($map['current_source_reference_texts'][0]['quote']), 'The aid does not rewrite a denial or create a shortened patient assertion.');
|
|
preg_match('~<SOURCE_EXAM_ROLE_INDEX>\n(.*?)\n</SOURCE_EXAM_ROLE_INDEX>~s', $prompt, $raw);
|
|
$rows = json_decode($raw[1], true, 512, JSON_THROW_ON_ERROR);
|
|
$expect(count($rows) === count($sources), 'All raw sources remain, including history and remote records.');
|
|
foreach ($rows as $row) {
|
|
$expect($row['date'] === $sources[$row['id']]['date'], 'Original date remains.');
|
|
$expect($row['scope'] === $sources[$row['id']]['scope'], 'Original time scope remains.');
|
|
$expect($row['spans'][0]['quote'] === $sources[$row['id']]['quote'], 'Exact original quote and qualifiers remain.');
|
|
}
|
|
$expect($index['sources']['s4']['negative_assertions'] === [], 'Unknown is not a recorded denial.');
|
|
$expect(str_contains($prompt, '不能删掉程度、已知或时间限定'), 'Qualifier retention is explicit during later reasoning.');
|
|
$expect(str_contains($prompt, '不能用来源核对代替完整分析'), 'A reference is not a substitute for a reasoned full report.');
|
|
$invalid = $index;
|
|
$invalid['valid'] = false;
|
|
preg_match('~<CURRENT_SIX_EXAM_SELECTION_MAP>\n(.*?)\n</CURRENT_SIX_EXAM_SELECTION_MAP>~s', Index::prompt($invalid), $bad);
|
|
$badMap = json_decode($bad[1], true, 512, JSON_THROW_ON_ERROR);
|
|
$expect($badMap['available'] === false && !isset($badMap['current_source_reference_texts']), 'Unavailable input cannot manufacture denial references.');
|
|
echo 'TCM recorded-denial input references: ' . $count . " assertions passed (pure input; no model-quality claim).\n";
|