Files
bw-mini-app-server/src/content-moderation/adapters/enhanced-base-content.adapter.ts
imeepos e36cdfc38d test: 完善单元测试覆盖率并优化统一异步架构
- 添加 AppController 测试用例,测试回调接口的错误处理
- 新增控制器、服务层、平台服务等全面的单元测试
- 优化增强模板控制器的错误处理和审核完成事件处理
- 添加数据库迁移脚本支持统一异步架构升级
- 完善 TypeScript 配置,添加 jest 类型支持
- 修复端到端测试,确保 API 响应格式正确性
- 所有测试通过 (109 个测试用例),覆盖率达到要求
2025-09-05 17:05:08 +08:00

124 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Injectable, Inject, Optional } from '@nestjs/common';
import { BaseContentAdapter } from './base-content.adapter';
import {
ImageAuditRequest,
ContentAuditResult,
AuditStatus,
AuditConclusion,
RiskLevel,
AuditSuggestion,
} from '../interfaces/content-moderation.interface';
// 定义回调接口
export interface IAuditCompleteCallback {
handleAuditComplete(auditTaskId: string, auditResult: ContentAuditResult): Promise<void>;
}
/**
* 增强的基础适配器,实现平台差异抹平
*/
@Injectable()
export abstract class EnhancedBaseContentAdapter extends BaseContentAdapter {
/**
* 标识是否为同步平台
*/
abstract readonly isSyncPlatform: boolean;
/**
* 统一的审核接口 - 所有平台都返回异步状态
*/
async auditImage(auditData: ImageAuditRequest): Promise<ContentAuditResult> {
try {
// 1. 创建审核日志
const auditLog = await this.createAuditLog(auditData);
// 2. 验证图片URL
const isValidImage = await this.validateImageUrl(auditData.imageUrl);
if (!isValidImage) {
throw new Error('无效的图片URL');
}
// 3. 调用平台特定的审核方法
const platformResult = await this.callPlatformAuditAPI({
...auditData,
taskId: auditLog.taskId,
});
// 4. 统一返回PROCESSING状态
const unifiedResult: ContentAuditResult = {
taskId: auditLog.taskId,
status: AuditStatus.PROCESSING,
conclusion: AuditConclusion.UNCERTAIN,
confidence: 0,
details: [],
riskLevel: RiskLevel.MEDIUM,
suggestion: AuditSuggestion.HUMAN_REVIEW,
timestamp: new Date(),
};
// 5. 更新审核日志为处理中状态
await this.updateAuditLog(auditLog.taskId, unifiedResult);
// 6. 如果是同步平台,立即模拟异步回调
if (this.isSyncPlatform) {
setImmediate(async () => {
try {
await this.handleAuditCallback(this.formatCallbackData(platformResult));
} catch (error) {
console.error(`模拟回调失败 (${this.platform}):`, error);
}
});
}
return unifiedResult;
} catch (error) {
const auditError = this.handleAuditError(error, this.platform);
throw auditError;
}
}
/**
* 平台特定的API调用 - 子类实现
*/
protected abstract callPlatformAuditAPI(
auditData: ImageAuditRequest
): Promise<any>;
/**
* 格式化平台结果为回调数据格式 - 同步平台需要
*/
protected abstract formatCallbackData(platformResult: any): any;
/**
* 🎯 通知模板执行系统 - 审核完成后的关键集成点
*
* 当前实现:发布事件,由审核完成事件监听器处理
* 未来优化:可以改为事件总线或消息队列
*/
protected async notifyTemplateExecution(taskId: string, auditResult: ContentAuditResult): Promise<void> {
try {
// 🎯 发布审核完成事件
console.log(`🎯 审核完成事件 [${this.platform}]:`, {
auditTaskId: taskId,
conclusion: auditResult.conclusion,
confidence: auditResult.confidence,
platformData: auditResult.platformData
});
// 发布全局事件,通过事件名称让监听者处理
// 这样可以解耦审核系统和模板执行系统
if (global.process) {
// 使用 process 作为 EventEmitter避免 TypeScript 信号类型错误
(global.process as any).emit('auditComplete', {
auditTaskId: taskId,
auditResult: auditResult,
platform: this.platform
});
}
} catch (error) {
console.error(`模板执行通知失败 [${this.platform}]:`, error);
}
}
}