feat(medications): 增加基于视觉AI的药品智能录入系统
构建了从照片到药品档案的自动化处理流程,通过GLM多模态大模型实现药品信息的智能采集: 核心能力: - 创建任务追踪表 t_medication_recognition_tasks 存储识别任务状态 - 四阶段渐进式分析:基础识别→人群适配→成分解析→风险评估 - 提供三个REST端点支持任务创建、进度查询和结果确认 - 前端可通过轮询方式获取0-100%的实时进度反馈 - VIP用户免费使用,普通用户按次扣费 技术实现: - 利用GLM-4V-Plus模型处理多角度药品图像(正面+侧面+说明书) - 采用GLM-4-Flash模型进行文本深度分析 - 异步任务执行机制避免接口阻塞 - 完整的异常处理和任务失败恢复策略 - 新增AI_RECOGNITION.md文档详细说明集成方式 同步修复: - 修正会员用户AI配额扣减逻辑,避免不必要的次数消耗 - 优化APNs推送中无效设备令牌的检测和清理流程 - 将服药提醒的提前通知时间从15分钟缩短为5分钟
This commit is contained in:
32
src/medications/dto/create-recognition-task.dto.ts
Normal file
32
src/medications/dto/create-recognition-task.dto.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { IsString, IsNotEmpty, IsOptional } from 'class-validator';
|
||||
|
||||
/**
|
||||
* 创建药物识别任务 DTO
|
||||
*/
|
||||
export class CreateRecognitionTaskDto {
|
||||
@ApiProperty({
|
||||
description: '正面图片URL(必需)',
|
||||
example: 'https://cdn.example.com/medications/front_001.jpg',
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
frontImageUrl: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '侧面图片URL(必需)',
|
||||
example: 'https://cdn.example.com/medications/side_001.jpg',
|
||||
})
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
sideImageUrl: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '辅助面图片URL(可选,如说明书)',
|
||||
example: 'https://cdn.example.com/medications/auxiliary_001.jpg',
|
||||
required: false,
|
||||
})
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
auxiliaryImageUrl?: string;
|
||||
}
|
||||
94
src/medications/dto/recognition-result.dto.ts
Normal file
94
src/medications/dto/recognition-result.dto.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { MedicationFormEnum } from '../enums/medication-form.enum';
|
||||
|
||||
/**
|
||||
* 药物识别结果 DTO
|
||||
* 包含创建药物所需的所有字段 + AI分析结果
|
||||
*/
|
||||
export class RecognitionResultDto {
|
||||
@ApiProperty({ description: '药品名称', example: '阿莫西林胶囊' })
|
||||
name: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '药品照片URL(使用正面图片)',
|
||||
example: 'https://cdn.example.com/medications/front_001.jpg',
|
||||
})
|
||||
photoUrl: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '药物剂型',
|
||||
enum: MedicationFormEnum,
|
||||
example: MedicationFormEnum.CAPSULE,
|
||||
})
|
||||
form: MedicationFormEnum;
|
||||
|
||||
@ApiProperty({ description: '剂量数值', example: 1 })
|
||||
dosageValue: number;
|
||||
|
||||
@ApiProperty({ description: '剂量单位', example: '粒' })
|
||||
dosageUnit: string;
|
||||
|
||||
@ApiProperty({ description: '建议每日服用次数', example: 3 })
|
||||
timesPerDay: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: '建议服药时间',
|
||||
example: ['08:00', '14:00', '20:00'],
|
||||
type: [String],
|
||||
})
|
||||
medicationTimes: string[];
|
||||
|
||||
@ApiProperty({
|
||||
description: '适合人群',
|
||||
example: ['成年人', '细菌感染患者'],
|
||||
type: [String],
|
||||
})
|
||||
suitableFor: string[];
|
||||
|
||||
@ApiProperty({
|
||||
description: '不适合人群',
|
||||
example: ['青霉素过敏者', '孕妇', '哺乳期妇女'],
|
||||
type: [String],
|
||||
})
|
||||
unsuitableFor: string[];
|
||||
|
||||
@ApiProperty({
|
||||
description: '主要成分',
|
||||
example: ['阿莫西林'],
|
||||
type: [String],
|
||||
})
|
||||
mainIngredients: string[];
|
||||
|
||||
@ApiProperty({
|
||||
description: '主要用途',
|
||||
example: '用于敏感菌引起的各种感染',
|
||||
})
|
||||
mainUsage: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '可能的副作用',
|
||||
example: ['恶心', '呕吐', '腹泻', '皮疹'],
|
||||
type: [String],
|
||||
})
|
||||
sideEffects: string[];
|
||||
|
||||
@ApiProperty({
|
||||
description: '储存建议',
|
||||
example: ['密封保存', '室温避光', '儿童接触不到的地方'],
|
||||
type: [String],
|
||||
})
|
||||
storageAdvice: string[];
|
||||
|
||||
@ApiProperty({
|
||||
description: '健康建议',
|
||||
example: ['按时服药', '多喝水', '避免饮酒'],
|
||||
type: [String],
|
||||
})
|
||||
healthAdvice: string[];
|
||||
|
||||
@ApiProperty({
|
||||
description: '识别置信度(0-1)',
|
||||
example: 0.95,
|
||||
})
|
||||
confidence: number;
|
||||
}
|
||||
60
src/medications/dto/recognition-status.dto.ts
Normal file
60
src/medications/dto/recognition-status.dto.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { RecognitionStatusEnum } from '../enums/recognition-status.enum';
|
||||
import { RecognitionResultDto } from './recognition-result.dto';
|
||||
|
||||
/**
|
||||
* 药物识别状态响应 DTO
|
||||
*/
|
||||
export class RecognitionStatusDto {
|
||||
@ApiProperty({
|
||||
description: '任务ID',
|
||||
example: 'task_user123_1234567890',
|
||||
})
|
||||
taskId: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '识别状态',
|
||||
enum: RecognitionStatusEnum,
|
||||
example: RecognitionStatusEnum.ANALYZING_PRODUCT,
|
||||
})
|
||||
status: RecognitionStatusEnum;
|
||||
|
||||
@ApiProperty({
|
||||
description: '当前步骤描述',
|
||||
example: '正在识别药品基本信息...',
|
||||
})
|
||||
currentStep: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '进度百分比(0-100)',
|
||||
example: 40,
|
||||
})
|
||||
progress: number;
|
||||
|
||||
@ApiProperty({
|
||||
description: '识别结果(仅在状态为completed时返回)',
|
||||
type: RecognitionResultDto,
|
||||
required: false,
|
||||
})
|
||||
result?: RecognitionResultDto;
|
||||
|
||||
@ApiProperty({
|
||||
description: '错误信息(仅在状态为failed时返回)',
|
||||
example: '图片无法识别,请提供更清晰的照片',
|
||||
required: false,
|
||||
})
|
||||
errorMessage?: string;
|
||||
|
||||
@ApiProperty({
|
||||
description: '创建时间',
|
||||
example: '2025-01-20T12:00:00.000Z',
|
||||
})
|
||||
createdAt: Date;
|
||||
|
||||
@ApiProperty({
|
||||
description: '完成时间(仅在completed或failed时返回)',
|
||||
example: '2025-01-20T12:01:30.000Z',
|
||||
required: false,
|
||||
})
|
||||
completedAt?: Date;
|
||||
}
|
||||
Reference in New Issue
Block a user