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 CompleteChatAsync(AiModelDescribe aiModelDescribe, List 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); while (await streamReader.ReadLineAsync(cancellationToken) is { } line) { var result = new CompleteChatResponse(); try { var jsonObj = MapToJObject(line); var content = GetContent(jsonObj); var tokenUsage = GetTokenUsage(jsonObj); result= new CompleteChatResponse { TokenUsage = tokenUsage, IsFinish = tokenUsage is not null, Content = content }; } catch (Exception e) { Console.WriteLine("解析失败"); } yield return result; } } private JObject? MapToJObject(string line) { if (string.IsNullOrWhiteSpace(line)) return null; string prefix = "data: "; line = line.Substring(prefix.Length); return JObject.Parse(line); } private string? GetContent(JObject? jsonObj) { var contentToken = jsonObj.SelectToken("choices[0].delta.content"); if (contentToken != null && contentToken.Type != JTokenType.Null) { return contentToken.ToString(); } return null; } private TokenUsage? GetTokenUsage(JObject? jsonObj) { var usage = jsonObj.SelectToken("usage"); if (usage is not null && usage.Type != JTokenType.Null) { var result = new TokenUsage() { OutputTokenCount = usage["completion_tokens"].ToObject(), InputTokenCount = usage["prompt_tokens"].ToObject(), TotalTokenCount = usage["total_tokens"].ToObject() }; return result; } return null; } }