88 lines
3.2 KiB
C#
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);
|
|
}
|
|
} |