feat: ai完成接入deepseek
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OpenAI.Chat;
|
||||
using Yi.Framework.AiHub.Application.Contracts.Options;
|
||||
using Yi.Framework.AiHub.Domain.Extensions;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.AiChat.Impl;
|
||||
|
||||
public class AzureRestChatService : IChatService
|
||||
{
|
||||
private readonly AiChatModelOptions _options;
|
||||
|
||||
public AzureRestChatService(IOptions<AiGateWayOptions> options)
|
||||
{
|
||||
this._options = options.Value.Chats[nameof(AzureRestChatService)];
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<string> CompleteChatAsync(string modelId, List<ChatMessage> messages,
|
||||
[EnumeratorCancellation] CancellationToken cancellationToken)
|
||||
{
|
||||
// 设置API URL
|
||||
var apiUrl = $"{_options.Endpoint}models/chat/completions";
|
||||
|
||||
|
||||
var ss = messages.Select(x => new
|
||||
{
|
||||
role = x.GetRoleAsString(),
|
||||
content = x.Content.FirstOrDefault()?.Text
|
||||
}).ToList();
|
||||
|
||||
// 准备请求内容
|
||||
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 = modelId
|
||||
};
|
||||
|
||||
// 序列化请求内容为JSON
|
||||
string jsonBody = JsonConvert.SerializeObject(requestBody);
|
||||
|
||||
using var httpClient = new HttpClient();
|
||||
// 设置请求头
|
||||
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_options.ApiKey}");
|
||||
// 其他头信息如Content-Type在StringContent中设置
|
||||
|
||||
var content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
|
||||
// 发送POST请求
|
||||
HttpResponseMessage response = await httpClient.PostAsync(apiUrl, content, cancellationToken);
|
||||
// 确认响应成功
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
// 读取响应内容
|
||||
var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken);
|
||||
// 从流中读取数据并输出到控制台
|
||||
using var streamReader = new System.IO.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;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Reflection;
|
||||
using OpenAI.Chat;
|
||||
|
||||
namespace Yi.Framework.AiHub.Domain.Extensions;
|
||||
|
||||
public static class ChatMessageExtensions
|
||||
{
|
||||
public static string GetRoleAsString(this ChatMessage message)
|
||||
{
|
||||
var type = message.GetType();
|
||||
var propertyInfo = type.GetProperty("Role", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
if (propertyInfo != null)
|
||||
{
|
||||
var value = propertyInfo.GetValue(message) as ChatMessageRole?;
|
||||
return value.ToString().ToLower();
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ namespace Yi.Framework.AiHub.Domain
|
||||
|
||||
|
||||
services.AddKeyedTransient<IChatService, AzureChatService>(nameof(AzureChatService));
|
||||
services.AddKeyedTransient<IChatService, AzureRestChatService>(nameof(AzureRestChatService));
|
||||
}
|
||||
|
||||
public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
|
||||
|
||||
@@ -17,22 +17,18 @@ namespace Yi.Abp.Application
|
||||
[DependsOn(
|
||||
typeof(YiAbpApplicationContractsModule),
|
||||
typeof(YiAbpDomainModule),
|
||||
|
||||
|
||||
typeof(YiFrameworkRbacApplicationModule),
|
||||
typeof(YiFrameworkBbsApplicationModule),
|
||||
typeof(YiFrameworkBbsApplicationModule),
|
||||
typeof(YiFrameworkDigitalCollectiblesApplicationModule),
|
||||
typeof(YiFrameworkChatHubApplicationModule),
|
||||
typeof(YiFrameworkChatHubApplicationModule),
|
||||
typeof(YiFrameworkStockApplicationModule),
|
||||
typeof(YiFrameworkAiHubApplicationModule),
|
||||
|
||||
typeof(YiFrameworkTenantManagementApplicationModule),
|
||||
typeof(YiFrameworkCodeGenApplicationModule),
|
||||
typeof (YiFrameworkSettingManagementApplicationModule),
|
||||
|
||||
typeof(YiFrameworkSettingManagementApplicationModule),
|
||||
typeof(YiFrameworkDddApplicationModule)
|
||||
)]
|
||||
)]
|
||||
public class YiAbpApplicationModule : AbpModule
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user