2025-12-26 23:46:36 +08:00
|
|
|
|
using System.Text.Json;
|
|
|
|
|
|
using Microsoft.AspNetCore.Authorization;
|
|
|
|
|
|
using Microsoft.AspNetCore.Hosting;
|
|
|
|
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
2026-01-03 16:00:18 +08:00
|
|
|
|
using SqlSugar;
|
2025-12-26 23:46:36 +08:00
|
|
|
|
using Volo.Abp;
|
|
|
|
|
|
using Volo.Abp.Application.Services;
|
|
|
|
|
|
using Volo.Abp.BackgroundJobs;
|
|
|
|
|
|
using Volo.Abp.Guids;
|
|
|
|
|
|
using Volo.Abp.Users;
|
2026-01-03 00:00:17 +08:00
|
|
|
|
using Yi.Framework.AiHub.Application.Contracts.Dtos;
|
2025-12-26 23:46:36 +08:00
|
|
|
|
using Yi.Framework.AiHub.Application.Contracts.Dtos.Chat;
|
|
|
|
|
|
using Yi.Framework.AiHub.Application.Jobs;
|
|
|
|
|
|
using Yi.Framework.AiHub.Domain.Entities.Chat;
|
2026-01-03 00:00:17 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Entities.Model;
|
2025-12-26 23:46:36 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Extensions;
|
|
|
|
|
|
using Yi.Framework.AiHub.Domain.Managers;
|
|
|
|
|
|
using Yi.Framework.AiHub.Domain.Shared.Consts;
|
|
|
|
|
|
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
|
|
|
|
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Yi.Framework.AiHub.Application.Services.Chat;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// AI图片生成服务
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[Authorize]
|
|
|
|
|
|
public class AiImageService : ApplicationService
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly ISqlSugarRepository<ImageStoreTaskAggregateRoot> _imageTaskRepository;
|
|
|
|
|
|
private readonly IBackgroundJobManager _backgroundJobManager;
|
|
|
|
|
|
private readonly AiBlacklistManager _aiBlacklistManager;
|
|
|
|
|
|
private readonly PremiumPackageManager _premiumPackageManager;
|
2026-01-01 00:44:02 +08:00
|
|
|
|
private readonly ModelManager _modelManager;
|
2025-12-26 23:46:36 +08:00
|
|
|
|
private readonly IGuidGenerator _guidGenerator;
|
|
|
|
|
|
private readonly IWebHostEnvironment _webHostEnvironment;
|
2026-01-02 19:26:09 +08:00
|
|
|
|
private readonly TokenManager _tokenManager;
|
2026-01-03 00:00:17 +08:00
|
|
|
|
private readonly ISqlSugarRepository<AiModelEntity> _aiModelRepository;
|
2026-01-03 01:12:47 +08:00
|
|
|
|
|
2025-12-26 23:46:36 +08:00
|
|
|
|
public AiImageService(
|
|
|
|
|
|
ISqlSugarRepository<ImageStoreTaskAggregateRoot> imageTaskRepository,
|
|
|
|
|
|
IBackgroundJobManager backgroundJobManager,
|
|
|
|
|
|
AiBlacklistManager aiBlacklistManager,
|
|
|
|
|
|
PremiumPackageManager premiumPackageManager,
|
2026-01-01 00:44:02 +08:00
|
|
|
|
ModelManager modelManager,
|
2025-12-26 23:46:36 +08:00
|
|
|
|
IGuidGenerator guidGenerator,
|
2026-01-03 01:12:47 +08:00
|
|
|
|
IWebHostEnvironment webHostEnvironment, TokenManager tokenManager,
|
|
|
|
|
|
ISqlSugarRepository<AiModelEntity> aiModelRepository)
|
2025-12-26 23:46:36 +08:00
|
|
|
|
{
|
|
|
|
|
|
_imageTaskRepository = imageTaskRepository;
|
|
|
|
|
|
_backgroundJobManager = backgroundJobManager;
|
|
|
|
|
|
_aiBlacklistManager = aiBlacklistManager;
|
|
|
|
|
|
_premiumPackageManager = premiumPackageManager;
|
2026-01-01 00:44:02 +08:00
|
|
|
|
_modelManager = modelManager;
|
2025-12-26 23:46:36 +08:00
|
|
|
|
_guidGenerator = guidGenerator;
|
|
|
|
|
|
_webHostEnvironment = webHostEnvironment;
|
2026-01-02 19:26:09 +08:00
|
|
|
|
_tokenManager = tokenManager;
|
2026-01-03 00:00:17 +08:00
|
|
|
|
_aiModelRepository = aiModelRepository;
|
2025-12-26 23:46:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 生成图片(异步任务)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="input">图片生成输入参数</param>
|
|
|
|
|
|
/// <returns>任务ID</returns>
|
|
|
|
|
|
[HttpPost("ai-image/generate")]
|
|
|
|
|
|
[Authorize]
|
|
|
|
|
|
public async Task<Guid> GenerateAsync([FromBody] ImageGenerationInput input)
|
|
|
|
|
|
{
|
|
|
|
|
|
var userId = CurrentUser.GetId();
|
2026-01-03 01:12:47 +08:00
|
|
|
|
|
2025-12-26 23:46:36 +08:00
|
|
|
|
// 黑名单校验
|
|
|
|
|
|
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
|
|
|
|
|
|
|
2026-01-02 19:26:09 +08:00
|
|
|
|
//校验token
|
|
|
|
|
|
if (input.TokenId is not null)
|
|
|
|
|
|
{
|
|
|
|
|
|
await _tokenManager.ValidateTokenAsync(input.TokenId, input.ModelId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-03 01:12:47 +08:00
|
|
|
|
|
2025-12-26 23:46:36 +08:00
|
|
|
|
// VIP校验
|
|
|
|
|
|
if (!CurrentUser.IsAiVip())
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("图片生成功能需要VIP用户才能使用,请购买VIP后重新登录重试");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-01 00:44:02 +08:00
|
|
|
|
// 尊享包校验 - 使用ModelManager统一判断
|
|
|
|
|
|
var isPremium = await _modelManager.IsPremiumModelAsync(input.ModelId);
|
|
|
|
|
|
if (isPremium)
|
2025-12-26 23:46:36 +08:00
|
|
|
|
{
|
|
|
|
|
|
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(userId);
|
|
|
|
|
|
if (availableTokens <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("尊享token包用量不足,请先购买尊享token包");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建任务实体
|
|
|
|
|
|
var task = new ImageStoreTaskAggregateRoot
|
|
|
|
|
|
{
|
|
|
|
|
|
Prompt = input.Prompt,
|
2026-01-02 19:26:09 +08:00
|
|
|
|
ReferenceImagesPrefixBase64 = input.ReferenceImagesPrefixBase64 ?? new List<string>(),
|
2025-12-26 23:46:36 +08:00
|
|
|
|
ReferenceImagesUrl = new List<string>(),
|
|
|
|
|
|
TaskStatus = TaskStatusEnum.Processing,
|
2026-01-02 19:26:09 +08:00
|
|
|
|
UserId = userId,
|
2026-01-03 16:00:18 +08:00
|
|
|
|
UserName = CurrentUser.UserName,
|
2026-01-02 21:32:48 +08:00
|
|
|
|
TokenId = input.TokenId,
|
|
|
|
|
|
ModelId = input.ModelId
|
2025-12-26 23:46:36 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
await _imageTaskRepository.InsertAsync(task);
|
|
|
|
|
|
// 入队后台任务
|
|
|
|
|
|
await _backgroundJobManager.EnqueueAsync(new ImageGenerationJobArgs
|
|
|
|
|
|
{
|
2026-01-02 19:26:09 +08:00
|
|
|
|
TaskId = task.Id,
|
2025-12-26 23:46:36 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-01-02 19:26:09 +08:00
|
|
|
|
return task.Id;
|
2025-12-26 23:46:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 查询任务状态
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="taskId">任务ID</param>
|
|
|
|
|
|
/// <returns>任务详情</returns>
|
|
|
|
|
|
[HttpGet("ai-image/task/{taskId}")]
|
|
|
|
|
|
public async Task<ImageTaskOutput> GetTaskAsync([FromRoute] Guid taskId)
|
|
|
|
|
|
{
|
|
|
|
|
|
var userId = CurrentUser.GetId();
|
|
|
|
|
|
|
|
|
|
|
|
var task = await _imageTaskRepository.GetFirstAsync(x => x.Id == taskId && x.UserId == userId);
|
|
|
|
|
|
if (task == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("任务不存在或无权访问");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return new ImageTaskOutput
|
|
|
|
|
|
{
|
|
|
|
|
|
Id = task.Id,
|
|
|
|
|
|
Prompt = task.Prompt,
|
2026-01-02 19:26:09 +08:00
|
|
|
|
// ReferenceImagesBase64 = task.ReferenceImagesBase64,
|
|
|
|
|
|
// ReferenceImagesUrl = task.ReferenceImagesUrl,
|
|
|
|
|
|
// StoreBase64 = task.StoreBase64,
|
2025-12-26 23:46:36 +08:00
|
|
|
|
StoreUrl = task.StoreUrl,
|
|
|
|
|
|
TaskStatus = task.TaskStatus,
|
2026-01-03 14:03:24 +08:00
|
|
|
|
PublishStatus = task.PublishStatus,
|
|
|
|
|
|
Categories = task.Categories,
|
|
|
|
|
|
CreationTime = task.CreationTime,
|
|
|
|
|
|
ErrorInfo = task.ErrorInfo,
|
2025-12-26 23:46:36 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 上传Base64图片转换为URL
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="base64Data">Base64图片数据(包含前缀如 data:image/png;base64,)</param>
|
|
|
|
|
|
/// <returns>图片访问URL</returns>
|
|
|
|
|
|
[HttpPost("ai-image/upload-base64")]
|
2026-01-02 21:32:48 +08:00
|
|
|
|
[AllowAnonymous]
|
2025-12-26 23:46:36 +08:00
|
|
|
|
public async Task<string> UploadBase64ToUrlAsync([FromBody] string base64Data)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(base64Data))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("Base64数据不能为空");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析Base64数据
|
|
|
|
|
|
string mimeType = "image/png";
|
|
|
|
|
|
string base64Content = base64Data;
|
|
|
|
|
|
|
|
|
|
|
|
if (base64Data.Contains(","))
|
|
|
|
|
|
{
|
|
|
|
|
|
var parts = base64Data.Split(',');
|
|
|
|
|
|
if (parts.Length == 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 提取MIME类型
|
|
|
|
|
|
var header = parts[0];
|
|
|
|
|
|
if (header.Contains(":") && header.Contains(";"))
|
|
|
|
|
|
{
|
|
|
|
|
|
mimeType = header.Split(':')[1].Split(';')[0];
|
|
|
|
|
|
}
|
2026-01-03 01:12:47 +08:00
|
|
|
|
|
2025-12-26 23:46:36 +08:00
|
|
|
|
base64Content = parts[1];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取文件扩展名
|
|
|
|
|
|
var extension = mimeType switch
|
|
|
|
|
|
{
|
|
|
|
|
|
"image/png" => ".png",
|
|
|
|
|
|
"image/jpeg" => ".jpg",
|
|
|
|
|
|
"image/jpg" => ".jpg",
|
|
|
|
|
|
"image/gif" => ".gif",
|
|
|
|
|
|
"image/webp" => ".webp",
|
|
|
|
|
|
_ => ".png"
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 解码Base64
|
|
|
|
|
|
byte[] imageBytes;
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
imageBytes = Convert.FromBase64String(base64Content);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (FormatException)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("Base64格式无效");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-02 21:32:48 +08:00
|
|
|
|
// ==============================
|
|
|
|
|
|
// ✅ 按日期创建目录(yyyyMMdd)
|
|
|
|
|
|
// ==============================
|
|
|
|
|
|
var dateFolder = DateTime.Now.ToString("yyyyMMdd");
|
|
|
|
|
|
var uploadPath = Path.Combine(
|
|
|
|
|
|
_webHostEnvironment.ContentRootPath,
|
|
|
|
|
|
"wwwroot",
|
|
|
|
|
|
"ai-images",
|
|
|
|
|
|
dateFolder
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2025-12-26 23:46:36 +08:00
|
|
|
|
if (!Directory.Exists(uploadPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
Directory.CreateDirectory(uploadPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-02 21:32:48 +08:00
|
|
|
|
// 保存文件
|
2025-12-26 23:46:36 +08:00
|
|
|
|
var fileId = _guidGenerator.Create();
|
|
|
|
|
|
var fileName = $"{fileId}{extension}";
|
|
|
|
|
|
var filePath = Path.Combine(uploadPath, fileName);
|
|
|
|
|
|
|
|
|
|
|
|
await File.WriteAllBytesAsync(filePath, imageBytes);
|
|
|
|
|
|
|
2026-01-02 21:32:48 +08:00
|
|
|
|
// 返回包含日期目录的访问URL
|
|
|
|
|
|
return $"/wwwroot/ai-images/{dateFolder}/{fileName}";
|
2025-12-26 23:46:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-01-03 00:00:17 +08:00
|
|
|
|
/// 分页查询我的任务列表
|
2025-12-26 23:46:36 +08:00
|
|
|
|
/// </summary>
|
2026-01-03 00:00:17 +08:00
|
|
|
|
[HttpGet("ai-image/my-tasks")]
|
2026-01-03 16:00:18 +08:00
|
|
|
|
public async Task<PagedResult<ImageTaskOutput>> GetMyTaskPageAsync([FromQuery] ImageMyTaskPageInput input)
|
2025-12-26 23:46:36 +08:00
|
|
|
|
{
|
|
|
|
|
|
var userId = CurrentUser.GetId();
|
|
|
|
|
|
|
2026-01-03 16:00:18 +08:00
|
|
|
|
RefAsync<int> total = 0;
|
|
|
|
|
|
var output = await _imageTaskRepository._DbQueryable
|
2025-12-26 23:46:36 +08:00
|
|
|
|
.Where(x => x.UserId == userId)
|
2026-01-03 16:00:18 +08:00
|
|
|
|
.WhereIF(input.TaskStatus is not null, x => x.TaskStatus == input.TaskStatus)
|
|
|
|
|
|
.WhereIF(!string.IsNullOrWhiteSpace(input.Prompt), x => x.Prompt.Contains(input.Prompt))
|
|
|
|
|
|
.WhereIF(input.PublishStatus is not null, x => x.PublishStatus == input.PublishStatus)
|
|
|
|
|
|
.WhereIF(input.StartTime is not null && input.EndTime is not null,
|
|
|
|
|
|
x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
|
|
|
|
|
|
.OrderByDescending(x => x.CreationTime)
|
2025-12-26 23:46:36 +08:00
|
|
|
|
.Select(x => new ImageTaskOutput
|
|
|
|
|
|
{
|
|
|
|
|
|
Id = x.Id,
|
|
|
|
|
|
Prompt = x.Prompt,
|
|
|
|
|
|
StoreUrl = x.StoreUrl,
|
|
|
|
|
|
TaskStatus = x.TaskStatus,
|
2026-01-03 01:12:47 +08:00
|
|
|
|
PublishStatus = x.PublishStatus,
|
|
|
|
|
|
Categories = x.Categories,
|
|
|
|
|
|
CreationTime = x.CreationTime,
|
2026-01-03 22:09:30 +08:00
|
|
|
|
ErrorInfo = x.ErrorInfo,
|
|
|
|
|
|
UserName = x.UserName,
|
|
|
|
|
|
UserId = x.UserId,
|
2026-01-04 12:32:31 +08:00
|
|
|
|
IsAnonymous = x.IsAnonymous
|
2025-12-26 23:46:36 +08:00
|
|
|
|
})
|
2026-01-03 16:00:18 +08:00
|
|
|
|
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
|
|
|
|
|
|
2025-12-26 23:46:36 +08:00
|
|
|
|
|
2026-01-03 16:00:18 +08:00
|
|
|
|
return new PagedResult<ImageTaskOutput>(total, output);
|
2025-12-26 23:46:36 +08:00
|
|
|
|
}
|
2026-01-03 00:00:17 +08:00
|
|
|
|
|
2026-01-04 12:32:31 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 删除个人图片
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="ids"></param>
|
|
|
|
|
|
[HttpDelete("ai-image/my-tasks")]
|
2026-01-04 22:47:53 +08:00
|
|
|
|
public async Task DeleteMyTaskAsync([FromQuery] List<Guid> ids)
|
2026-01-04 12:32:31 +08:00
|
|
|
|
{
|
|
|
|
|
|
var userId = CurrentUser.GetId();
|
|
|
|
|
|
await _imageTaskRepository.DeleteAsync(x => ids.Contains(x.Id) && x.UserId == userId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-03 00:00:17 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 分页查询图片广场(已发布的图片)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[HttpGet("ai-image/plaza")]
|
|
|
|
|
|
[AllowAnonymous]
|
2026-01-03 16:00:18 +08:00
|
|
|
|
public async Task<PagedResult<ImageTaskOutput>> GetPlazaPageAsync([FromQuery] ImagePlazaPageInput input)
|
2026-01-03 00:00:17 +08:00
|
|
|
|
{
|
2026-01-03 16:00:18 +08:00
|
|
|
|
RefAsync<int> total = 0;
|
|
|
|
|
|
var output = await _imageTaskRepository._DbQueryable
|
2026-01-03 00:00:17 +08:00
|
|
|
|
.Where(x => x.PublishStatus == PublishStatusEnum.Published)
|
|
|
|
|
|
.Where(x => x.TaskStatus == TaskStatusEnum.Success)
|
2026-01-03 16:00:18 +08:00
|
|
|
|
.WhereIF(input.TaskStatus is not null, x => x.TaskStatus == input.TaskStatus)
|
|
|
|
|
|
.WhereIF(!string.IsNullOrWhiteSpace(input.Prompt), x => x.Prompt.Contains(input.Prompt))
|
2026-01-04 12:32:31 +08:00
|
|
|
|
.WhereIF(!string.IsNullOrWhiteSpace(input.Categories),
|
|
|
|
|
|
x => SqlFunc.JsonLike(x.Categories, input.Categories))
|
|
|
|
|
|
.WhereIF(!string.IsNullOrWhiteSpace(input.UserName), x => x.UserName.Contains(input.UserName))
|
2026-01-03 16:00:18 +08:00
|
|
|
|
.WhereIF(input.StartTime is not null && input.EndTime is not null,
|
|
|
|
|
|
x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
|
|
|
|
|
|
.OrderByDescending(x => x.CreationTime)
|
2026-01-03 00:00:17 +08:00
|
|
|
|
.Select(x => new ImageTaskOutput
|
|
|
|
|
|
{
|
|
|
|
|
|
Id = x.Id,
|
|
|
|
|
|
Prompt = x.Prompt,
|
2026-01-03 16:17:57 +08:00
|
|
|
|
IsAnonymous = x.IsAnonymous,
|
2026-01-03 00:00:17 +08:00
|
|
|
|
StoreUrl = x.StoreUrl,
|
|
|
|
|
|
TaskStatus = x.TaskStatus,
|
|
|
|
|
|
PublishStatus = x.PublishStatus,
|
|
|
|
|
|
Categories = x.Categories,
|
2026-01-03 16:00:18 +08:00
|
|
|
|
CreationTime = x.CreationTime,
|
2026-01-03 16:17:57 +08:00
|
|
|
|
ErrorInfo = null,
|
2026-01-03 16:00:18 +08:00
|
|
|
|
UserName = x.UserName,
|
|
|
|
|
|
UserId = x.UserId,
|
2026-01-03 00:00:17 +08:00
|
|
|
|
})
|
2026-01-04 12:32:31 +08:00
|
|
|
|
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
|
|
|
|
|
;
|
2026-01-03 16:00:18 +08:00
|
|
|
|
|
2026-01-03 00:00:17 +08:00
|
|
|
|
|
2026-01-03 16:17:57 +08:00
|
|
|
|
output.ForEach(x =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (x.IsAnonymous)
|
|
|
|
|
|
{
|
|
|
|
|
|
x.UserName = null;
|
|
|
|
|
|
x.UserId = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2026-01-04 12:32:31 +08:00
|
|
|
|
|
2026-01-03 16:00:18 +08:00
|
|
|
|
return new PagedResult<ImageTaskOutput>(total, output);
|
2026-01-03 00:00:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 发布图片到广场
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[HttpPost("ai-image/publish")]
|
|
|
|
|
|
public async Task PublishAsync([FromBody] PublishImageInput input)
|
|
|
|
|
|
{
|
|
|
|
|
|
var userId = CurrentUser.GetId();
|
|
|
|
|
|
|
|
|
|
|
|
var task = await _imageTaskRepository.GetFirstAsync(x => x.Id == input.TaskId && x.UserId == userId);
|
|
|
|
|
|
if (task == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("任务不存在或无权访问");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (task.TaskStatus != TaskStatusEnum.Success)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("只有已完成的任务才能发布");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (task.PublishStatus == PublishStatusEnum.Published)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("该任务已发布");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-03 16:17:57 +08:00
|
|
|
|
//设置发布
|
2026-01-04 12:32:31 +08:00
|
|
|
|
task.SetPublish(input.IsAnonymous, input.Categories);
|
2026-01-03 00:00:17 +08:00
|
|
|
|
await _imageTaskRepository.UpdateAsync(task);
|
|
|
|
|
|
}
|
2026-01-03 01:12:47 +08:00
|
|
|
|
|
2026-01-03 00:00:17 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取图片模型列表
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
[HttpPost("ai-image/model")]
|
2026-01-03 01:45:27 +08:00
|
|
|
|
[AllowAnonymous]
|
2026-01-03 00:00:17 +08:00
|
|
|
|
public async Task<List<ModelGetListOutput>> GetModelAsync()
|
|
|
|
|
|
{
|
|
|
|
|
|
var output = await _aiModelRepository._DbQueryable
|
2026-01-05 14:15:21 +08:00
|
|
|
|
.Where(x=>x.IsEnabled==true)
|
2026-01-03 00:00:17 +08:00
|
|
|
|
.Where(x => x.ModelType == ModelTypeEnum.Image)
|
2026-01-03 01:45:27 +08:00
|
|
|
|
.Where(x => x.ModelApiType == ModelApiTypeEnum.GenerateContent)
|
2026-01-03 00:00:17 +08:00
|
|
|
|
.OrderByDescending(x => x.OrderNum)
|
|
|
|
|
|
.Select(x => new ModelGetListOutput
|
|
|
|
|
|
{
|
|
|
|
|
|
Id = x.Id,
|
|
|
|
|
|
ModelId = x.ModelId,
|
|
|
|
|
|
ModelName = x.Name,
|
|
|
|
|
|
ModelDescribe = x.Description,
|
|
|
|
|
|
Remark = x.Description,
|
2026-01-03 01:46:40 +08:00
|
|
|
|
IsPremiumPackage = x.IsPremium
|
2026-01-03 00:00:17 +08:00
|
|
|
|
}).ToListAsync();
|
|
|
|
|
|
return output;
|
|
|
|
|
|
}
|
2025-12-26 23:46:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 分页结果
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T">数据类型</typeparam>
|
|
|
|
|
|
public class PagedResult<T>
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 总数
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public long Total { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 数据列表
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public List<T> Items { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public PagedResult(long total, List<T> items)
|
|
|
|
|
|
{
|
|
|
|
|
|
Total = total;
|
|
|
|
|
|
Items = items;
|
|
|
|
|
|
}
|
2026-01-03 01:12:47 +08:00
|
|
|
|
}
|