Files
Yi.Admin/Yi.Abp.Net8/module/ai-hub/Yi.Framework.AiHub.Application/Services/OpenApiService.cs

223 lines
8.4 KiB
C#
Raw Normal View History

2025-07-17 23:10:26 +08:00
using Microsoft.AspNetCore.Http;
2025-07-02 23:30:29 +08:00
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Volo.Abp.Application.Services;
using Volo.Abp.Users;
using Yi.Framework.AiHub.Domain.Entities;
2025-07-05 15:11:56 +08:00
using Yi.Framework.AiHub.Domain.Entities.Model;
2025-07-17 23:10:26 +08:00
using Yi.Framework.AiHub.Domain.Extensions;
2025-07-02 23:30:29 +08:00
using Yi.Framework.AiHub.Domain.Managers;
using Yi.Framework.AiHub.Domain.Shared.Consts;
2025-10-11 15:25:43 +08:00
using Yi.Framework.AiHub.Domain.Shared.Dtos.Anthropic;
2025-08-11 15:31:11 +08:00
using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi;
using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi.Embeddings;
using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi.Images;
2025-08-03 23:23:32 +08:00
using Yi.Framework.AiHub.Domain.Shared.Enums;
using Yi.Framework.Rbac.Application.Contracts.IServices;
2025-07-03 22:31:39 +08:00
using Yi.Framework.SqlSugarCore.Abstractions;
2025-07-02 23:30:29 +08:00
namespace Yi.Framework.AiHub.Application.Services;
public class OpenApiService : ApplicationService
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ILogger<OpenApiService> _logger;
2025-07-03 22:31:39 +08:00
private readonly TokenManager _tokenManager;
2025-07-05 15:11:56 +08:00
private readonly AiGateWayManager _aiGateWayManager;
private readonly ISqlSugarRepository<AiModelEntity> _aiModelRepository;
2025-08-03 23:23:32 +08:00
private readonly AiBlacklistManager _aiBlacklistManager;
private readonly IAccountService _accountService;
private readonly PremiumPackageManager _premiumPackageManager;
2025-07-03 22:31:39 +08:00
public OpenApiService(IHttpContextAccessor httpContextAccessor, ILogger<OpenApiService> logger,
2025-07-05 15:11:56 +08:00
TokenManager tokenManager, AiGateWayManager aiGateWayManager,
ISqlSugarRepository<AiModelEntity> aiModelRepository, AiBlacklistManager aiBlacklistManager,
IAccountService accountService, PremiumPackageManager premiumPackageManager)
2025-07-02 23:30:29 +08:00
{
_httpContextAccessor = httpContextAccessor;
_logger = logger;
2025-07-03 22:31:39 +08:00
_tokenManager = tokenManager;
2025-07-05 15:11:56 +08:00
_aiGateWayManager = aiGateWayManager;
_aiModelRepository = aiModelRepository;
2025-08-03 23:23:32 +08:00
_aiBlacklistManager = aiBlacklistManager;
_accountService = accountService;
_premiumPackageManager = premiumPackageManager;
2025-07-02 23:30:29 +08:00
}
2025-07-03 22:31:39 +08:00
/// <summary>
/// 对话
/// </summary>
/// <param name="input"></param>
/// <param name="cancellationToken"></param>
2025-07-03 22:44:52 +08:00
[HttpPost("openApi/v1/chat/completions")]
2025-07-17 23:10:26 +08:00
public async Task ChatCompletionsAsync([FromBody] ThorChatCompletionsRequest input,
CancellationToken cancellationToken)
2025-07-02 23:30:29 +08:00
{
//前面都是校验,后面才是真正的调用
var httpContext = this._httpContextAccessor.HttpContext;
2025-07-03 22:31:39 +08:00
var userId = await _tokenManager.GetUserIdAsync(GetTokenByHttpContext(httpContext));
2025-08-03 23:23:32 +08:00
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
//如果是尊享包服务,需要校验是是否尊享包足够
if (PremiumPackageConst.ModeIds.Contains(input.Model))
{
// 检查尊享token包用量
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(userId);
if (availableTokens <= 0)
{
throw new UserFriendlyException("尊享token包用量不足请先购买尊享token包");
}
}
2025-07-17 23:10:26 +08:00
//ai网关代理httpcontext
2025-07-09 22:44:24 +08:00
if (input.Stream == true)
2025-07-09 19:12:53 +08:00
{
2025-07-17 23:10:26 +08:00
await _aiGateWayManager.CompleteChatStreamForStatisticsAsync(_httpContextAccessor.HttpContext, input,
2025-07-09 19:12:53 +08:00
userId, null, cancellationToken);
}
else
{
2025-07-17 23:10:26 +08:00
await _aiGateWayManager.CompleteChatForStatisticsAsync(_httpContextAccessor.HttpContext, input, userId,
null,
2025-07-09 21:52:00 +08:00
cancellationToken);
2025-07-09 19:12:53 +08:00
}
2025-07-02 23:30:29 +08:00
}
2025-08-03 23:23:32 +08:00
/// <summary>
/// 图片生成
/// </summary>
/// <param name="input"></param>
/// <param name="cancellationToken"></param>
[HttpPost("openApi/v1/images/generations")]
public async Task ImagesGenerationsAsync([FromBody] ImageCreateRequest input, CancellationToken cancellationToken)
{
var httpContext = this._httpContextAccessor.HttpContext;
Intercept(httpContext);
2025-08-03 23:23:32 +08:00
var userId = await _tokenManager.GetUserIdAsync(GetTokenByHttpContext(httpContext));
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
await _aiGateWayManager.CreateImageForStatisticsAsync(httpContext, userId, null, input);
}
/// <summary>
/// 向量生成
/// </summary>
/// <param name="input"></param>
/// <param name="cancellationToken"></param>
[HttpPost("openApi/v1/embeddings")]
public async Task EmbeddingAsync([FromBody] ThorEmbeddingInput input, CancellationToken cancellationToken)
{
var httpContext = this._httpContextAccessor.HttpContext;
Intercept(httpContext);
var userId = await _tokenManager.GetUserIdAsync(GetTokenByHttpContext(httpContext));
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
await _aiGateWayManager.EmbeddingForStatisticsAsync(httpContext, userId, null, input);
}
2025-08-03 23:23:32 +08:00
2025-07-04 00:16:58 +08:00
/// <summary>
/// 获取模型列表
/// </summary>
/// <returns></returns>
[HttpGet("openApi/v1/models")]
2025-07-17 23:10:26 +08:00
public async Task<ModelsListDto> ModelsAsync()
2025-07-04 00:16:58 +08:00
{
2025-07-05 15:11:56 +08:00
var data = await _aiModelRepository._DbQueryable
2025-08-03 23:23:32 +08:00
.Where(x => x.ModelType == ModelTypeEnum.Chat)
2025-07-05 15:11:56 +08:00
.OrderByDescending(x => x.OrderNum)
2025-07-17 23:10:26 +08:00
.Select(x => new ModelsDataDto
2025-07-04 00:16:58 +08:00
{
2025-07-17 23:10:26 +08:00
Id = x.ModelId,
@object = "model",
Created = DateTime.Now.ToUnixTimeSeconds(),
OwnedBy = "organization-owner",
Type = x.ModelId
2025-07-05 15:11:56 +08:00
}).ToListAsync();
2025-07-09 19:12:53 +08:00
2025-07-17 23:10:26 +08:00
return new ModelsListDto()
2025-07-02 23:30:29 +08:00
{
2025-07-05 15:11:56 +08:00
Data = data
2025-07-02 23:30:29 +08:00
};
}
2025-07-03 22:31:39 +08:00
2025-10-11 15:25:43 +08:00
/// <summary>
/// Anthropic对话尊享服务专用
2025-10-11 15:25:43 +08:00
/// </summary>
/// <param name="input"></param>
/// <param name="cancellationToken"></param>
[HttpPost("openApi/v1/messages")]
public async Task MessagesAsync([FromBody] AnthropicInput input,
CancellationToken cancellationToken)
{
//前面都是校验,后面才是真正的调用
var httpContext = this._httpContextAccessor.HttpContext;
var userId = await _tokenManager.GetUserIdAsync(GetTokenByHttpContext(httpContext));
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
// 验证用户是否为VIP
var userInfo = await _accountService.GetAsync(null, null, userId);
if (userInfo == null)
{
throw new UserFriendlyException("用户信息不存在");
}
// 检查是否为VIP使用RoleCodes判断
if (!userInfo.RoleCodes.Contains(AiHubConst.VipRole) && userInfo.User.UserName != "cc")
{
throw new UserFriendlyException("该接口为尊享服务专用需要VIP权限才能使用");
}
// 检查尊享token包用量
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(userId);
if (availableTokens <= 0)
{
throw new UserFriendlyException("尊享token包用量不足请先购买尊享token包");
}
2025-10-11 15:25:43 +08:00
//ai网关代理httpcontext
if (input.Stream)
{
await _aiGateWayManager.AnthropicCompleteChatStreamForStatisticsAsync(_httpContextAccessor.HttpContext, input,
userId, null, cancellationToken);
}
else
{
await _aiGateWayManager.AnthropicCompleteChatForStatisticsAsync(_httpContextAccessor.HttpContext, input, userId,
null,
cancellationToken);
}
}
#region
2025-07-03 22:31:39 +08:00
private string? GetTokenByHttpContext(HttpContext httpContext)
{
// 优先从 x-api-key 获取
string apiKeyHeader = httpContext.Request.Headers["x-api-key"];
if (!string.IsNullOrWhiteSpace(apiKeyHeader))
{
return apiKeyHeader.Trim();
}
2025-07-03 22:31:39 +08:00
// 再检查 Authorization 头
string authHeader = httpContext.Request.Headers["Authorization"];
if (!string.IsNullOrWhiteSpace(authHeader) && authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
2025-07-03 22:31:39 +08:00
{
return authHeader.Substring("Bearer ".Length).Trim();
}
return null;
}
private void Intercept(HttpContext httpContext)
{
if (httpContext.Request.Host.Value == "yxai.chat")
{
throw new UserFriendlyException("当前海外站点不支持大流量接口请使用转发站点https://ai.ccnetcore.com");
}
}
2025-10-11 15:25:43 +08:00
#endregion
2025-07-02 23:30:29 +08:00
}