43 lines
3.5 KiB
PHP
43 lines
3.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
require dirname(__DIR__) . '/vendor/autoload.php';
|
|
use app\common\service\followupaudio\FollowupAudioTranscriptPrompt as Prompt;
|
|
use app\common\service\followupaudio\FollowupAudioPipeline as Pipeline;
|
|
use app\common\service\followupaudio\FollowupAudioStore as Store;
|
|
// Supports real baseline/rollback source execution without changing the worktree.
|
|
if (($root = getenv('FOLLOWUP_AUDIO_DIALOGUE_SOURCE_ROOT')) !== false && $root !== '') {
|
|
foreach (['FollowupAudioStore', 'FollowupAudioTranscriptPrompt', 'FollowupAudioPipeline'] as $name) {
|
|
require $root . '/server/app/common/service/followupaudio/' . $name . '.php';
|
|
}
|
|
}
|
|
$checks = []; $check = static function (string $label, bool $ok) use (&$checks): void { $checks[$label] = $ok; };
|
|
$segments = [
|
|
['id' => 'left', 'start_ms' => 0, 'end_ms' => 20000, 'channel' => 0, 'text' => '今天早晨血糖多少?有没有头晕?'],
|
|
['id' => 'right', 'start_ms' => 0, 'end_ms' => 20000, 'channel' => 1, 'text' => '空腹六点一,没有头晕。'],
|
|
];
|
|
$transcript = implode("\n", array_column($segments, 'text'));
|
|
$catalog = ['blood' => [['key' => 'fasting_blood_sugar', 'type' => 'number']]];
|
|
$context = static function (string $prompt): array { return json_decode(explode("\nSOURCE_CITATIONS=", explode("\nSERVER_CONTEXT=", $prompt, 2)[1], 2)[0], true, 512, JSON_THROW_ON_ERROR); };
|
|
foreach (['left_service' => ['0' => 'service', '1' => 'patient'], 'right_service' => ['0' => 'patient', '1' => 'service'], 'unconfirmed' => []] as $roles => $map) {
|
|
$prompt = Prompt::build($transcript, $segments, '2026-09-29 10:00:00', $catalog, $roles); $ctx = $context($prompt);
|
|
$check($roles . ':binding', ($ctx['channel_roles'] ?? null) === $roles);
|
|
$check($roles . ':map', ($ctx['channel_role_map'] ?? null) === $map);
|
|
foreach (['完整问答上下文', '不能只读患者声道', '问题本身不是患者事实', '必须同时包含问题和回答', '同窗交叠', '不是逐字时间戳', '全部 SOURCE_CITATIONS', '已提供的角色约定', '家属'] as $rule) {
|
|
$check($roles . ':' . $rule, str_contains($prompt, $rule));
|
|
}
|
|
foreach (['openai', 'dify_chat'] as $protocol) {
|
|
$provider = ['fingerprint' => str_repeat('a', 64), 'extraction' => ['protocol' => $protocol, 'model' => 'synthetic', 'response_format' => 'prompt_json', 'binding_revision' => 'synthetic-v1']];
|
|
$payload = (new Pipeline([], $provider))->extractRequest($transcript, $segments, '2026-09-29 10:00:00', $catalog, null, $roles);
|
|
$check($roles . ':' . $protocol, ($payload['query'] ?? $payload['messages'][0]['content']) === $prompt);
|
|
}
|
|
}
|
|
$mono = [['id' => 'mono', 'start_ms' => 0, 'end_ms' => 20000, 'text' => $transcript]];
|
|
$check('mono_requested_confirmed_is_unconfirmed', ($context(Prompt::build($transcript, $mono, '2026-09-29 10:00:00', $catalog, 'left_service'))['channel_roles'] ?? null) === 'unconfirmed');
|
|
$legacy = $context(Prompt::build($transcript, $segments, '2026-09-29 10:00:00', $catalog));
|
|
$check('legacy_default_unconfirmed', ($legacy['channel_roles'] ?? null) === 'unconfirmed');
|
|
$check('canonical_citations_unchanged', Prompt::citations($segments)[0]['text'] === $segments[0]['text'] && Prompt::citations($segments)[1]['text'] === $segments[1]['text']);
|
|
$failed = array_keys(array_filter($checks, static fn (bool $ok): bool => !$ok));
|
|
echo 'FOLLOWUP_AUDIO_DIALOGUE_PROMPT passed=' . (count($checks) - count($failed)) . '/' . count($checks) . ' failures=' . json_encode($failed, JSON_UNESCAPED_UNICODE) . PHP_EOL;
|
|
exit($failed === [] ? 0 : 1);
|