dramaling-vocab-learning/backend/DramaLing.Api/Services/AI/Generation/ImageSaveManager.cs

88 lines
3.2 KiB
C#

using DramaLing.Api.Data;
using DramaLing.Api.Models.Entities;
using DramaLing.Api.Services.Storage;
using DramaLing.Api.Services;
namespace DramaLing.Api.Services.AI.Generation;
public class ImageSaveManager : IImageSaveManager
{
private readonly ILogger<ImageSaveManager> _logger;
public ImageSaveManager(ILogger<ImageSaveManager> logger)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public async Task<ExampleImage> SaveGeneratedImageAsync(
DramaLingDbContext dbContext,
IImageStorageService storageService,
IImageProcessingService imageProcessingService,
ImageGenerationRequest request,
string optimizedPrompt,
ReplicateImageResult imageResult)
{
// 下載原圖 (1024x1024)
using var httpClient = new HttpClient();
var originalBytes = await httpClient.GetByteArrayAsync(imageResult.ImageUrl);
_logger.LogInformation("Downloaded original image: {OriginalSize}KB", originalBytes.Length / 1024);
// 壓縮為 512x512
var resizedBytes = await imageProcessingService.ResizeImageAsync(originalBytes, 512, 512);
var imageStream = new MemoryStream(resizedBytes);
// 生成檔案名稱
var fileName = $"{request.FlashcardId}_{Guid.NewGuid()}.png";
// 儲存到本地/雲端
var relativePath = await storageService.SaveImageAsync(imageStream, fileName);
// 建立 ExampleImage 記錄
var exampleImage = new ExampleImage
{
Id = Guid.NewGuid(),
RelativePath = relativePath,
AltText = $"Example image for {request.Flashcard?.Word}",
GeminiPrompt = request.GeminiPrompt,
GeminiDescription = request.GeneratedDescription,
ReplicatePrompt = optimizedPrompt,
ReplicateModel = "ideogram-v2a-turbo",
GeminiCost = request.GeminiCost ?? 0.002m,
ReplicateCost = imageResult.Cost,
TotalGenerationCost = (request.GeminiCost ?? 0.002m) + imageResult.Cost,
FileSize = resizedBytes.Length,
ImageWidth = 512,
ImageHeight = 512,
ContentHash = ComputeHash(resizedBytes),
ModerationStatus = "pending",
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow
};
dbContext.ExampleImages.Add(exampleImage);
// 建立詞卡圖片關聯
var flashcardImage = new FlashcardExampleImage
{
FlashcardId = request.FlashcardId,
ExampleImageId = exampleImage.Id,
DisplayOrder = 1,
IsPrimary = true,
ContextRelevance = 1.0m,
CreatedAt = DateTime.UtcNow
};
dbContext.FlashcardExampleImages.Add(flashcardImage);
await dbContext.SaveChangesAsync();
return exampleImage;
}
private static string ComputeHash(byte[] bytes)
{
using var sha256 = System.Security.Cryptography.SHA256.Create();
var hashBytes = sha256.ComputeHash(bytes);
return Convert.ToHexString(hashBytes);
}
}