feat: configure audio providers and add local sample acceptance

This commit is contained in:
2026-10-07 18:15:32 +08:00
parent 70be2fc70f
commit fea33285e8
21 changed files with 1103 additions and 131 deletions
+24 -5
View File
@@ -64,12 +64,31 @@ $makeTask = static function (string $path, string $extension) use ($directory):
'file_name' => 'synthetic.' . $extension, 'extension' => $extension, 'total_bytes' => filesize($target),
'received_bytes' => filesize($target), 'sha256' => $hash, 'duration_seconds' => $duration,
'status' => 'complete', 'created_at' => time(), 'expires_at' => time() + 86400]);
return ['id' => 1, 'upload_id' => $id, 'diagnosis_id' => 91, 'actor_id' => 7, 'model_key' => 'qwen',
return ['upstream_ids_json' => '{}', 'id' => 1, 'upload_id' => $id, 'diagnosis_id' => 91, 'actor_id' => 7, 'model_key' => 'qwen',
'recorded_at' => '2026-09-29 10:00:00', 'sha256' => $hash, 'duration_seconds' => $duration, 'path' => $target];
};
$adapter = static function (string $scenario, array $overrides = []) use ($port, $settings): Dify {
return new Dify(null, $overrides + $settings, ['base_url' => 'http://127.0.0.1:' . $port . '/' . $scenario . '/v1',
'models' => ['qwen' => ['api_key' => 'synthetic-test-key']]]);
$provider = ['base_url' => 'https://synthetic.invalid/' . $scenario . '/v1',
'models' => ['qwen' => ['api_key' => 'synthetic-test-key']]];
$effective = $overrides + $settings;
// Keep a stable task identity while varying transport scenarios; the test seam owns scenario routing.
$provider['base_url'] = 'https://synthetic.invalid/v1';
$effective['providers']['qwen']['verified_fingerprint'] = \app\common\service\followupaudio\FollowupAudioProviderConfig::resolve('qwen', $effective, $provider)['fingerprint'];
$adapter = null;
$transport = static function (array $spec, callable $heartbeat) use (&$adapter, $port, $scenario): array {
$spec['url'] = str_replace('https://synthetic.invalid', 'http://127.0.0.1:' . $port . '/' . $scenario, $spec['url']);
// Reflection is a test seam only; production cURL still verifies HTTPS certificates.
$curl = new ReflectionMethod(Dify::class, 'curl');
return $curl->invoke($adapter, $spec, $heartbeat);
};
$adapter = new Dify($transport, $effective, $provider);
return $adapter;
};
$taskFingerprint = \app\common\service\followupaudio\FollowupAudioProviderConfig::resolve('qwen', $settings,
['base_url' => 'https://synthetic.invalid/v1', 'models' => ['qwen' => ['api_key' => 'synthetic-test-key']]])['fingerprint'];
$bindTask = static function (array $task) use ($taskFingerprint): array {
$task['upstream_ids_json'] = json_encode(['provider_fingerprint' => $taskFingerprint]);
return $task;
};
$requests = static fn (): array => is_file($directory . '/requests.jsonl') ? array_map(static fn (string $line): array =>
json_decode($line, true), file($directory . '/requests.jsonl', FILE_IGNORE_NEW_LINES)) : [];
@@ -87,7 +106,7 @@ try {
file_put_contents($directory . '/source.amr', "#!AMR\n" . str_repeat("\x3c" . str_repeat("\0", 31), 150));
$tasks = [];
foreach (['wav', 'm4a', 'mp3', 'amr'] as $extension) {
$task = $makeTask($directory . '/source.' . $extension, $extension); $tasks[$extension] = $task;
$task = $bindTask($makeTask($directory . '/source.' . $extension, $extension)); $tasks[$extension] = $task;
$events = []; $copies = [];
$heartbeat = static function (array $fields = []) use (&$events, &$copies, $task): bool {
$events[] = $fields;
@@ -140,7 +159,7 @@ try {
$expect(count($requests()) === $before + 2 && glob(dirname($wave['path']) . '/processing.*') === [],
'unknown HTTP result is not resent and processing copy is erased');
$expect(hash_file('sha256', $wave['path']) === $wave['sha256'], 'unknown result leaves original intact');
$makeWav($directory . '/long.wav', 3600); $long = $makeTask($directory . '/long.wav', 'wav');
$makeWav($directory . '/long.wav', 3600); $long = $bindTask($makeTask($directory . '/long.wav', 'wav'));
$copyMetadata = [];
$adapter('media-long')->analyze($long, static function (array $fields = []) use ($long, &$copyMetadata): bool {
if (isset($fields['upstream_started_at'])) {