fix: 修复template.controller支持异步审核模式

解决原有template.controller在异步审核模式下无法工作的问题:

🔧 核心修改:
- 检测auditResult.conclusion字段判断同步/异步审核模式
- 同步模式:立即检查审核结果并执行模板
- 异步模式:保存执行记录,等待回调处理

🆕 新增功能:
- handleAuditComplete() 处理审核完成回调
- startTemplateExecution() 启动模板执行
- updateExecutionStatus() 更新执行状态
- 支持PENDING_AUDIT状态管理

📈 改进效果:
- 保持API接口向后兼容
- 同时支持微信同步审核和抖音异步审核
- 完善错误处理和状态管理
- 用户可查询执行进度

 修复问题:
- 解决template.controller.ts:201行异步审核时的undefined错误
- 统一审核架构,无需维护两套API
This commit is contained in:
imeepos 2025-09-05 17:21:16 +08:00
parent e36cdfc38d
commit 71b26fb5c4
2 changed files with 178 additions and 27 deletions

View File

@ -45,7 +45,10 @@ import { ApiCommonResponses } from '../decorators/api-common-responses.decorator
import { PlatformAuthGuard } from '../platform/guards/platform-auth.guard';
import { ResponseUtil, ApiResponse } from '../utils/response.util';
import { UnifiedContentService } from '../content-moderation/services/unified-content.service';
import { AuditConclusion } from '../content-moderation/interfaces/content-moderation.interface';
import {
AuditConclusion,
AuditStatus,
} from '../content-moderation/interfaces/content-moderation.interface';
@ApiTags('AI模板系统')
@Controller('templates')
@ -162,7 +165,7 @@ export class TemplateController {
@Param('code') code: string,
@Body() body: { imageUrl: string },
@Request() req,
): Promise<ApiResponse<number>> {
): Promise<ApiResponse<any>> {
try {
const { imageUrl } = body;
@ -197,25 +200,40 @@ export class TemplateController {
},
);
// 2. 检查审核结果
if (auditResult.conclusion !== AuditConclusion.PASS) {
const failureReason =
auditResult.details.length > 0
? auditResult.details.map((d) => d.description).join(', ')
: '包含不当内容';
// 2. 处理审核结果(支持同步和异步模式)
const finalAuditResult = auditResult;
let taskId: string | null = null;
throw new HttpException(
`图片审核未通过: ${failureReason}`,
HttpStatus.FORBIDDEN,
// 检查是否为同步审核有conclusion字段
if (auditResult.conclusion !== undefined) {
console.log('同步审核模式,立即检查结果');
// 3. 检查同步审核结果
if (auditResult.conclusion !== AuditConclusion.PASS) {
const failureReason =
auditResult.details && auditResult.details.length > 0
? auditResult.details.map((d) => d.description).join(', ')
: '包含不当内容';
throw new HttpException(
`图片审核未通过: ${failureReason}`,
HttpStatus.FORBIDDEN,
);
}
// 4. 同步审核通过,立即执行模板
console.log('图片审核通过,开始执行模板');
const template = await this.templateFactory.createTemplateByCode(code);
taskId = await template.execute(imageUrl);
} else {
// 异步审核模式,立即返回执行记录,等待回调
console.log(
`异步审核模式等待审核完成auditTaskId: ${auditResult.taskId}`,
);
}
// 3. 审核通过,执行模板
const template = await this.templateFactory.createTemplateByCode(code);
const taskId = await template.execute(imageUrl);
// 4. 将任务保存到 TemplateExecutionEntity
const execution = this.executionRepository.create({
// 5. 创建执行记录
const executionData = {
templateId: templateConfig.id,
userId,
platform: req.user.platform,
@ -225,17 +243,43 @@ export class TemplateController {
: ExecutionType.IMAGE,
prompt: '', // 可以从请求参数中获取,如果有的话
inputImageUrl: imageUrl,
taskId: taskId, // 保存外部系统返回的任务ID用于回调匹配
status: ExecutionStatus.PROCESSING,
taskId: taskId || undefined, // 同步模式时有值异步模式时为undefined
auditTaskId: auditResult.taskId, // 审核任务ID用于回调匹配
status: taskId
? ExecutionStatus.PROCESSING
: ExecutionStatus.PENDING_AUDIT, // 根据模式设置状态
progress: 0,
creditCost: templateConfig.creditCost,
startedAt: new Date(),
});
};
const execution = this.executionRepository.create(executionData);
const savedExecution = await this.executionRepository.save(execution);
// 返回任务id (执行记录的ID) 以及审核信息
return ResponseUtil.success(savedExecution.id, '模板执行已启动');
// 6. 返回结果
if (taskId) {
// 同步模式:审核通过且模板已开始执行
return ResponseUtil.success(
{
executionId: savedExecution.id,
taskId,
status: 'processing',
message: '模板执行已启动',
},
'模板执行已启动',
);
} else {
// 异步模式:审核中,等待回调
return ResponseUtil.success(
{
executionId: savedExecution.id,
auditTaskId: auditResult.taskId,
status: 'pending_audit',
message: '图片审核中,请查询执行进度获取最新状态',
},
'模板执行已提交,正在进行图片审核',
);
}
} catch (error) {
console.error(error);
throw new HttpException(
@ -815,6 +859,99 @@ export class TemplateController {
}
}
/**
* 🎯 -
*/
async handleAuditComplete(
auditTaskId: string,
auditResult: any,
): Promise<void> {
try {
// 查找对应的执行记录
const execution = await this.executionRepository.findOne({
where: { auditTaskId },
relations: ['template'],
});
if (!execution) {
console.error(`未找到审核任务对应的执行记录: ${auditTaskId}`);
return;
}
// 根据审核结果决定后续处理
if (auditResult.conclusion === AuditConclusion.PASS) {
// 审核通过,开始执行模板
await this.startTemplateExecution(execution);
} else {
// 审核不通过,更新状态为审核失败
await this.updateExecutionStatus(
execution.id,
ExecutionStatus.FAILED,
`图片审核未通过: ${auditResult.details?.map((d) => d.description).join(', ') || '包含不当内容'}`,
);
}
} catch (error) {
console.error('处理审核完成回调失败:', error);
}
}
/**
*
*/
private async startTemplateExecution(
execution: TemplateExecutionEntity,
): Promise<void> {
try {
// 1. 更新状态为执行中
await this.updateExecutionStatus(
execution.id,
ExecutionStatus.PROCESSING,
);
// 2. 创建模板实例并执行
const template = await this.templateFactory.createTemplateByCode(
execution.template.code,
);
const taskId = await template.execute(execution.inputImageUrl);
// 3. 更新外部任务ID
await this.executionRepository.update(execution.id, {
taskId: taskId, // N8N或其他服务返回的任务ID
});
} catch (error) {
console.error('模板执行失败:', error);
await this.updateExecutionStatus(
execution.id,
ExecutionStatus.FAILED,
`模板执行失败: ${error.message}`,
);
}
}
/**
*
*/
private async updateExecutionStatus(
executionId: number,
status: ExecutionStatus,
errorMessage?: string,
): Promise<void> {
const updateData: Partial<TemplateExecutionEntity> = {
status,
updatedAt: new Date(),
};
if (errorMessage) {
updateData.errorMessage = errorMessage;
}
if (status === ExecutionStatus.FAILED) {
updateData.completedAt = new Date();
}
await this.executionRepository.update(executionId, updateData);
}
/**
*
* @param page

View File

@ -3,6 +3,7 @@ import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';
import { setupSwagger } from './config/swagger.config';
import { EnhancedTemplateController } from './controllers/enhanced-template.controller';
import { TemplateController } from './controllers/template.controller';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
@ -40,13 +41,23 @@ async function bootstrap() {
// 🎯 设置审核完成事件监听器
const enhancedTemplateController = app.get(EnhancedTemplateController);
const templateController = app.get(TemplateController);
process.on('auditComplete', async (eventData: any) => {
try {
console.log('🎯 收到审核完成事件:', eventData);
await enhancedTemplateController.handleAuditComplete(
eventData.auditTaskId,
eventData.auditResult
);
// 同时调用两个Controller的处理方法保证兼容性
await Promise.all([
enhancedTemplateController.handleAuditComplete(
eventData.auditTaskId,
eventData.auditResult,
),
templateController.handleAuditComplete(
eventData.auditTaskId,
eventData.auditResult,
),
]);
} catch (error) {
console.error('处理审核完成事件失败:', error);
}
@ -59,6 +70,9 @@ async function bootstrap() {
console.log(`📡 服务地址: http://localhost:${port}`);
console.log(`📖 API文档地址: http://localhost:${port}/docs`);
console.log(`📋 模板管理 API: http://localhost:${port}/api/v1/templates`);
console.log(`🎯 统一异步架构已启用!`);
console.log(
`🔄 增强版 API: http://localhost:${port}/api/v1/enhanced/templates`,
);
console.log(`🎯 统一异步架构已启用!支持同步和异步审核模式`);
}
bootstrap();