284 lines
11 KiB
C#
284 lines
11 KiB
C#
using LMS.DAO;
|
||
using LMS.Repository.DB;
|
||
using LMS.Repository.Forward;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Newtonsoft.Json;
|
||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||
using System.Net;
|
||
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;
|
||
|
||
namespace LMS.service.Service;
|
||
|
||
public class ForwardWordService(ApplicationDbContext context)
|
||
{
|
||
private readonly ApplicationDbContext _context = context;
|
||
|
||
#region 非流转发接口,需要系统数据
|
||
/// <summary>
|
||
/// 转发OpenAi格式的请求 非流
|
||
/// </summary>
|
||
/// <param name="request"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<ActionResult<APIResponseModel<object>>> ForwardWord(ForwardModel request)
|
||
{
|
||
try
|
||
{
|
||
// 要校验机器码,但是目前不需要
|
||
|
||
if (request.Word == null || request.Word == "")
|
||
{
|
||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||
}
|
||
|
||
// 获取提示词预设
|
||
Prompt? prompt = await _context.Prompt.FirstOrDefaultAsync(x => x.PromptTypeId == request.PromptTypeId && x.Id == request.PromptId);
|
||
if (prompt == null)
|
||
{
|
||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.FindPromptStringFail);
|
||
}
|
||
|
||
// 开始拼接请求体
|
||
using HttpClient client = new HttpClient();
|
||
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + request.ApiKey);
|
||
string json = JsonConvert.SerializeObject(new
|
||
{
|
||
model = request.Model,
|
||
temperature = 0.3,
|
||
messages = new List<OpenAI.RequestMessage>
|
||
{
|
||
new OpenAI.RequestMessage
|
||
{
|
||
role = "system",
|
||
content = prompt.PromptString
|
||
|
||
},
|
||
new OpenAI.RequestMessage
|
||
{
|
||
role = "user",
|
||
content = request.Word
|
||
}
|
||
}
|
||
});
|
||
|
||
// 判断请求的url是不是满足条件
|
||
if (string.IsNullOrEmpty(request.GptUrl))
|
||
{
|
||
throw new Exception("请求的url为空");
|
||
}
|
||
if (!request.GptUrl.StartsWith("https://ark.cn-beijing.volces.com") && !request.GptUrl.StartsWith("https://api.moonshot.cn") && !request.GptUrl.StartsWith("https://laitool.net") && !request.GptUrl.StartsWith("https://api.laitool.cc") && !request.GptUrl.StartsWith("https://laitool.cc"))
|
||
{
|
||
throw new Exception("请求的url不合法");
|
||
}
|
||
client.Timeout = Timeout.InfiniteTimeSpan;
|
||
var response = await client.PostAsync(request.GptUrl, new StringContent(json, Encoding.UTF8, "application/json"));
|
||
|
||
// 判断返回的状态码
|
||
if (response.StatusCode != HttpStatusCode.OK)
|
||
{
|
||
// 读取响应体
|
||
string responseContent = await response.Content.ReadAsStringAsync();
|
||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ForwardWordFail, responseContent, "请求失败");
|
||
}
|
||
var content = await response.Content.ReadAsStringAsync();
|
||
// 序列化一下
|
||
return APIResponseModel<object>.CreateSuccessResponseModel(content);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 流式转发接口,需要系统数据
|
||
/// <summary>
|
||
/// 流式转发
|
||
/// </summary>
|
||
/// <param name="request"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="Exception"></exception>
|
||
public async IAsyncEnumerable<string> ForwardWordStream(ForwardModel request)
|
||
{
|
||
|
||
// 要校验机器码,但是目前不需要
|
||
|
||
if (request.Word == null || request.Word == "")
|
||
{
|
||
throw new Exception("参数错误");
|
||
}
|
||
|
||
// 判断请求的url是不是满足条件
|
||
if (string.IsNullOrEmpty(request.GptUrl))
|
||
{
|
||
throw new Exception("请求的url为空");
|
||
}
|
||
if (!request.GptUrl.StartsWith("https://ark.cn-beijing.volces.com") && !request.GptUrl.StartsWith("https://api.moonshot.cn") && !request.GptUrl.StartsWith("https://laitool.net") && !request.GptUrl.StartsWith("https://api.laitool.cc") && !request.GptUrl.StartsWith("https://laitool.cc"))
|
||
{
|
||
throw new Exception("请求的url不合法");
|
||
}
|
||
|
||
// 获取提示词预设
|
||
Prompt? prompt = await _context.Prompt.FirstOrDefaultAsync(x => x.PromptTypeId == request.PromptTypeId && x.Id == request.PromptId);
|
||
if (prompt == null)
|
||
{
|
||
throw new Exception(ResponseCode.FindPromptStringFail.GetResult());
|
||
}
|
||
var openAiService = new OpenAIService(new OpenAIOptions()
|
||
{
|
||
ApiKey = request.ApiKey,
|
||
BaseDomain = request.GptUrl,
|
||
});
|
||
var completionResult = openAiService.ChatCompletion.CreateCompletionAsStream(new ChatCompletionCreateRequest
|
||
{
|
||
Messages = new List<ChatMessage>
|
||
{
|
||
ChatMessage.FromSystem(prompt.PromptString),
|
||
ChatMessage.FromUser(request.Word)
|
||
},
|
||
Model = request.Model,
|
||
Stream = true
|
||
});
|
||
|
||
await foreach (var completion in completionResult)
|
||
{
|
||
if (completion.Successful)
|
||
{ // 这边只返回数据,不返回全部的数据结构了
|
||
yield return completion.Choices.First().Message.Content ?? "";
|
||
}
|
||
else
|
||
{
|
||
if (completion.Error == null)
|
||
{
|
||
throw new Exception("Unknown Error");
|
||
}
|
||
|
||
throw new Exception($"{completion.Error.Code}: {completion.Error.Message}");
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Post 转发接口
|
||
/// <summary>
|
||
/// 简单的转发接口
|
||
/// </summary>
|
||
/// <param name="request"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<ActionResult<APIResponseModel<object>>> SimpleTransfer(SimpleTransferModel request)
|
||
{
|
||
try
|
||
{
|
||
// 开始拼接请求体
|
||
using HttpClient client = new();
|
||
if (request.url.StartsWith("https://api.laitool.net"))
|
||
{
|
||
//client.DefaultRequestHeaders.Add("Authorization", "Bearer " + request.APIKey);
|
||
client.DefaultRequestHeaders.Add("mj-api-secret", request.APIKey);
|
||
}
|
||
else
|
||
{
|
||
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + request.APIKey);
|
||
}
|
||
|
||
// 判断请求的url是不是满足条件
|
||
if (string.IsNullOrEmpty(request.url))
|
||
{
|
||
throw new Exception("请求的url为空");
|
||
}
|
||
if (!request.url.StartsWith("https://ark.cn-beijing.volces.com")
|
||
&& !request.url.StartsWith("https://api.moonshot.cn")
|
||
&& !request.url.StartsWith("https://laitool.net")
|
||
&& !request.url.StartsWith("https://api.laitool.net")
|
||
&& !request.url.StartsWith("https://api.laitool.cc")
|
||
&& !request.url.StartsWith("https://laitool.cc"))
|
||
{
|
||
throw new Exception("请求的url不支持转发");
|
||
}
|
||
client.Timeout = Timeout.InfiniteTimeSpan;
|
||
var response = await client.PostAsync(request.url, new StringContent(request.dataString, Encoding.UTF8, "application/json"));
|
||
|
||
// 判断返回的状态码
|
||
if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Created)
|
||
{
|
||
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
||
{
|
||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ForwardWordFail, "responseCode: 401", "请求失败");
|
||
}
|
||
// 读取响应体
|
||
string responseContent = await response.Content.ReadAsStringAsync();
|
||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ForwardWordFail, responseContent, "请求失败");
|
||
}
|
||
var content = await response.Content.ReadAsStringAsync();
|
||
return APIResponseModel<object>.CreateSuccessResponseModel(content);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Get直接转发接口
|
||
internal async Task<ActionResult<APIResponseModel<object>>> GetTransfer(GetTransferModel getTransferModel)
|
||
{
|
||
try
|
||
{
|
||
// 开始拼接请求体
|
||
using HttpClient client = new();
|
||
|
||
if (getTransferModel.url.StartsWith("https://api.laitool.net"))
|
||
{
|
||
client.DefaultRequestHeaders.Add("mj-api-secret", getTransferModel.APIKey);
|
||
}
|
||
else
|
||
{
|
||
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + getTransferModel.APIKey);
|
||
}
|
||
|
||
// 判断请求的url是不是满足条件
|
||
if (string.IsNullOrEmpty(getTransferModel.url))
|
||
{
|
||
throw new Exception("请求的url为空");
|
||
}
|
||
if (!getTransferModel.url.StartsWith("https://ark.cn-beijing.volces.com")
|
||
&& !getTransferModel.url.StartsWith("https://api.moonshot.cn")
|
||
&& !getTransferModel.url.StartsWith("https://laitool.net")
|
||
&& !getTransferModel.url.StartsWith("https://api.laitool.net")
|
||
&& !getTransferModel.url.StartsWith("https://api.laitool.cc")
|
||
&& !getTransferModel.url.StartsWith("https://laitool.cc"))
|
||
{
|
||
throw new Exception("请求的url不支持转发");
|
||
}
|
||
client.Timeout = Timeout.InfiniteTimeSpan;
|
||
var response = await client.GetAsync(getTransferModel.url);
|
||
// 判断返回的状态码
|
||
if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Created)
|
||
{
|
||
// 读取响应体
|
||
string responseContent = await response.Content.ReadAsStringAsync();
|
||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ForwardWordFail, responseContent, "请求失败");
|
||
}
|
||
var content = await response.Content.ReadAsStringAsync();
|
||
// 序列化一下
|
||
return APIResponseModel<object>.CreateSuccessResponseModel(content);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||
}
|
||
}
|
||
#endregion
|
||
}
|