using System.Text.Json; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Volo.Abp.Application.Services; using Volo.Abp.Users; using Yi.Framework.AiHub.Domain.Entities; using Yi.Framework.AiHub.Domain.Entities.Chat; using Yi.Framework.AiHub.Domain.Entities.Model; 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.Dtos.Anthropic; 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; using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi.Responses; using Yi.Framework.AiHub.Domain.Shared.Enums; using Yi.Framework.Rbac.Application.Contracts.IServices; using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.AiHub.Application.Services; public class OpenApiService : ApplicationService { private readonly IHttpContextAccessor _httpContextAccessor; private readonly ILogger _logger; private readonly TokenManager _tokenManager; private readonly AiGateWayManager _aiGateWayManager; private readonly ISqlSugarRepository _aiModelRepository; private readonly AiBlacklistManager _aiBlacklistManager; private readonly IAccountService _accountService; private readonly PremiumPackageManager _premiumPackageManager; private readonly ISqlSugarRepository _imageStoreRepository; public OpenApiService(IHttpContextAccessor httpContextAccessor, ILogger logger, TokenManager tokenManager, AiGateWayManager aiGateWayManager, ISqlSugarRepository aiModelRepository, AiBlacklistManager aiBlacklistManager, IAccountService accountService, PremiumPackageManager premiumPackageManager, ISqlSugarRepository imageStoreRepository) { _httpContextAccessor = httpContextAccessor; _logger = logger; _tokenManager = tokenManager; _aiGateWayManager = aiGateWayManager; _aiModelRepository = aiModelRepository; _aiBlacklistManager = aiBlacklistManager; _accountService = accountService; _premiumPackageManager = premiumPackageManager; _imageStoreRepository = imageStoreRepository; } /// /// 对话 /// /// /// [HttpPost("openApi/v1/chat/completions")] public async Task ChatCompletionsAsync([FromBody] ThorChatCompletionsRequest input, CancellationToken cancellationToken) { //前面都是校验,后面才是真正的调用 var httpContext = this._httpContextAccessor.HttpContext; var tokenValidation = await _tokenManager.ValidateTokenAsync(GetTokenByHttpContext(httpContext), input.Model); var userId = tokenValidation.UserId; var tokenId = tokenValidation.TokenId; await _aiBlacklistManager.VerifiyAiBlacklist(userId); //如果是尊享包服务,需要校验是是否尊享包足够 var isPremium = await _aiModelRepository._DbQueryable .Where(x => x.ModelId == input.Model) .Select(x => x.IsPremium) .FirstAsync(); if (isPremium) { // 检查尊享token包用量 var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(userId); if (availableTokens <= 0) { throw new UserFriendlyException("尊享token包用量不足,请先购买尊享token包"); } } //ai网关代理httpcontext if (input.Stream == true) { await _aiGateWayManager.CompleteChatStreamForStatisticsAsync(_httpContextAccessor.HttpContext, input, userId, null, tokenId, cancellationToken); } else { await _aiGateWayManager.CompleteChatForStatisticsAsync(_httpContextAccessor.HttpContext, input, userId, null, tokenId, cancellationToken); } } /// /// 图片生成 /// /// /// [HttpPost("openApi/v1/images/generations")] public async Task ImagesGenerationsAsync([FromBody] ImageCreateRequest input, CancellationToken cancellationToken) { var httpContext = this._httpContextAccessor.HttpContext; Intercept(httpContext); var tokenValidation = await _tokenManager.ValidateTokenAsync(GetTokenByHttpContext(httpContext), input.Model); var userId = tokenValidation.UserId; var tokenId = tokenValidation.TokenId; await _aiBlacklistManager.VerifiyAiBlacklist(userId); await _aiGateWayManager.CreateImageForStatisticsAsync(httpContext, userId, null, input, tokenId); } /// /// 向量生成 /// /// /// [HttpPost("openApi/v1/embeddings")] public async Task EmbeddingAsync([FromBody] ThorEmbeddingInput input, CancellationToken cancellationToken) { var httpContext = this._httpContextAccessor.HttpContext; Intercept(httpContext); var tokenValidation = await _tokenManager.ValidateTokenAsync(GetTokenByHttpContext(httpContext), input.Model); var userId = tokenValidation.UserId; var tokenId = tokenValidation.TokenId; await _aiBlacklistManager.VerifiyAiBlacklist(userId); await _aiGateWayManager.EmbeddingForStatisticsAsync(httpContext, userId, null, input, tokenId); } /// /// 获取模型列表 /// /// [HttpGet("openApi/v1/models")] public async Task ModelsAsync() { var data = await _aiModelRepository._DbQueryable .Where(x => x.ModelType == ModelTypeEnum.Chat) .OrderByDescending(x => x.OrderNum) .Select(x => new ModelsDataDto { Id = x.ModelId, @object = "model", Created = DateTime.Now.ToUnixTimeSeconds(), OwnedBy = "organization-owner", Type = x.ModelId }).ToListAsync(); return new ModelsListDto() { Data = data }; } /// /// Anthropic对话(尊享服务专用) /// /// /// [HttpPost("openApi/v1/messages")] public async Task MessagesAsync([FromBody] AnthropicInput input, CancellationToken cancellationToken) { //前面都是校验,后面才是真正的调用 var httpContext = this._httpContextAccessor.HttpContext; var tokenValidation = await _tokenManager.ValidateTokenAsync(GetTokenByHttpContext(httpContext), input.Model); var userId = tokenValidation.UserId; var tokenId = tokenValidation.TokenId; 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包"); } //ai网关代理httpcontext if (input.Stream) { await _aiGateWayManager.AnthropicCompleteChatStreamForStatisticsAsync(_httpContextAccessor.HttpContext, input, userId, null, tokenId, cancellationToken); } else { await _aiGateWayManager.AnthropicCompleteChatForStatisticsAsync(_httpContextAccessor.HttpContext, input, userId, null, tokenId, cancellationToken); } } /// /// 响应-Openai新规范 (尊享服务专用) /// /// /// [HttpPost("openApi/v1/responses")] public async Task ResponsesAsync([FromBody] OpenAiResponsesInput input, CancellationToken cancellationToken) { //前面都是校验,后面才是真正的调用 var httpContext = this._httpContextAccessor.HttpContext; var tokenValidation = await _tokenManager.ValidateTokenAsync(GetTokenByHttpContext(httpContext), input.Model); var userId = tokenValidation.UserId; var tokenId = tokenValidation.TokenId; 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包"); } //ai网关代理httpcontext if (input.Stream == true) { await _aiGateWayManager.OpenAiResponsesStreamForStatisticsAsync(_httpContextAccessor.HttpContext, input, userId, null, tokenId, cancellationToken); } else { await _aiGateWayManager.OpenAiResponsesAsyncForStatisticsAsync(_httpContextAccessor.HttpContext, input, userId, null, tokenId, cancellationToken); } } /// /// 生成-Gemini (尊享服务专用) /// /// /// /// /// [HttpPost("openApi/v1beta/models/{modelId}:{action:regex(^(generateContent|streamGenerateContent)$)}")] public async Task GenerateContentAsync([FromBody] JsonElement input, [FromRoute] string modelId, [FromQuery] string? alt, CancellationToken cancellationToken) { //前面都是校验,后面才是真正的调用 var httpContext = this._httpContextAccessor.HttpContext; var tokenValidation = await _tokenManager.ValidateTokenAsync(GetTokenByHttpContext(httpContext), modelId); var userId = tokenValidation.UserId; var tokenId = tokenValidation.TokenId; 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包"); } //ai网关代理httpcontext if (alt == "sse") { await _aiGateWayManager.GeminiGenerateContentStreamForStatisticsAsync(_httpContextAccessor.HttpContext, modelId, input, userId, null, tokenId, cancellationToken); } else { await _aiGateWayManager.GeminiGenerateContentForStatisticsAsync(_httpContextAccessor.HttpContext, modelId, input, userId, null, tokenId, cancellationToken); } } #region 私有 private string? GetTokenByHttpContext(HttpContext httpContext) { // 优先从 x-api-key 获取 string apiKeyHeader = httpContext.Request.Headers["x-api-key"]; if (!string.IsNullOrWhiteSpace(apiKeyHeader)) { return apiKeyHeader.Trim(); } // 再从 谷歌 获取 string googApiKeyHeader = httpContext.Request.Headers["x-goog-api-key"]; if (!string.IsNullOrWhiteSpace(googApiKeyHeader)) { return googApiKeyHeader.Trim(); } // 再检查 Authorization 头 string authHeader = httpContext.Request.Headers["Authorization"]; if (!string.IsNullOrWhiteSpace(authHeader) && authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { 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"); } } #endregion }