修改机器码的验证,抽象通用方法

添加 OpenAI 格式的 流式转发接口 保持返回的数据格式
This commit is contained in:
2025-11-23 12:04:48 +08:00
parent 6d41f52de5
commit 5875ffe671
4 changed files with 178 additions and 12 deletions
+92 -9
View File
@@ -1,24 +1,30 @@
using LMS.DAO;
using Betalgo.Ranul.OpenAI;
using Betalgo.Ranul.OpenAI.Managers;
using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels;
using LMS.Common.Extensions;
using LMS.DAO;
using LMS.Repository.DB;
using LMS.Repository.Forward;
using LMS.Repository.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using static LMS.Common.Enums.ResponseCodeEnum;
using System.Net;
using System.Net.Http.Headers;
using System.Text;
using LMS.Repository.Model;
using Betalgo.Ranul.OpenAI.Managers;
using Betalgo.Ranul.OpenAI;
using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels;
using LMS.Common.Extensions;
using static LMS.Common.Enums.ResponseCodeEnum;
using static LMS.service.Controllers.ForwardController;
namespace LMS.service.Service;
public class ForwardWordService(ApplicationDbContext context)
public class ForwardWordService(ApplicationDbContext context, IHttpClientFactory httpClientFactory, MachineService machineService)
{
private readonly ApplicationDbContext _context = context;
private readonly IHttpClientFactory _httpClientFactory = httpClientFactory;
private readonly MachineService _machineService = machineService;
#region
/// <summary>
/// 转发OpenAi格式的请求 非流
@@ -228,7 +234,84 @@ public class ForwardWordService(ApplicationDbContext context)
}
}
#endregion
#endregion
#region OpenAI
public async Task<HttpResponseMessage> ForwardWordStreamRaw(ForwardModel request)
{
// --- 1. 基础校验 (保持原有逻辑) ---
if (string.IsNullOrEmpty(request.Word)) throw new Exception("参数错误");
if (string.IsNullOrEmpty(request.GptUrl)) throw new Exception("请求的url为空");
var allowedUrls = new[] {
"https://ark.cn-beijing.volces.com",
"https://api.moonshot.cn",
"https://laitool.net",
"https://api.laitool.cc",
"https://laitool.cc",
"https://zhiluoai.net"
};
// 简单的校验逻辑优化
if (!allowedUrls.Any(url => request.GptUrl.StartsWith(url)))
{
throw new Exception("请求的url不合法");
}
// 校验机器码
Machine? machine = await _machineService.GetActiveMachineByMachineId(request.MachineId);
if (machine == null)
{
throw new Exception("机器码不存在或已过期");
}
// --- 2. 获取提示词预设 (保持原有逻辑) ---
Prompt? prompt = await _context.Prompt.FirstOrDefaultAsync(x => x.PromptTypeId == request.PromptTypeId && x.Id == request.PromptId);
if (prompt == null)
{
throw new Exception("FindPromptStringFail"); // 建议使用具体错误码
}
// --- 3. 手动构建 OpenAI 格式的请求体 ---
// SDK 帮你做了这一步,现在我们要自己做,以便获得原始流
var payload = new
{
model = request.Model,
messages = new List<object>
{
new { role = "system", content = prompt.PromptString },
new { role = "user", content = request.Word }
},
stream = true, // 必须开启流式
// max_tokens = 2000, // 如果有需要可以加其他参数
// temperature = 0.7
};
var jsonContent = JsonConvert.SerializeObject(payload, new JsonSerializerSettings { ContractResolver = new LowercaseContractResolver() });
var httpContent = new StringContent(jsonContent, Encoding.UTF8, "application/json");
// --- 4. 发起 HTTP 请求 ---
var client = _httpClientFactory.CreateClient(); // 或者直接 new HttpClient();
// 拼接完整的 API 地址,通常 OpenAI 兼容接口的路径是 /v1/chat/completions
// 注意处理 request.GptUrl 结尾是否有 / 的情况
var baseUrl = request.GptUrl.TrimEnd('/');
var targetUrl = $"{baseUrl}/v1/chat/completions";
var requestMessage = new HttpRequestMessage(HttpMethod.Post, targetUrl);
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", request.ApiKey);
requestMessage.Content = httpContent;
// *** 关键点:使用 HttpCompletionOption.ResponseHeadersRead ***
// 这表示一旦读到响应头就返回,不要等待整个 Body 下载完成,这样才能实现流式转发
var response = await client.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead);
return response;
}
#endregion
#region Get直接转发接口
internal async Task<ActionResult<APIResponseModel<object>>> GetTransfer(GetTransferModel getTransferModel)