# AI图片/视频生成服务配置指南 ## 1. 服务架构设计 ### 1.1 AI生成服务流程 ``` 用户请求 → 积分校验 → 任务创建 → 队列处理 → AI模型调用 → 结果存储 → 用户通知 ``` ### 1.2 核心组件 - **模板管理器**: 管理AI生成模板的注册和执行 - **任务管理器**: 管理生成任务的生命周期 - **积分系统**: 校验和扣除用户积分 - **文件存储**: 处理输入图片和生成结果的存储 - **异步队列**: 处理耗时的AI生成任务 ### 1.3 与模板系统集成 本服务与面向对象的模板管理系统深度集成: - 通过 `TemplateService` 执行具体的AI生成模板 - 使用 `GenerationTask` 实体记录任务状态和结果 - 模板信息存储在任务的 `metadata` 字段中 ## 2. AI生成服务实现 ### 2.1 生成任务服务 (与模板系统集成版本) ```typescript // src/services/generation.service.ts import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { GenerationTask, GenerationType, TaskStatus } from '../entities/generation-task.entity'; import { CreditService } from './credit.service'; import { TemplateService } from './template.service'; import { FileService } from './file.service'; import { MessageProducerService } from './message-producer.service'; @Injectable() export class GenerationService { constructor( @InjectRepository(GenerationTask) private readonly taskRepository: Repository, private readonly creditService: CreditService, private readonly templateService: TemplateService, private readonly fileService: FileService, private readonly messageProducer: MessageProducerService, ) {} // 新版本:通过模板代码创建生成任务 async createGenerationTaskByTemplate(createTaskDto: CreateTemplateTaskDto): Promise { const { userId, platform, templateCode, inputParameters } = createTaskDto; // 1. 获取模板信息 const templateInfo = this.templateService.getTemplateInfo(templateCode); if (!templateInfo) { throw new Error(`模板 ${templateCode} 不存在`); } // 2. 校验用户积分 const hasEnoughCredits = await this.creditService.checkBalance(userId, platform, templateInfo.creditCost); if (!hasEnoughCredits) { throw new Error('积分不足'); } // 3. 上传输入图片(如果有) let inputImageUrl = null; if (inputParameters.inputImage) { inputImageUrl = await this.fileService.uploadImage(inputParameters.inputImage, userId); inputParameters.inputImage = inputImageUrl; // 替换为URL } // 4. 创建任务记录 const task = this.taskRepository.create({ userId, platform, type: templateInfo.category.includes('视频') ? GenerationType.VIDEO : GenerationType.IMAGE, prompt: inputParameters.prompt || inputParameters.clothingDescription || '', inputImageUrl, creditCost: templateInfo.creditCost, parameters: inputParameters, status: TaskStatus.PENDING, metadata: { templateCode: templateInfo.code, templateName: templateInfo.name, templateVersion: templateInfo.version, templateCategory: templateInfo.category, }, }); const savedTask = await this.taskRepository.save(task); // 5. 扣除积分 await this.creditService.consumeCredits(userId, platform, templateInfo.creditCost, 'ai_generation', savedTask.id); // 6. 发送到处理队列 await this.messageProducer.sendGenerationTask({ taskId: savedTask.id, userId, platform, type: savedTask.type, templateCode, inputParameters, }); return savedTask; } async processGenerationTask(taskId: string): Promise { const task = await this.taskRepository.findOne({ where: { id: taskId } }); if (!task) { throw new Error('任务不存在'); } try { // 更新状态为处理中 await this.updateTaskStatus(taskId, TaskStatus.PROCESSING); const startTime = Date.now(); // 调用AI模型生成 const result = await this.aiModelService.generate({ type: task.type, prompt: task.prompt, inputImageUrl: task.inputImageUrl, parameters: task.parameters, }); const processingTime = Math.floor((Date.now() - startTime) / 1000); // 上传生成结果 const outputUrl = await this.fileService.uploadGeneratedContent(result.content, task.userId); const thumbnailUrl = await this.fileService.generateThumbnail(outputUrl, task.userId); // 更新任务结果 await this.taskRepository.update(taskId, { status: TaskStatus.COMPLETED, outputUrl, thumbnailUrl, processingTime, }); // 发送完成通知 await this.messageProducer.sendGenerationCompleted({ taskId, userId: task.userId, platform: task.platform, outputUrl, thumbnailUrl, }); } catch (error) { // 处理失败,退还积分 await this.creditService.refundCredits( task.userId, task.platform, task.creditCost, 'ai_generation_failed', taskId ); await this.taskRepository.update(taskId, { status: TaskStatus.FAILED, errorMessage: error.message, }); } } private calculateCreditCost(type: GenerationType, parameters: any): number { // 根据生成类型和参数计算积分消耗 (与credit-and-ad-system.md保持一致) let baseCost = type === GenerationType.IMAGE ? 10 : 50; // 图片10积分,视频50积分 // 根据参数调整消耗 if (type === GenerationType.IMAGE) { // 图片生成:基础10积分,高质量15积分 if (parameters?.quality === 'high') { baseCost = 15; } } else { // 视频生成:基础50积分,高质量75积分 if (parameters?.quality === 'high') { baseCost = 75; } } // 分辨率额外消耗 if (parameters?.resolution === '4k') { baseCost = Math.ceil(baseCost * 1.5); } return baseCost; } async getUserTasks(userId: string, platform: string, page: number = 1, limit: number = 10) { const [tasks, total] = await this.taskRepository.findAndCount({ where: { userId, platform }, order: { createdAt: 'DESC' }, skip: (page - 1) * limit, take: limit, }); return { tasks, total, page, limit, totalPages: Math.ceil(total / limit), }; } async getTaskById(taskId: string, userId: string): Promise { const task = await this.taskRepository.findOne({ where: { id: taskId, userId }, }); if (!task) { throw new Error('任务不存在或无权限访问'); } return task; } private async updateTaskStatus(taskId: string, status: TaskStatus): Promise { await this.taskRepository.update(taskId, { status }); } } ``` ### 2.2 AI模型适配器服务 ```typescript // src/services/ai-model.service.ts import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import axios from 'axios'; export interface GenerationRequest { type: 'image' | 'video'; prompt: string; inputImageUrl?: string; parameters?: any; } export interface GenerationResult { content: Buffer; contentType: string; metadata?: any; } @Injectable() export class AIModelService { constructor(private readonly configService: ConfigService) {} async generate(request: GenerationRequest): Promise { if (request.type === 'image') { return this.generateImage(request); } else { return this.generateVideo(request); } } private async generateImage(request: GenerationRequest): Promise { // 示例:调用Stable Diffusion API const apiUrl = this.configService.get('STABLE_DIFFUSION_API_URL'); const apiKey = this.configService.get('STABLE_DIFFUSION_API_KEY'); const payload = { prompt: request.prompt, negative_prompt: "low quality, blurry, distorted", width: request.parameters?.width || 512, height: request.parameters?.height || 512, steps: request.parameters?.steps || 20, cfg_scale: request.parameters?.cfg_scale || 7, sampler_name: request.parameters?.sampler || "DPM++ 2M Karras", }; if (request.inputImageUrl) { // 图生图模式 const inputImageBuffer = await this.downloadImage(request.inputImageUrl); payload['init_images'] = [inputImageBuffer.toString('base64')]; payload['denoising_strength'] = request.parameters?.denoising_strength || 0.7; } const response = await axios.post(`${apiUrl}/sdapi/v1/txt2img`, payload, { headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, timeout: 120000, // 2分钟超时 }); const imageBase64 = response.data.images[0]; const imageBuffer = Buffer.from(imageBase64, 'base64'); return { content: imageBuffer, contentType: 'image/png', metadata: { seed: response.data.info?.seed, parameters: payload, }, }; } private async generateVideo(request: GenerationRequest): Promise { // 示例:调用RunwayML或其他视频生成API const apiUrl = this.configService.get('VIDEO_GENERATION_API_URL'); const apiKey = this.configService.get('VIDEO_GENERATION_API_KEY'); const payload = { prompt: request.prompt, duration: request.parameters?.duration || 5, // 5秒视频 fps: request.parameters?.fps || 24, resolution: request.parameters?.resolution || '720p', }; if (request.inputImageUrl) { payload['image_url'] = request.inputImageUrl; } // 创建生成任务 const createResponse = await axios.post(`${apiUrl}/generate`, payload, { headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, }); const taskId = createResponse.data.task_id; // 轮询任务状态 let attempts = 0; const maxAttempts = 60; // 最多等待10分钟 while (attempts < maxAttempts) { await new Promise(resolve => setTimeout(resolve, 10000)); // 等待10秒 const statusResponse = await axios.get(`${apiUrl}/task/${taskId}`, { headers: { 'Authorization': `Bearer ${apiKey}` }, }); if (statusResponse.data.status === 'completed') { const videoUrl = statusResponse.data.result_url; const videoBuffer = await this.downloadVideo(videoUrl); return { content: videoBuffer, contentType: 'video/mp4', metadata: { taskId, duration: payload.duration, fps: payload.fps, }, }; } else if (statusResponse.data.status === 'failed') { throw new Error(`视频生成失败: ${statusResponse.data.error}`); } attempts++; } throw new Error('视频生成超时'); } private async downloadImage(url: string): Promise { const response = await axios.get(url, { responseType: 'arraybuffer' }); return Buffer.from(response.data); } private async downloadVideo(url: string): Promise { const response = await axios.get(url, { responseType: 'arraybuffer' }); return Buffer.from(response.data); } } ``` ## 3. 文件存储服务 ### 3.1 文件管理服务 ```typescript // src/services/file.service.ts import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import * as AWS from 'aws-sdk'; import * as sharp from 'sharp'; import { v4 as uuidv4 } from 'uuid'; @Injectable() export class FileService { private s3: AWS.S3; private bucketName: string; constructor(private readonly configService: ConfigService) { this.s3 = new AWS.S3({ accessKeyId: this.configService.get('AWS_ACCESS_KEY_ID'), secretAccessKey: this.configService.get('AWS_SECRET_ACCESS_KEY'), region: this.configService.get('AWS_REGION'), }); this.bucketName = this.configService.get('AWS_S3_BUCKET'); } async uploadImage(imageBuffer: Buffer, userId: string): Promise { const fileName = `inputs/${userId}/${uuidv4()}.jpg`; // 压缩图片 const compressedImage = await sharp(imageBuffer) .jpeg({ quality: 85 }) .resize(1024, 1024, { fit: 'inside', withoutEnlargement: true }) .toBuffer(); const uploadParams = { Bucket: this.bucketName, Key: fileName, Body: compressedImage, ContentType: 'image/jpeg', ACL: 'public-read', }; const result = await this.s3.upload(uploadParams).promise(); return result.Location; } async uploadGeneratedContent(content: Buffer, userId: string): Promise { const fileName = `outputs/${userId}/${uuidv4()}.png`; const uploadParams = { Bucket: this.bucketName, Key: fileName, Body: content, ContentType: 'image/png', ACL: 'public-read', }; const result = await this.s3.upload(uploadParams).promise(); return result.Location; } async generateThumbnail(imageUrl: string, userId: string): Promise { // 下载原图 const response = await fetch(imageUrl); const imageBuffer = Buffer.from(await response.arrayBuffer()); // 生成缩略图 const thumbnail = await sharp(imageBuffer) .resize(200, 200, { fit: 'cover' }) .jpeg({ quality: 80 }) .toBuffer(); const fileName = `thumbnails/${userId}/${uuidv4()}.jpg`; const uploadParams = { Bucket: this.bucketName, Key: fileName, Body: thumbnail, ContentType: 'image/jpeg', ACL: 'public-read', }; const result = await this.s3.upload(uploadParams).promise(); return result.Location; } } ``` ## 4. 环境配置 ### 4.1 AI服务配置 ```env # Stable Diffusion API STABLE_DIFFUSION_API_URL=https://api.stability.ai STABLE_DIFFUSION_API_KEY=your-stability-api-key # 视频生成API (示例:RunwayML) VIDEO_GENERATION_API_URL=https://api.runwayml.com VIDEO_GENERATION_API_KEY=your-runway-api-key # 文件存储配置 AWS_ACCESS_KEY_ID=your-aws-access-key AWS_SECRET_ACCESS_KEY=your-aws-secret-key AWS_REGION=us-east-1 AWS_S3_BUCKET=your-s3-bucket-name # 积分配置 DEFAULT_IMAGE_CREDIT_COST=10 DEFAULT_VIDEO_CREDIT_COST=50 HIGH_QUALITY_MULTIPLIER=1.5 ``` ## 5. API接口示例 ### 5.1 创建生成任务 ```typescript @Post('generate') @ApiOperation({ summary: '创建AI生成任务' }) async createTask(@Body() createTaskDto: CreateGenerationTaskDto) { return this.generationService.createGenerationTask(createTaskDto); } ``` ### 5.2 查询任务状态 ```typescript @Get('tasks/:taskId') @ApiOperation({ summary: '查询生成任务状态' }) async getTask(@Param('taskId') taskId: string, @CurrentUser() user: any) { return this.generationService.getTaskById(taskId, user.id); } ``` ### 5.3 获取用户任务列表 ```typescript @Get('tasks') @ApiOperation({ summary: '获取用户生成任务列表' }) async getUserTasks( @CurrentUser() user: any, @Query('page') page: number = 1, @Query('limit') limit: number = 10 ) { return this.generationService.getUserTasks(user.id, user.platform, page, limit); } ``` 这个AI生成服务提供了完整的图片/视频生成功能,包括任务管理、积分校验、文件存储和异步处理等核心功能。