98 lines
6.5 KiB
PHP
98 lines
6.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace think\facade {
|
|
class Cache {
|
|
public static array $entries = [];
|
|
public static function get(string $key) { return self::$entries[$key] ?? null; }
|
|
public static function set(string $key, $value, int $ttl): void { self::$entries[$key] = $value; }
|
|
}
|
|
class Log { public static function warning(string $message, array $context = []): void {} }
|
|
}
|
|
|
|
namespace app\adminapi\service {
|
|
function config(string $key): array { return ['context_compaction_cache_ttl' => 300]; }
|
|
}
|
|
|
|
namespace app\adminapi\logic\firstvisit {
|
|
class MyPatientLogic {
|
|
public static function canAccessDiagnosis($id, $adminId, $adminInfo): bool { ++$GLOBALS['requiredScopeChecks']; return true; }
|
|
}
|
|
}
|
|
|
|
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 { return ['id' => $params['id'], 'patient_id' => 99, 'gender' => '女', 'age' => 42]; }
|
|
}
|
|
class PatientAiReportLogic {
|
|
public static function contextForAuthorizedDiagnosis($diagnosis, $adminId, $adminInfo): array {
|
|
++$GLOBALS['requiredAggregates'];
|
|
return ['snapshot' => ['required_sections' => $GLOBALS['requiredRawSections'],
|
|
'synthetic_history' => str_repeat('合成无真实患者资料。', 9000) . $GLOBALS['requiredRevision']],
|
|
'source_summary' => ['required_sections' => $GLOBALS['requiredMetadata'], 'snapshot_complete' => true],
|
|
'source_diagnosis_ids' => [11, 12], 'files' => array_fill(0, 8,
|
|
['type' => 'document', 'url' => 'https://synthetic.invalid/required.pdf'])];
|
|
}
|
|
public static function compactSourceForPrompt(string $profile, string $source, array $options): array {
|
|
++$GLOBALS['requiredCompactions'];
|
|
foreach ($GLOBALS['requiredMetadata'] as $section) {
|
|
\contextRequiredExpect(str_contains($source, $section['label']), 'every required section enters the complete evidence extraction source');
|
|
}
|
|
if ($GLOBALS['requiredCancelInCompaction']) $GLOBALS['requiredContextCancelled'] = true;
|
|
return ['text' => '逐片合成证据摘要。', 'chunk_count' => 4, 'reduction_rounds' => 1,
|
|
'source_bytes' => strlen($source), 'compacted' => true];
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
require dirname(__DIR__) . '/vendor/autoload.php';
|
|
use app\adminapi\logic\tcm\DiagnosisAiLogic;
|
|
use think\facade\Cache;
|
|
function contextRequiredExpect(bool $ok, string $message): void { if (!$ok) throw new RuntimeException($message); }
|
|
$requiredMetadata = []; $requiredRawSections = [];
|
|
foreach (['basic_info' => '基本信息', 'vital_signs' => '生命体征', 'chief_complaint' => '主诉', 'present_illness' => '现病史',
|
|
'past_history' => '既往史', 'other_history' => '其他病史', 'diagnosis_info' => '诊断信息', 'doctor_image_notes' => '医生备注图片',
|
|
'doctor_file_notes' => '医生备注文件', 'daily_tracking' => '日常整个页', 'prescriptions' => '历史处方',
|
|
'video_consultation_text' => '既往视频面诊转文字', 'chat' => '聊天'] as $key => $label) {
|
|
$empty = in_array($key, ['other_history', 'chat'], true);
|
|
$requiredMetadata[] = ['key' => $key, 'label' => $label, 'count' => $empty ? 0 : 1,
|
|
'availability' => $empty ? 'empty' : 'present', 'status' => 'prepared'];
|
|
$requiredRawSections[$key] = ['label' => $label, 'content' => $empty ? '无' : '合成记录'];
|
|
}
|
|
$requiredScopeChecks = 0; $requiredAggregates = 0; $requiredCompactions = 0; $requiredRevision = 'revision-1';
|
|
$requiredContextCancelled = false; $requiredCancelInCompaction = false;
|
|
$prepare = static function (): array|null {
|
|
$events = []; $started = null;
|
|
$result = DiagnosisAiLogic::prepareAssistant(11, 'summary', '', 7, ['root' => 1], null,
|
|
['should_abort' => static fn (): bool => $GLOBALS['requiredContextCancelled'],
|
|
'on_authorized' => static function (array $metadata) use (&$started): bool { $started = $metadata; return true; },
|
|
'on_progress' => static function (array $event) use (&$events): void { $events[] = $event; }]);
|
|
if ($result !== null) {
|
|
contextRequiredExpect($started['required_sections'] === [], 'start makes no section availability claims before aggregation');
|
|
contextRequiredExpect(count($events[1]['required_sections']) === 13 && count(end($events)['required_sections']) === 13,
|
|
'aggregation and prepared progress carry every mandatory section');
|
|
}
|
|
return $result;
|
|
};
|
|
$prepared = $prepare();
|
|
contextRequiredExpect(is_array($prepared) && $prepared['source_form'] === 'evidence_summary' && !$prepared['evidence_cache_hit'], 'large source is fully covered by evidence extraction');
|
|
foreach ($requiredMetadata as $section) {
|
|
contextRequiredExpect(str_contains($prepared['query'], $section['label']) && str_contains($prepared['inputs']['herbs_json'], $section['label']),
|
|
'required column survives compaction in both model input channels');
|
|
}
|
|
contextRequiredExpect(str_contains($prepared['query'], '其他病史:无') && str_contains($prepared['query'], '聊天:无'), 'empty required sections remain explicit no-data body entries');
|
|
contextRequiredExpect(count($prepared['required_sections']) === 13 && $prepared['required_sections'][0]['status'] === 'prepared', 'preparation never reports submission');
|
|
$cached = $prepare();
|
|
contextRequiredExpect($cached['evidence_cache_hit'] && $requiredCompactions === 1 && $requiredScopeChecks === 2 && $requiredAggregates === 2,
|
|
'cache reuse follows fresh scope authorization and complete live aggregation');
|
|
contextRequiredExpect($cached['required_sections'] === $prepared['required_sections'] && str_contains($cached['query'], '聊天:无')
|
|
&& count($cached['files']) === 8 && count($prepared['files']) === 8, 'cache cannot remove required source manifest or attachments');
|
|
$requiredRevision = 'revision-2'; $requiredCancelInCompaction = true;
|
|
contextRequiredExpect($prepare() === null && DiagnosisAiLogic::getAssistantErrorCode() === 'AI_ASSISTANT_CANCELLED'
|
|
&& count(Cache::$entries) === 1, 'cancelled evidence extraction is not cached or promoted to ready');
|
|
echo "Diagnosis AI required source prepare / compaction / cache / explicit empty context: OK\n";
|
|
}
|