refactor: 移除executeTemplateByCode接口的后端图片审核功能

- 简化执行流程,直接执行模板跳过后端审核
- 支持前端传递auditTaskId参数用于审核追踪
- 移除UnifiedContentService依赖和相关审核逻辑
- 删除handleAuditComplete和startTemplateExecution方法
- 更新API文档说明前端审核职责
- 修改测试用例适配新的执行流程
- 保持数据库字段兼容性,auditTaskId改为前端传入

变更影响:
- executeTemplateByCode接口不再执行后端图片审核
- 执行记录状态直接设为PROCESSING
- 前端需要在调用接口前完成图片审核
This commit is contained in:
imeepos 2025-09-08 11:01:30 +08:00
parent 6ef0fe5bb1
commit fe0aa0a9c5
3 changed files with 55 additions and 84 deletions

View File

@ -190,28 +190,23 @@ describe('TemplateController', () => {
); );
mockTemplate.execute.mockResolvedValue('task123'); mockTemplate.execute.mockResolvedValue('task123');
unifiedContentService.auditImage.mockResolvedValue({
taskId: 'audit123',
status: AuditStatus.COMPLETED,
conclusion: AuditConclusion.PASS,
confidence: 99,
details: [],
riskLevel: RiskLevel.LOW,
suggestion: AuditSuggestion.PASS,
timestamp: new Date(),
} as any);
const result = await controller.executeTemplateByCode( const result = await controller.executeTemplateByCode(
'test_template_v1', 'test_template_v1',
{ imageUrl: 'http://example.com/input.jpg' }, { imageUrl: 'http://example.com/input.jpg', auditTaskId: 'audit123' },
mockRequest, mockRequest,
); );
expect(result.code).toBe(200); expect(result.code).toBe(200);
expect(result.data?.executionId).toBe(1); expect(result.data?.executionId).toBe(1);
expect(result.data?.taskId).toBe('task123'); expect(result.data?.taskId).toBe('task123');
expect(result.data?.auditTaskId).toBe('audit123');
expect(result.data?.status).toBe('processing'); expect(result.data?.status).toBe('processing');
expect(unifiedContentService.auditImage).toHaveBeenCalled(); expect(templateFactory.createTemplateByCode).toHaveBeenCalledWith(
'test_template_v1',
);
expect(mockTemplate.execute).toHaveBeenCalledWith(
'http://example.com/input.jpg',
);
}); });
it('should throw error when template not found', async () => { it('should throw error when template not found', async () => {
@ -228,37 +223,24 @@ describe('TemplateController', () => {
); );
}); });
it('should throw error when image audit fails', async () => { it('should execute template without audit when auditTaskId is not provided', async () => {
templateFactory.getTemplateByCode.mockResolvedValue(mockTemplate as any); templateFactory.getTemplateByCode.mockResolvedValue(mockTemplate as any);
templateFactory.createTemplateByCode.mockResolvedValue(
// Reset the mock to ensure it returns the correct audit failure response mockTemplate as any,
unifiedContentService.auditImage.mockResolvedValue({
taskId: 'audit123',
status: AuditStatus.COMPLETED,
conclusion: AuditConclusion.REJECT,
confidence: 95,
details: [
{
type: 'inappropriate_content',
label: 'blocked',
confidence: 95,
description: '包含不当内容',
},
],
riskLevel: RiskLevel.HIGH,
suggestion: AuditSuggestion.BLOCK,
timestamp: new Date(),
} as any);
await expect(
controller.executeTemplateByCode(
'test_template_v1',
{ imageUrl: 'http://example.com/input.jpg' },
mockRequest,
),
).rejects.toThrow(
new HttpException('图片审核未通过: 包含不当内容', HttpStatus.FORBIDDEN),
); );
mockTemplate.execute.mockResolvedValue('task123');
const result = await controller.executeTemplateByCode(
'test_template_v1',
{ imageUrl: 'http://example.com/input.jpg' },
mockRequest,
);
expect(result.code).toBe(200);
expect(result.data?.executionId).toBe(1);
expect(result.data?.taskId).toBe('task123');
expect(result.data?.auditTaskId).toBeNull();
expect(result.data?.status).toBe('processing');
}); });
it('should throw error when user has too many tasks', async () => { it('should throw error when user has too many tasks', async () => {
@ -278,7 +260,7 @@ describe('TemplateController', () => {
), ),
).rejects.toThrow( ).rejects.toThrow(
new HttpException( new HttpException(
'有4个任务正在进行中请稍后再试', '当前账号有4个任务正在进行中且距开始时间不足5分钟,请稍后再试',
HttpStatus.TOO_MANY_REQUESTS, HttpStatus.TOO_MANY_REQUESTS,
), ),
); );

View File

@ -119,14 +119,16 @@ export class TemplateController {
@ApiOperation({ @ApiOperation({
summary: '通过代码执行模板', summary: '通过代码执行模板',
description: ` description: `
AI生成任务 AI生成任务
- executionId taskId
- executionId auditTaskId
ID说明
- imageUrl: 输入图片URL
- auditTaskId: 前端审核任务ID
ID说明
- executionId: 数据库执行记录主键 - executionId: 数据库执行记录主键
- taskId: 外部服务(N8N)ID - taskId: 外部服务(N8N)ID
- auditTaskId: 审核服务任务ID - auditTaskId: 前端传入的审核任务ID
`, `,
}) })
@ApiParam({ @ApiParam({
@ -144,35 +146,11 @@ export class TemplateController {
message: '模板执行已启动', message: '模板执行已启动',
data: { data: {
executionId: 123, executionId: 123,
taskId: 'n8n_task_456', // 同步模式 taskId: 'n8n_task_456',
status: 'processing' auditTaskId: 'audit_task_789',
} status: 'processing',
} message: '模板执行已启动',
} },
})
@SwaggerApiResponse({
status: 200,
description: '异步审核模式',
schema: {
example: {
code: 200,
message: '模板执行已提交,正在进行图片审核',
data: {
executionId: 124,
auditTaskId: 'audit_task_789', // 异步模式
status: 'pending_audit'
}
}
}
})
@SwaggerApiResponse({
status: 403,
description: '图片审核未通过',
schema: {
example: {
code: 403,
message: '图片审核未通过: 包含不当内容',
data: null,
}, },
}, },
}) })
@ -590,10 +568,10 @@ export class TemplateController {
outputUrl: null, outputUrl: null,
errorMessage: null, errorMessage: null,
createdAt: '2025-01-01T00:00:00Z', createdAt: '2025-01-01T00:00:00Z',
updatedAt: '2025-01-01T00:05:00Z' updatedAt: '2025-01-01T00:05:00Z',
} },
} },
} },
}) })
@SwaggerApiResponse({ @SwaggerApiResponse({
status: 404, status: 404,
@ -881,7 +859,6 @@ export class TemplateController {
} }
} }
/** /**
* *
*/ */
@ -899,7 +876,10 @@ export class TemplateController {
updateData.errorMessage = errorMessage; updateData.errorMessage = errorMessage;
} }
if (status === ExecutionStatus.FAILED || status === ExecutionStatus.AUDIT_FAILED) { if (
status === ExecutionStatus.FAILED ||
status === ExecutionStatus.AUDIT_FAILED
) {
updateData.completedAt = new Date(); updateData.completedAt = new Date();
} }

View File

@ -284,6 +284,15 @@ export class TemplateExecuteDto {
}) })
@IsString() @IsString()
imageUrl: string; imageUrl: string;
@ApiProperty({
description: '审核任务ID可选',
required: false,
example: 'audit_task_12345',
})
@IsString()
@IsOptional()
auditTaskId?: string;
} }
export class TemplateExecuteResponseDto { export class TemplateExecuteResponseDto {