111 lines
3.7 KiB
C#
111 lines
3.7 KiB
C#
using System.Runtime.CompilerServices;
|
||
using System.Text;
|
||
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
using OpenAI.Chat;
|
||
using Yi.Framework.AiHub.Domain.Extensions;
|
||
using Yi.Framework.AiHub.Domain.Shared.Dtos;
|
||
|
||
namespace Yi.Framework.AiHub.Domain.AiChat.Impl;
|
||
|
||
public class AzureRestChatService : IChatService
|
||
{
|
||
public AzureRestChatService()
|
||
{
|
||
}
|
||
|
||
public async IAsyncEnumerable<string> CompleteChatAsync(AiModelDescribe aiModelDescribe, List<ChatMessage> messages,
|
||
[EnumeratorCancellation] CancellationToken cancellationToken)
|
||
{
|
||
// 设置API URL
|
||
var apiUrl = $"{aiModelDescribe.Endpoint}";
|
||
|
||
// 准备请求内容
|
||
var requestBody = new
|
||
{
|
||
messages = messages.Select(x => new
|
||
{
|
||
role = x.GetRoleAsString(),
|
||
content = x.Content.FirstOrDefault()?.Text
|
||
}).ToList(),
|
||
stream = true,
|
||
max_tokens = 2048,
|
||
temperature = 0.8,
|
||
top_p = 0.1,
|
||
// presence_penalty = 0,
|
||
// frequency_penalty = 0,
|
||
model = aiModelDescribe.ModelId
|
||
};
|
||
|
||
// 序列化请求内容为JSON
|
||
string jsonBody = JsonConvert.SerializeObject(requestBody);
|
||
|
||
using var httpClient = new HttpClient();
|
||
// 设置请求头
|
||
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {aiModelDescribe.ApiKey}");
|
||
// 其他头信息如Content-Type在StringContent中设置
|
||
|
||
// 构造 POST 请求
|
||
var request = new HttpRequestMessage(HttpMethod.Post, apiUrl);
|
||
|
||
// 设置请求内容(示例)
|
||
request.Content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
|
||
|
||
// 发送POST请求
|
||
HttpResponseMessage response =
|
||
await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
|
||
// 确认响应成功
|
||
response.EnsureSuccessStatusCode();
|
||
|
||
// 读取响应内容
|
||
var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken);
|
||
// 从流中读取数据并输出到控制台
|
||
using var streamReader = new StreamReader(responseStream);
|
||
string line;
|
||
while ((line = await streamReader.ReadLineAsync(cancellationToken)) != null)
|
||
{
|
||
var result = GetContent(line);
|
||
if (result is not null)
|
||
{
|
||
yield return result;
|
||
}
|
||
}
|
||
}
|
||
|
||
private string? GetContent(string line)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(line))
|
||
return null;
|
||
string prefix = "data: ";
|
||
line = line.Substring(prefix.Length);
|
||
|
||
|
||
try
|
||
{
|
||
// 解析为JObject
|
||
var jsonObj = JObject.Parse(line);
|
||
var content = jsonObj["choices"][0]["delta"]["content"].ToString();
|
||
return content;
|
||
// // 判断choices是否存在且是数组,并且有元素
|
||
// if (jsonObj.TryGetValue("choices", out var choicesToken) && choicesToken is JArray choicesArray &&
|
||
// choicesArray.Count > 0)
|
||
// {
|
||
// var firstChoice = choicesArray[0] as JObject;
|
||
// // 判断delta字段是否存在
|
||
// if (firstChoice.TryGetValue("delta", out var deltaToken))
|
||
// {
|
||
// // 获取content字段
|
||
// if (deltaToken.Type == JTokenType.Object && ((JObject)deltaToken).TryGetValue("content", out var contentToken))
|
||
// {
|
||
// return contentToken.ToString();
|
||
// }
|
||
// }
|
||
// }
|
||
}
|
||
catch (Exception)
|
||
{
|
||
// 解析失败
|
||
return null;
|
||
}
|
||
}
|
||
} |