Files
zyt/server/app/adminapi/logic/tcm/TongueScreenshotLogic.php
2026-11-03 17:20:35 +08:00

62 lines
3.1 KiB
PHP

<?php
declare(strict_types=1);
namespace app\adminapi\logic\tcm;
use app\adminapi\logic\firstvisit\MyPatientLogic;
use app\common\cache\AdminAuthCache;
use app\common\logic\BaseLogic;
use app\common\service\DifyTongueScreenshotService;
use app\common\service\TongueScreenshotImage;
/** Read-only assistant operation: authorization + this upload, never a chart snapshot or persistence. */
final class TongueScreenshotLogic extends BaseLogic
{
public static function analyze(array $params, $file, int $adminId, array $adminInfo): ?array
{
$image = null;
try {
if (array_diff(array_keys($params), ['id', 'request_id', 'model']) !== []) {
throw new \DomainException('截图分析请求包含不支持的字段');
}
$model = array_key_exists('model', $params) ? $params['model'] : 'qwen';
if (!is_string($model) || !in_array($model, ['qwen', 'openai'], true)) {
throw new \DomainException('截图分析模型无效');
}
$rawId = $params['id'] ?? null;
$id = (is_string($rawId) || is_int($rawId))
? filter_var($rawId, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]) : false;
if ($id === false) throw new \DomainException('诊单ID必须大于0');
$requestId = $params['request_id'] ?? null;
if (!is_string($requestId) || !preg_match('/\A[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\z/Di', $requestId)) {
throw new \DomainException('截图请求标识无效');
}
if ($adminId < 1) throw new \DomainException('请先登录');
if ((int) ($adminInfo['root'] ?? 0) !== 1) {
$uris = (new AdminAuthCache($adminId))->getAdminUri() ?? [];
$uris = array_map(static fn ($uri): string => strtolower(trim((string) $uri)), is_array($uris) ? $uris : []);
if (!in_array('tcm.diagnosis/aiassistant', $uris, true)) {
throw new \DomainException('权限不足,无法使用诊单 AI 助手');
}
}
if (!MyPatientLogic::canAccessDiagnosis($id, $adminId, $adminInfo)) {
throw new \DomainException('诊单不存在或无权访问');
}
$image = TongueScreenshotImage::fromUpload($file);
$result = DifyTongueScreenshotService::analyze($image, $model);
return ['request_id' => $requestId, 'diagnosis_id' => $id, 'image_sha256' => $image->sha256(),
'analysis' => $result['analysis'], 'model' => $result['model'], 'model_label' => $result['model_label']];
} catch (\DomainException $error) {
self::setError($error->getMessage());
return null;
} catch (\Throwable $error) {
// Never log image bytes, patient data, model text, transport details or exception messages.
self::setError('截图分析暂不可用,请稍后重试');
return null;
} finally {
if ($image !== null) $image->release();
}
}
}