initialize(); use app\common\model\doctor\Medicine; use app\common\service\prescriptionai\PrescriptionAiCipher; use app\common\service\prescriptionai\PrescriptionAiGenerator; use think\facade\Db; $batchId = (int) ($argv[1] ?? 7); $model = (string) ($argv[2] ?? 'qwen'); $cipher = new PrescriptionAiCipher(); $batch = Db::name('prescription_ai_batch')->where('id', $batchId)->find(); if (!$batch || (string) $batch['context_cipher'] === '') { throw new RuntimeException('batch context is not prepared'); } $context = $cipher->decrypt((string) $batch['context_cipher'], 'context'); $context['_comparison_catalog'] = Medicine::where('status', 1)->whereNull('delete_time') ->field(['id', 'name', 'unit'])->order('id')->select()->toArray(); $progress = []; $started = microtime(true); $result = PrescriptionAiGenerator::generate($model, $context, static function (array $state) use (&$progress): bool { $progress = $state; return true; }); echo json_encode([ 'batch' => $batchId, 'model' => $model, 'ok' => (bool) ($result['ok'] ?? false), 'error_code' => $result['error_code'] ?? '', 'candidate_status' => $result['candidate']['status'] ?? null, 'candidate_herb_count' => is_array($result['candidate']['herbs'] ?? null) ? count($result['candidate']['herbs']) : null, 'coverage_status' => $result['coverage']['status'] ?? null, 'source_ids' => count((array) ($result['coverage']['source_ids'] ?? [])), 'files' => count((array) ($result['coverage']['files'] ?? [])), 'missing' => count((array) ($result['coverage']['missing'] ?? [])), 'wall_seconds' => round(microtime(true) - $started, 1), 'format_rejects' => $progress['format_rejects'] ?? [], 'calls' => array_map(static fn (array $call): array => [ 'stage' => $call['stage'], 'ok' => $call['ok'], 'latency_ms' => $call['latency_ms'], 'input_bytes' => $call['input_token_upper_bound'], 'files' => $call['file_count'], 'error_code' => $call['error_code'], 'completion_tokens' => $call['usage']['completion_tokens'] ?? null, ], (array) ($progress['usage']['calls'] ?? [])), ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";