This commit is contained in:
Your Name
2026-10-23 10:40:43 +08:00
parent e974d3cfa5
commit a3d2d3170d
14 changed files with 1660 additions and 83 deletions
@@ -1058,7 +1058,8 @@ class DiagnosisController extends BaseAdminController
+ ($control !== null ? $control->publicState() : []));
}
$emit('error', ['code' => $cancelled ? 'AI_ASSISTANT_CANCELLED' : DiagnosisAiLogic::getAssistantErrorCode(),
'message' => $cancelled ? '本次请求已取消' : DiagnosisAiLogic::getError()]);
'message' => $cancelled ? '本次请求已取消' : DiagnosisAiLogic::getError()]
+ ($cancelled ? [] : DiagnosisAiLogic::getAssistantErrorMeta()));
}
/** @param array<string,mixed> $prepared */
@@ -14,6 +14,7 @@ use app\common\service\NihaixiaClinicalSkill;
use app\common\service\TcmAncientBooksReference;
use app\adminapi\service\AssistantSseTiming;
use app\adminapi\service\AiContextCompactionCache;
use app\adminapi\service\AiRequiredSource;
use app\adminapi\service\AssistantRequestControl;
use think\facade\Db;
use think\facade\Log;
@@ -26,6 +27,9 @@ class DiagnosisAiLogic extends BaseLogic
/** @var string Safe machine-readable code for the current assistant request. */
private static $assistantErrorCode = 'AI_ASSISTANT_FAILED';
/** @var array<string,mixed> Safe final receipt, never upstream text/URLs. */
private static $assistantErrorMeta = [];
private const PROMPT_VERSION = 'patient-context-case-explain-nihaixia-ancient-v4';
private const ASSISTANT_PROMPT_VERSION = 'patient-context-assistant-required-sources-v6';
@@ -379,6 +383,7 @@ class DiagnosisAiLogic extends BaseLogic
$status = 'error';
try {
self::$assistantErrorCode = 'AI_ASSISTANT_FAILED';
self::$assistantErrorMeta = [];
$task = strtolower(trim($task));
if (!isset(self::ASSISTANT_TASKS[$task])) {
self::setError('不支持的 AI 助手任务');
@@ -517,6 +522,7 @@ class DiagnosisAiLogic extends BaseLogic
?AssistantSseTiming $timing = null,
array $options = []
): ?array {
self::$assistantErrorMeta = [];
$diagnosisId = (int) ($prepared['diagnosis_id'] ?? 0);
$profile = (string) ($prepared['profile'] ?? '');
$adminId = (int) ($prepared['admin_id'] ?? 0);
@@ -693,7 +699,9 @@ class DiagnosisAiLogic extends BaseLogic
*/
private static function formatAssistantResult(array $prepared, array $result): ?array
{
self::$assistantErrorMeta = [];
if (empty($result['ok'])) {
self::$assistantErrorMeta = self::safeAssistantErrorMeta($result);
// 附带上游错误码,让医生反馈时管理员能直接定位是配置、体积还是上游拒绝。
$message = (string) ($result['error'] ?? 'AI 助手暂时不可用,请稍后重试');
$errorCode = trim((string) ($result['error_code'] ?? ''));
@@ -753,6 +761,52 @@ class DiagnosisAiLogic extends BaseLogic
return self::normaliseAssistantErrorCode(self::$assistantErrorCode);
}
public static function getAssistantErrorMeta(): array
{
return self::$assistantErrorMeta;
}
private static function safeAssistantErrorMeta(array $result): array
{
$meta = [];
$sections = $result['required_sections'] ?? $result['source_summary']['required_sections'] ?? null;
if (is_array($sections)) {
$meta['required_sections'] = [];
foreach ($sections as $section) {
$key = is_array($section) ? ($section['key'] ?? null) : null;
if (!is_string($key) || !isset(AiRequiredSource::LABELS[$key])) continue;
$status = $section['status'] ?? '';
if (!in_array($status, ['prepared', 'submitting', 'submitted', 'failed', 'omitted'], true)) continue;
$meta['required_sections'][] = ['key' => $key, 'label' => AiRequiredSource::LABELS[$key],
'count' => max(0, (int) ($section['count'] ?? 0)),
'availability' => ($section['availability'] ?? '') === 'empty' ? 'empty' : 'present', 'status' => $status];
}
$meta['source_summary'] = ['required_sections' => $meta['required_sections']];
}
if (is_array($result['items'] ?? null)) {
$meta['items'] = [];
$labels = ['image' => '图片附件', 'document' => '文档附件', 'audio' => '音频附件', 'custom' => '附件'];
$counts = [];
foreach ($result['items'] as $item) {
if (!is_array($item)) continue;
$kind = $item['kind'] ?? '';
$status = $item['status'] ?? '';
if (!is_string($kind) || !isset($labels[$kind])
|| !in_array($status, ['prepared', 'uploading', 'uploaded', 'submitting', 'submitted', 'failed', 'omitted'], true)) continue;
$counts[$kind] = ($counts[$kind] ?? 0) + 1;
$meta['items'][] = ['kind' => $kind, 'label' => $labels[$kind] . $counts[$kind], 'status' => $status];
}
}
if (is_int($result['attachment_count'] ?? null)) $meta['attachment_count'] = max(0, $result['attachment_count']);
if (in_array($result['attachment_transfer'] ?? '', ['remote_url_references', 'uploaded_files'], true)) {
$meta['attachment_transfer'] = $result['attachment_transfer'];
}
if (($result['transfer_manifest_final'] ?? false) === true) $meta['transfer_manifest_final'] = true;
if (is_int($result['upstream_http_status'] ?? null) && $result['upstream_http_status'] >= 100
&& $result['upstream_http_status'] <= 599) $meta['upstream_http_status'] = $result['upstream_http_status'];
return $meta;
}
private static function normaliseAssistantErrorCode(string $code): string
{
$code = strtoupper(trim($code));