2025-12-17 18:47:28 +08:00
|
|
|
|
using System.Text.Json;
|
|
|
|
|
|
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;
|
2025-10-12 20:07:58 +08:00
|
|
|
|
using Volo.Abp.Users;
|
|
|
|
|
|
using Yi.Framework.AiHub.Domain.Entities;
|
2025-12-25 23:25:54 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Entities.Chat;
|
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;
|
2025-10-12 20:07:58 +08:00
|
|
|
|
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-12-11 01:17:31 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Shared.Dtos.OpenAi.Responses;
|
2025-08-03 23:23:32 +08:00
|
|
|
|
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
2025-10-12 20:07:58 +08:00
|
|
|
|
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;
|
2026-01-01 00:44:02 +08:00
|
|
|
|
private readonly ModelManager _modelManager;
|
2025-08-03 23:23:32 +08:00
|
|
|
|
private readonly AiBlacklistManager _aiBlacklistManager;
|
2025-10-12 20:07:58 +08:00
|
|
|
|
private readonly IAccountService _accountService;
|
|
|
|
|
|
private readonly PremiumPackageManager _premiumPackageManager;
|
2025-12-25 23:25:54 +08:00
|
|
|
|
private readonly ISqlSugarRepository<ImageStoreTaskAggregateRoot> _imageStoreRepository;
|
2026-01-01 00:44:02 +08:00
|
|
|
|
private readonly ISqlSugarRepository<AiModelEntity> _aiModelRepository;
|
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,
|
2026-01-01 00:44:02 +08:00
|
|
|
|
ModelManager modelManager, AiBlacklistManager aiBlacklistManager,
|
|
|
|
|
|
IAccountService accountService, PremiumPackageManager premiumPackageManager, ISqlSugarRepository<ImageStoreTaskAggregateRoot> imageStoreRepository, ISqlSugarRepository<AiModelEntity> aiModelRepository)
|
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;
|
2026-01-01 00:44:02 +08:00
|
|
|
|
_modelManager = modelManager;
|
2025-08-03 23:23:32 +08:00
|
|
|
|
_aiBlacklistManager = aiBlacklistManager;
|
2025-10-12 20:07:58 +08:00
|
|
|
|
_accountService = accountService;
|
|
|
|
|
|
_premiumPackageManager = premiumPackageManager;
|
2025-12-25 23:25:54 +08:00
|
|
|
|
_imageStoreRepository = imageStoreRepository;
|
2026-01-01 00:44:02 +08:00
|
|
|
|
_aiModelRepository = aiModelRepository;
|
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-11-27 19:01:16 +08:00
|
|
|
|
var tokenValidation = await _tokenManager.ValidateTokenAsync(GetTokenByHttpContext(httpContext), input.Model);
|
|
|
|
|
|
var userId = tokenValidation.UserId;
|
|
|
|
|
|
var tokenId = tokenValidation.TokenId;
|
2025-08-03 23:23:32 +08:00
|
|
|
|
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
|
2025-10-14 22:17:21 +08:00
|
|
|
|
|
|
|
|
|
|
//如果是尊享包服务,需要校验是是否尊享包足够
|
2026-01-01 00:44:02 +08:00
|
|
|
|
var isPremium = await _modelManager.IsPremiumModelAsync(input.Model);
|
|
|
|
|
|
|
|
|
|
|
|
if (isPremium)
|
2025-10-14 22:17:21 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 检查尊享token包用量
|
|
|
|
|
|
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(userId);
|
|
|
|
|
|
if (availableTokens <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new UserFriendlyException("尊享token包用量不足,请先购买尊享token包");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-27 19:01:16 +08:00
|
|
|
|
|
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,
|
2026-01-01 00:44:02 +08:00
|
|
|
|
userId, null, tokenId,CancellationToken.None);
|
2025-07-09 19:12:53 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-07-17 23:10:26 +08:00
|
|
|
|
await _aiGateWayManager.CompleteChatForStatisticsAsync(_httpContextAccessor.HttpContext, input, userId,
|
2025-11-27 19:01:16 +08:00
|
|
|
|
null, tokenId,
|
2026-01-01 00:44:02 +08:00
|
|
|
|
CancellationToken.None);
|
2025-07-09 19:12:53 +08:00
|
|
|
|
}
|
2025-07-02 23:30:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-11 01:17:31 +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;
|
2025-08-14 15:14:30 +08:00
|
|
|
|
Intercept(httpContext);
|
2025-11-27 19:01:16 +08:00
|
|
|
|
var tokenValidation = await _tokenManager.ValidateTokenAsync(GetTokenByHttpContext(httpContext), input.Model);
|
|
|
|
|
|
var userId = tokenValidation.UserId;
|
|
|
|
|
|
var tokenId = tokenValidation.TokenId;
|
2025-08-03 23:23:32 +08:00
|
|
|
|
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
|
2025-11-27 19:01:16 +08:00
|
|
|
|
await _aiGateWayManager.CreateImageForStatisticsAsync(httpContext, userId, null, input, tokenId);
|
2025-08-03 23:23:32 +08:00
|
|
|
|
}
|
2025-08-14 15:14:30 +08:00
|
|
|
|
|
2025-12-11 01:17:31 +08:00
|
|
|
|
|
2025-08-11 15:29:24 +08:00
|
|
|
|
/// <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;
|
2025-08-14 15:14:30 +08:00
|
|
|
|
Intercept(httpContext);
|
2025-11-27 19:01:16 +08:00
|
|
|
|
var tokenValidation = await _tokenManager.ValidateTokenAsync(GetTokenByHttpContext(httpContext), input.Model);
|
|
|
|
|
|
var userId = tokenValidation.UserId;
|
|
|
|
|
|
var tokenId = tokenValidation.TokenId;
|
2025-08-11 15:29:24 +08:00
|
|
|
|
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
|
2025-11-27 19:01:16 +08:00
|
|
|
|
await _aiGateWayManager.EmbeddingForStatisticsAsync(httpContext, userId, null, input, tokenId);
|
2025-08-11 15:29:24 +08:00
|
|
|
|
}
|
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-12-11 01:17:31 +08:00
|
|
|
|
|
2025-10-11 15:25:43 +08:00
|
|
|
|
/// <summary>
|
2025-10-12 20:07:58 +08:00
|
|
|
|
/// 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;
|
2025-11-27 19:01:16 +08:00
|
|
|
|
var tokenValidation = await _tokenManager.ValidateTokenAsync(GetTokenByHttpContext(httpContext), input.Model);
|
|
|
|
|
|
var userId = tokenValidation.UserId;
|
|
|
|
|
|
var tokenId = tokenValidation.TokenId;
|
2025-10-11 15:25:43 +08:00
|
|
|
|
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
|
2025-10-12 20:07:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 验证用户是否为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)
|
|
|
|
|
|
{
|
2025-12-11 01:17:31 +08:00
|
|
|
|
await _aiGateWayManager.AnthropicCompleteChatStreamForStatisticsAsync(_httpContextAccessor.HttpContext,
|
|
|
|
|
|
input,
|
2026-01-01 00:44:02 +08:00
|
|
|
|
userId, null, tokenId, CancellationToken.None);
|
2025-10-11 15:25:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-12-11 01:17:31 +08:00
|
|
|
|
await _aiGateWayManager.AnthropicCompleteChatForStatisticsAsync(_httpContextAccessor.HttpContext, input,
|
|
|
|
|
|
userId,
|
2025-11-27 19:01:16 +08:00
|
|
|
|
null, tokenId,
|
2026-01-01 00:44:02 +08:00
|
|
|
|
CancellationToken.None);
|
2025-10-11 15:25:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-17 18:47:28 +08:00
|
|
|
|
|
2025-12-11 01:17:31 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 响应-Openai新规范 (尊享服务专用)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="input"></param>
|
|
|
|
|
|
/// <param name="cancellationToken"></param>
|
|
|
|
|
|
[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)
|
|
|
|
|
|
{
|
2025-12-17 18:47:28 +08:00
|
|
|
|
await _aiGateWayManager.OpenAiResponsesStreamForStatisticsAsync(_httpContextAccessor.HttpContext,
|
|
|
|
|
|
input,
|
2026-01-01 00:44:02 +08:00
|
|
|
|
userId, null, tokenId, CancellationToken.None);
|
2025-12-11 01:17:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
await _aiGateWayManager.OpenAiResponsesAsyncForStatisticsAsync(_httpContextAccessor.HttpContext, input,
|
|
|
|
|
|
userId,
|
|
|
|
|
|
null, tokenId,
|
2026-01-01 00:44:02 +08:00
|
|
|
|
CancellationToken.None);
|
2025-12-11 01:17:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-10-11 15:25:43 +08:00
|
|
|
|
|
2025-12-17 18:47:28 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 生成-Gemini (尊享服务专用)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="input"></param>
|
|
|
|
|
|
/// <param name="modelId"></param>
|
|
|
|
|
|
/// <param name="alt"></param>
|
|
|
|
|
|
/// <param name="cancellationToken"></param>
|
2025-12-17 21:51:01 +08:00
|
|
|
|
[HttpPost("openApi/v1beta/models/{modelId}:{action:regex(^(generateContent|streamGenerateContent)$)}")]
|
2025-12-17 18:47:28 +08:00
|
|
|
|
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包");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-26 18:29:47 +08:00
|
|
|
|
|
2025-12-17 18:47:28 +08:00
|
|
|
|
//ai网关代理httpcontext
|
|
|
|
|
|
if (alt == "sse")
|
|
|
|
|
|
{
|
2025-12-17 21:51:01 +08:00
|
|
|
|
await _aiGateWayManager.GeminiGenerateContentStreamForStatisticsAsync(_httpContextAccessor.HttpContext,
|
|
|
|
|
|
modelId, input,
|
|
|
|
|
|
userId,
|
|
|
|
|
|
null, tokenId,
|
2026-01-01 00:44:02 +08:00
|
|
|
|
CancellationToken.None);
|
2025-12-17 18:47:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-12-17 21:51:01 +08:00
|
|
|
|
await _aiGateWayManager.GeminiGenerateContentForStatisticsAsync(_httpContextAccessor.HttpContext,
|
2025-12-17 18:47:28 +08:00
|
|
|
|
modelId, input,
|
|
|
|
|
|
userId,
|
|
|
|
|
|
null, tokenId,
|
2026-01-01 00:44:02 +08:00
|
|
|
|
CancellationToken.None);
|
2025-12-17 18:47:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-11 15:25:43 +08:00
|
|
|
|
#region 私有
|
|
|
|
|
|
|
2025-07-03 22:31:39 +08:00
|
|
|
|
private string? GetTokenByHttpContext(HttpContext httpContext)
|
|
|
|
|
|
{
|
2025-10-18 13:23:54 +08:00
|
|
|
|
// 优先从 x-api-key 获取
|
|
|
|
|
|
string apiKeyHeader = httpContext.Request.Headers["x-api-key"];
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(apiKeyHeader))
|
|
|
|
|
|
{
|
|
|
|
|
|
return apiKeyHeader.Trim();
|
|
|
|
|
|
}
|
2025-12-17 21:51:01 +08:00
|
|
|
|
|
|
|
|
|
|
// 再从 谷歌 获取
|
|
|
|
|
|
string googApiKeyHeader = httpContext.Request.Headers["x-goog-api-key"];
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(googApiKeyHeader))
|
|
|
|
|
|
{
|
|
|
|
|
|
return googApiKeyHeader.Trim();
|
|
|
|
|
|
}
|
2025-07-03 22:31:39 +08:00
|
|
|
|
|
2025-10-18 13:23:54 +08:00
|
|
|
|
// 再检查 Authorization 头
|
|
|
|
|
|
string authHeader = httpContext.Request.Headers["Authorization"];
|
2025-12-11 01:17:31 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
2025-08-14 15:14:30 +08:00
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|