feat: 完成图片生成功能
This commit is contained in:
@@ -15,7 +15,7 @@ public class AgentSendInput
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// api密钥Id
|
/// api密钥Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Token { get; set; }
|
public Guid TokenId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 模型id
|
/// 模型id
|
||||||
|
|||||||
@@ -5,6 +5,11 @@ namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Chat;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ImageGenerationInput
|
public class ImageGenerationInput
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 密钥id
|
||||||
|
/// </summary>
|
||||||
|
public Guid? TokenId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 提示词
|
/// 提示词
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -16,7 +21,7 @@ public class ImageGenerationInput
|
|||||||
public string ModelId { get; set; } = string.Empty;
|
public string ModelId { get; set; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 参考图Base64列表(可选,包含前缀如 data:image/png;base64,...)
|
/// 参考图PrefixBase64列表(可选,包含前缀如 data:image/png;base64,...)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<string>? ReferenceImagesBase64 { get; set; }
|
public List<string>? ReferenceImagesPrefixBase64 { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,19 +18,19 @@ public class ImageTaskOutput
|
|||||||
public string Prompt { get; set; } = string.Empty;
|
public string Prompt { get; set; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 参考图Base64列表
|
/// 参考图PrefixBase64列表(带前缀)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<string>? ReferenceImagesBase64 { get; set; }
|
// public List<string>? ReferenceImagesPrefixBase64 { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 参考图URL列表
|
/// 参考图URL列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<string>? ReferenceImagesUrl { get; set; }
|
// public List<string>? ReferenceImagesUrl { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生成图片Base64(包含前缀)
|
/// 生成图片PrefixBase64(包含前缀)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? StoreBase64 { get; set; }
|
public string? StorePrefixBase64 { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生成图片URL
|
/// 生成图片URL
|
||||||
@@ -42,6 +42,16 @@ public class ImageTaskOutput
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public TaskStatusEnum TaskStatus { get; set; }
|
public TaskStatusEnum TaskStatus { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发布状态
|
||||||
|
/// </summary>
|
||||||
|
public PublishStatusEnum PublishStatus { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 分类标签
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Categories { get; set; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建时间
|
/// 创建时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Chat;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发布图片输入
|
||||||
|
/// </summary>
|
||||||
|
public class PublishImageInput
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 任务ID
|
||||||
|
/// </summary>
|
||||||
|
public Guid TaskId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 分类标签
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Categories { get; set; } = new();
|
||||||
|
}
|
||||||
@@ -7,12 +7,6 @@ public class ModelGetListOutput
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型分类
|
|
||||||
/// </summary>
|
|
||||||
public string Category { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 模型id
|
/// 模型id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -28,36 +22,6 @@ public class ModelGetListOutput
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string? ModelDescribe { get; set; }
|
public string? ModelDescribe { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型价格
|
|
||||||
/// </summary>
|
|
||||||
public double ModelPrice { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型类型
|
|
||||||
/// </summary>
|
|
||||||
public string ModelType { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型展示状态
|
|
||||||
/// </summary>
|
|
||||||
public string ModelShow { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 系统提示
|
|
||||||
/// </summary>
|
|
||||||
public string SystemPrompt { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// API 主机地址
|
|
||||||
/// </summary>
|
|
||||||
public string ApiHost { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// API 密钥
|
|
||||||
/// </summary>
|
|
||||||
public string ApiKey { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 备注信息
|
/// 备注信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -30,18 +30,55 @@ public class ImageGenerationJob : AsyncBackgroundJob<ImageGenerationJobArgs>, IT
|
|||||||
|
|
||||||
public override async Task ExecuteAsync(ImageGenerationJobArgs args)
|
public override async Task ExecuteAsync(ImageGenerationJobArgs args)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("开始执行图片生成任务,TaskId: {TaskId}, ModelId: {ModelId}, UserId: {UserId}",
|
var task = await _imageStoreTaskRepository.GetFirstAsync(x => x.Id == args.TaskId);
|
||||||
args.TaskId, args.ModelId, args.UserId);
|
if (task is null)
|
||||||
|
{
|
||||||
|
throw new UserFriendlyException($"{args.TaskId} 图片生成任务不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("开始执行图片生成任务,TaskId: {TaskId}, ModelId: {ModelId}, UserId: {UserId}",
|
||||||
|
task.Id, task.ModelId, task.UserId);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var request = JsonSerializer.Deserialize<JsonElement>(args.RequestJson);
|
// 构建 Gemini API 请求对象
|
||||||
|
var parts = new List<object>
|
||||||
|
{
|
||||||
|
new { text = task.Prompt }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加参考图(如果有)
|
||||||
|
foreach (var prefixBase64 in task.ReferenceImagesPrefixBase64)
|
||||||
|
{
|
||||||
|
var (mimeType, base64Data) = ParsePrefixBase64(prefixBase64);
|
||||||
|
parts.Add(new
|
||||||
|
{
|
||||||
|
inline_data = new
|
||||||
|
{
|
||||||
|
mime_type = mimeType,
|
||||||
|
data = base64Data
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestObj = new
|
||||||
|
{
|
||||||
|
contents = new[]
|
||||||
|
{
|
||||||
|
new { parts }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var request = JsonSerializer.Deserialize<JsonElement>(
|
||||||
|
JsonSerializer.Serialize(requestObj));
|
||||||
|
|
||||||
|
//里面生成成功已经包含扣款了
|
||||||
await _aiGateWayManager.GeminiGenerateContentImageForStatisticsAsync(
|
await _aiGateWayManager.GeminiGenerateContentImageForStatisticsAsync(
|
||||||
args.TaskId,
|
task.Id,
|
||||||
args.ModelId,
|
task.ModelId,
|
||||||
request,
|
request,
|
||||||
args.UserId);
|
task.UserId,
|
||||||
|
tokenId:task.TokenId);
|
||||||
|
|
||||||
|
|
||||||
_logger.LogInformation("图片生成任务完成,TaskId: {TaskId}", args.TaskId);
|
_logger.LogInformation("图片生成任务完成,TaskId: {TaskId}", args.TaskId);
|
||||||
}
|
}
|
||||||
@@ -49,13 +86,37 @@ public class ImageGenerationJob : AsyncBackgroundJob<ImageGenerationJobArgs>, IT
|
|||||||
{
|
{
|
||||||
_logger.LogError(ex, "图片生成任务失败,TaskId: {TaskId}, Error: {Error}", args.TaskId, ex.Message);
|
_logger.LogError(ex, "图片生成任务失败,TaskId: {TaskId}, Error: {Error}", args.TaskId, ex.Message);
|
||||||
|
|
||||||
// 更新任务状态为失败
|
|
||||||
var task = await _imageStoreTaskRepository.GetFirstAsync(x => x.Id == args.TaskId);
|
|
||||||
if (task != null)
|
|
||||||
{
|
|
||||||
task.TaskStatus = TaskStatusEnum.Fail;
|
task.TaskStatus = TaskStatusEnum.Fail;
|
||||||
|
task.ErrorInfo = ex.Message;
|
||||||
|
|
||||||
await _imageStoreTaskRepository.UpdateAsync(task);
|
await _imageStoreTaskRepository.UpdateAsync(task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解析带前缀的 Base64 字符串,提取 mimeType 和纯 base64 数据
|
||||||
|
/// </summary>
|
||||||
|
private static (string mimeType, string base64Data) ParsePrefixBase64(string prefixBase64)
|
||||||
|
{
|
||||||
|
// 默认值
|
||||||
|
var mimeType = "image/png";
|
||||||
|
var base64Data = prefixBase64;
|
||||||
|
|
||||||
|
if (prefixBase64.Contains(","))
|
||||||
|
{
|
||||||
|
var parts = prefixBase64.Split(',');
|
||||||
|
if (parts.Length == 2)
|
||||||
|
{
|
||||||
|
var header = parts[0];
|
||||||
|
if (header.Contains(":") && header.Contains(";"))
|
||||||
|
{
|
||||||
|
mimeType = header.Split(':')[1].Split(';')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
base64Data = parts[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (mimeType, base64Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,19 +9,4 @@ public class ImageGenerationJobArgs
|
|||||||
/// 图片任务ID
|
/// 图片任务ID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid TaskId { get; set; }
|
public Guid TaskId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型ID
|
|
||||||
/// </summary>
|
|
||||||
public string ModelId { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 请求JSON字符串
|
|
||||||
/// </summary>
|
|
||||||
public string RequestJson { get; set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用户ID
|
|
||||||
/// </summary>
|
|
||||||
public Guid UserId { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ public class AiChatService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取模型列表
|
/// 获取对话模型列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<List<ModelGetListOutput>> GetModelAsync()
|
public async Task<List<ModelGetListOutput>> GetModelAsync()
|
||||||
@@ -98,16 +98,9 @@ public class AiChatService : ApplicationService
|
|||||||
.Select(x => new ModelGetListOutput
|
.Select(x => new ModelGetListOutput
|
||||||
{
|
{
|
||||||
Id = x.Id,
|
Id = x.Id,
|
||||||
Category = "chat",
|
|
||||||
ModelId = x.ModelId,
|
ModelId = x.ModelId,
|
||||||
ModelName = x.Name,
|
ModelName = x.Name,
|
||||||
ModelDescribe = x.Description,
|
ModelDescribe = x.Description,
|
||||||
ModelPrice = 0,
|
|
||||||
ModelType = "1",
|
|
||||||
ModelShow = "0",
|
|
||||||
SystemPrompt = null,
|
|
||||||
ApiHost = null,
|
|
||||||
ApiKey = null,
|
|
||||||
Remark = x.Description,
|
Remark = x.Description,
|
||||||
IsPremiumPackage = PremiumPackageConst.ModeIds.Contains(x.ModelId)
|
IsPremiumPackage = PremiumPackageConst.ModeIds.Contains(x.ModelId)
|
||||||
}).ToListAsync();
|
}).ToListAsync();
|
||||||
@@ -202,7 +195,7 @@ public class AiChatService : ApplicationService
|
|||||||
[HttpPost("ai-chat/agent/send")]
|
[HttpPost("ai-chat/agent/send")]
|
||||||
public async Task PostAgentSendAsync([FromBody] AgentSendInput input, CancellationToken cancellationToken)
|
public async Task PostAgentSendAsync([FromBody] AgentSendInput input, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var tokenValidation = await _tokenManager.ValidateTokenAsync(input.Token, input.ModelId);
|
var tokenValidation = await _tokenManager.ValidateTokenAsync(input.TokenId, input.ModelId);
|
||||||
|
|
||||||
await _aiBlacklistManager.VerifiyAiBlacklist(tokenValidation.UserId);
|
await _aiBlacklistManager.VerifiyAiBlacklist(tokenValidation.UserId);
|
||||||
// 验证用户是否为VIP
|
// 验证用户是否为VIP
|
||||||
@@ -232,7 +225,7 @@ public class AiChatService : ApplicationService
|
|||||||
await _chatManager.AgentCompleteChatStreamAsync(_httpContextAccessor.HttpContext,
|
await _chatManager.AgentCompleteChatStreamAsync(_httpContextAccessor.HttpContext,
|
||||||
input.SessionId,
|
input.SessionId,
|
||||||
input.Content,
|
input.Content,
|
||||||
input.Token,
|
tokenValidation.Token,
|
||||||
tokenValidation.TokenId,
|
tokenValidation.TokenId,
|
||||||
input.ModelId,
|
input.ModelId,
|
||||||
tokenValidation.UserId,
|
tokenValidation.UserId,
|
||||||
|
|||||||
@@ -31,14 +31,14 @@ public class AiImageService : ApplicationService
|
|||||||
private readonly PremiumPackageManager _premiumPackageManager;
|
private readonly PremiumPackageManager _premiumPackageManager;
|
||||||
private readonly IGuidGenerator _guidGenerator;
|
private readonly IGuidGenerator _guidGenerator;
|
||||||
private readonly IWebHostEnvironment _webHostEnvironment;
|
private readonly IWebHostEnvironment _webHostEnvironment;
|
||||||
|
private readonly TokenManager _tokenManager;
|
||||||
public AiImageService(
|
public AiImageService(
|
||||||
ISqlSugarRepository<ImageStoreTaskAggregateRoot> imageTaskRepository,
|
ISqlSugarRepository<ImageStoreTaskAggregateRoot> imageTaskRepository,
|
||||||
IBackgroundJobManager backgroundJobManager,
|
IBackgroundJobManager backgroundJobManager,
|
||||||
AiBlacklistManager aiBlacklistManager,
|
AiBlacklistManager aiBlacklistManager,
|
||||||
PremiumPackageManager premiumPackageManager,
|
PremiumPackageManager premiumPackageManager,
|
||||||
IGuidGenerator guidGenerator,
|
IGuidGenerator guidGenerator,
|
||||||
IWebHostEnvironment webHostEnvironment)
|
IWebHostEnvironment webHostEnvironment, TokenManager tokenManager)
|
||||||
{
|
{
|
||||||
_imageTaskRepository = imageTaskRepository;
|
_imageTaskRepository = imageTaskRepository;
|
||||||
_backgroundJobManager = backgroundJobManager;
|
_backgroundJobManager = backgroundJobManager;
|
||||||
@@ -46,6 +46,7 @@ public class AiImageService : ApplicationService
|
|||||||
_premiumPackageManager = premiumPackageManager;
|
_premiumPackageManager = premiumPackageManager;
|
||||||
_guidGenerator = guidGenerator;
|
_guidGenerator = guidGenerator;
|
||||||
_webHostEnvironment = webHostEnvironment;
|
_webHostEnvironment = webHostEnvironment;
|
||||||
|
_tokenManager = tokenManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -62,6 +63,13 @@ public class AiImageService : ApplicationService
|
|||||||
// 黑名单校验
|
// 黑名单校验
|
||||||
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
|
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
|
||||||
|
|
||||||
|
//校验token
|
||||||
|
if (input.TokenId is not null)
|
||||||
|
{
|
||||||
|
await _tokenManager.ValidateTokenAsync(input.TokenId, input.ModelId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// VIP校验
|
// VIP校验
|
||||||
if (!CurrentUser.IsAiVip())
|
if (!CurrentUser.IsAiVip())
|
||||||
{
|
{
|
||||||
@@ -82,32 +90,21 @@ public class AiImageService : ApplicationService
|
|||||||
var task = new ImageStoreTaskAggregateRoot
|
var task = new ImageStoreTaskAggregateRoot
|
||||||
{
|
{
|
||||||
Prompt = input.Prompt,
|
Prompt = input.Prompt,
|
||||||
ReferenceImagesBase64 = input.ReferenceImagesBase64 ?? new List<string>(),
|
ReferenceImagesPrefixBase64 = input.ReferenceImagesPrefixBase64 ?? new List<string>(),
|
||||||
ReferenceImagesUrl = new List<string>(),
|
ReferenceImagesUrl = new List<string>(),
|
||||||
TaskStatus = TaskStatusEnum.Processing,
|
TaskStatus = TaskStatusEnum.Processing,
|
||||||
UserId = userId
|
UserId = userId,
|
||||||
|
TokenId = input.TokenId
|
||||||
};
|
};
|
||||||
|
|
||||||
await _imageTaskRepository.InsertAsync(task);
|
await _imageTaskRepository.InsertAsync(task);
|
||||||
var taskId = task.Id;
|
|
||||||
|
|
||||||
// 构建请求JSON
|
|
||||||
var requestJson = JsonSerializer.Serialize(new
|
|
||||||
{
|
|
||||||
prompt = input.Prompt,
|
|
||||||
referenceImages = input.ReferenceImagesBase64
|
|
||||||
});
|
|
||||||
|
|
||||||
// 入队后台任务
|
// 入队后台任务
|
||||||
await _backgroundJobManager.EnqueueAsync(new ImageGenerationJobArgs
|
await _backgroundJobManager.EnqueueAsync(new ImageGenerationJobArgs
|
||||||
{
|
{
|
||||||
TaskId = taskId,
|
TaskId = task.Id,
|
||||||
ModelId = input.ModelId,
|
|
||||||
RequestJson = requestJson,
|
|
||||||
UserId = userId
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return taskId;
|
return task.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -130,9 +127,9 @@ public class AiImageService : ApplicationService
|
|||||||
{
|
{
|
||||||
Id = task.Id,
|
Id = task.Id,
|
||||||
Prompt = task.Prompt,
|
Prompt = task.Prompt,
|
||||||
ReferenceImagesBase64 = task.ReferenceImagesBase64,
|
// ReferenceImagesBase64 = task.ReferenceImagesBase64,
|
||||||
ReferenceImagesUrl = task.ReferenceImagesUrl,
|
// ReferenceImagesUrl = task.ReferenceImagesUrl,
|
||||||
StoreBase64 = task.StoreBase64,
|
// StoreBase64 = task.StoreBase64,
|
||||||
StoreUrl = task.StoreUrl,
|
StoreUrl = task.StoreUrl,
|
||||||
TaskStatus = task.TaskStatus,
|
TaskStatus = task.TaskStatus,
|
||||||
CreationTime = task.CreationTime
|
CreationTime = task.CreationTime
|
||||||
@@ -234,9 +231,9 @@ public class AiImageService : ApplicationService
|
|||||||
{
|
{
|
||||||
Id = x.Id,
|
Id = x.Id,
|
||||||
Prompt = x.Prompt,
|
Prompt = x.Prompt,
|
||||||
ReferenceImagesBase64 = x.ReferenceImagesBase64,
|
// ReferenceImagesBase64 = x.ReferenceImagesBase64,
|
||||||
ReferenceImagesUrl = x.ReferenceImagesUrl,
|
// ReferenceImagesUrl = x.ReferenceImagesUrl,
|
||||||
StoreBase64 = x.StoreBase64,
|
// StoreBase64 = x.StoreBase64,
|
||||||
StoreUrl = x.StoreUrl,
|
StoreUrl = x.StoreUrl,
|
||||||
TaskStatus = x.TaskStatus,
|
TaskStatus = x.TaskStatus,
|
||||||
CreationTime = x.CreationTime
|
CreationTime = x.CreationTime
|
||||||
|
|||||||
@@ -36,10 +36,32 @@ public static class GeminiGenerateContentAcquirer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="response"></param>
|
/// <param name="response"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GetImageBase64(JsonElement response)
|
public static string GetImagePrefixBase64(JsonElement response)
|
||||||
|
{
|
||||||
|
// 获取 candidates[0].content.parts[0].text
|
||||||
|
var text = response.GetPath("candidates", 0, "content", "parts", 0, "text").GetString();
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
{
|
{
|
||||||
//todo
|
|
||||||
//获取他的base64字符串
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 解析 markdown 图片格式: 
|
||||||
|
// 提取括号内的 data:image/xxx;base64,xxx 部分
|
||||||
|
var startMarker = "(data:image/";
|
||||||
|
var startIndex = text.IndexOf(startMarker);
|
||||||
|
if (startIndex < 0)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从 "data:" 开始
|
||||||
|
startIndex += 1; // 跳过 "("
|
||||||
|
var endIndex = text.IndexOf(')', startIndex);
|
||||||
|
if (endIndex < 0)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.Substring(startIndex, endIndex - startIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
namespace Yi.Framework.AiHub.Domain.Shared.Enums;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发布状态枚举
|
||||||
|
/// </summary>
|
||||||
|
public enum PublishStatusEnum
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 未发布
|
||||||
|
/// </summary>
|
||||||
|
Unpublished = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 已发布
|
||||||
|
/// </summary>
|
||||||
|
Published = 1
|
||||||
|
}
|
||||||
@@ -14,10 +14,10 @@ public class ImageStoreTaskAggregateRoot : FullAuditedAggregateRoot<Guid>
|
|||||||
public string Prompt { get; set; }
|
public string Prompt { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 参考图Base64
|
/// 参考图PrefixBase64(带前缀,如 data:image/png;base64,xxx)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SugarColumn(IsJson = true)]
|
[SugarColumn(IsJson = true)]
|
||||||
public List<string> ReferenceImagesBase64 { get; set; }
|
public List<string> ReferenceImagesPrefixBase64 { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 参考图url
|
/// 参考图url
|
||||||
@@ -27,9 +27,9 @@ public class ImageStoreTaskAggregateRoot : FullAuditedAggregateRoot<Guid>
|
|||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 图片base64
|
/// 生成图片PrefixBase64(带前缀,如 data:image/png;base64,xxx)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? StoreBase64 { get; set; }
|
public string? StorePrefixBase64 { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 图片绝对路径
|
/// 图片绝对路径
|
||||||
@@ -46,6 +46,34 @@ public class ImageStoreTaskAggregateRoot : FullAuditedAggregateRoot<Guid>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid UserId { get; set; }
|
public Guid UserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模型id
|
||||||
|
/// </summary>
|
||||||
|
public string ModelId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 错误信息
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(ColumnDataType = StaticConfig.CodeFirst_BigString)]
|
||||||
|
public string? ErrorInfo { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 发布状态
|
||||||
|
/// </summary>
|
||||||
|
public PublishStatusEnum PublishStatus { get; set; } = PublishStatusEnum.Unpublished;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 分类标签
|
||||||
|
/// </summary>
|
||||||
|
[SugarColumn(IsJson = true)]
|
||||||
|
public List<string> Categories { get; set; } = new();
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 密钥id
|
||||||
|
/// </summary>
|
||||||
|
public Guid? TokenId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 设置成功
|
/// 设置成功
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -984,11 +984,12 @@ public class AiGateWayManager : DomainService
|
|||||||
var data = await chatService.GenerateContentAsync(modelDescribe, request, cancellationToken);
|
var data = await chatService.GenerateContentAsync(modelDescribe, request, cancellationToken);
|
||||||
|
|
||||||
//解析json,获取base64字符串
|
//解析json,获取base64字符串
|
||||||
var imageBase64 = GeminiGenerateContentAcquirer.GetImageBase64(data);
|
var imageBase64 = GeminiGenerateContentAcquirer.GetImagePrefixBase64(data);
|
||||||
|
|
||||||
//远程调用上传接口,将base64转换为URL
|
//远程调用上传接口,将base64转换为URL
|
||||||
var httpClient = LazyServiceProvider.LazyGetRequiredService<IHttpClientFactory>().CreateClient();
|
var httpClient = LazyServiceProvider.LazyGetRequiredService<IHttpClientFactory>().CreateClient();
|
||||||
var uploadUrl = $"https://ccnetcore.com/prod-api/ai-hub/ai-image/upload-base64";
|
// var uploadUrl = $"https://ccnetcore.com/prod-api/ai-hub/ai-image/upload-base64";
|
||||||
|
var uploadUrl = $"http://localhost:19001/api/app/ai-image/upload-base64";
|
||||||
var content = new StringContent(JsonSerializer.Serialize(imageBase64), Encoding.UTF8, "application/json");
|
var content = new StringContent(JsonSerializer.Serialize(imageBase64), Encoding.UTF8, "application/json");
|
||||||
var uploadResponse = await httpClient.PostAsync(uploadUrl, content, cancellationToken);
|
var uploadResponse = await httpClient.PostAsync(uploadUrl, content, cancellationToken);
|
||||||
uploadResponse.EnsureSuccessStatusCode();
|
uploadResponse.EnsureSuccessStatusCode();
|
||||||
@@ -1020,7 +1021,7 @@ public class AiGateWayManager : DomainService
|
|||||||
}
|
}
|
||||||
|
|
||||||
//设置存储base64和url
|
//设置存储base64和url
|
||||||
imageStoreTask.StoreBase64 = imageBase64;
|
imageStoreTask.StorePrefixBase64 = imageBase64;
|
||||||
imageStoreTask.SetSuccess(storeUrl);
|
imageStoreTask.SetSuccess(storeUrl);
|
||||||
await _imageStoreTaskRepository.UpdateAsync(imageStoreTask);
|
await _imageStoreTaskRepository.UpdateAsync(imageStoreTask);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ public class TokenValidationResult
|
|||||||
/// Token Id
|
/// Token Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Guid TokenId { get; set; }
|
public Guid TokenId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// token
|
||||||
|
/// </summary>
|
||||||
|
public string Token { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TokenManager : DomainService
|
public class TokenManager : DomainService
|
||||||
@@ -39,24 +44,35 @@ public class TokenManager : DomainService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证Token并返回用户Id和TokenId
|
/// 验证Token并返回用户Id和TokenId
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token">Token密钥</param>
|
/// <param name="tokenOrId">Token密钥或者TokenId</param>
|
||||||
/// <param name="modelId">模型Id(用于判断是否是尊享模型需要检查额度)</param>
|
/// <param name="modelId">模型Id(用于判断是否是尊享模型需要检查额度)</param>
|
||||||
/// <returns>Token验证结果</returns>
|
/// <returns>Token验证结果</returns>
|
||||||
public async Task<TokenValidationResult> ValidateTokenAsync(string? token, string? modelId = null)
|
public async Task<TokenValidationResult> ValidateTokenAsync(object tokenOrId, string? modelId = null)
|
||||||
{
|
{
|
||||||
if (token is null)
|
|
||||||
|
if (tokenOrId is null)
|
||||||
{
|
{
|
||||||
throw new UserFriendlyException("当前请求未包含token", "401");
|
throw new UserFriendlyException("当前请求未包含token", "401");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!token.StartsWith("yi-"))
|
TokenAggregateRoot entity;
|
||||||
|
if (tokenOrId is Guid tokenId)
|
||||||
|
{
|
||||||
|
entity = await _tokenRepository._DbQueryable
|
||||||
|
.Where(x => x.Id == tokenId)
|
||||||
|
.FirstAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var tokenStr = tokenOrId.ToString();
|
||||||
|
if (!tokenStr.StartsWith("yi-"))
|
||||||
{
|
{
|
||||||
throw new UserFriendlyException("当前请求token非法", "401");
|
throw new UserFriendlyException("当前请求token非法", "401");
|
||||||
}
|
}
|
||||||
|
entity = await _tokenRepository._DbQueryable
|
||||||
var entity = await _tokenRepository._DbQueryable
|
.Where(x => x.Token == tokenStr)
|
||||||
.Where(x => x.Token == token)
|
|
||||||
.FirstAsync();
|
.FirstAsync();
|
||||||
|
}
|
||||||
|
|
||||||
if (entity is null)
|
if (entity is null)
|
||||||
{
|
{
|
||||||
@@ -90,7 +106,8 @@ public class TokenManager : DomainService
|
|||||||
return new TokenValidationResult
|
return new TokenValidationResult
|
||||||
{
|
{
|
||||||
UserId = entity.UserId,
|
UserId = entity.UserId,
|
||||||
TokenId = entity.Id
|
TokenId = entity.Id,
|
||||||
|
Token = entity.Token
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user