using System; using System.Collections.Generic; using System.IO; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; namespace WPFUI.Test.Web { /// /// TODO /// internal class LLMClient { private readonly HttpClient _httpClient; private readonly List _conversationHistory; private bool _disposed; /// /// 创建LLM客户端实例 /// /// API密钥 /// API端点地址 /// 可选的系统提示词 public LLMClient(string apiKey, string endpoint, string systemPrompt = null) { if (string.IsNullOrEmpty(apiKey)) throw new ArgumentNullException(nameof(apiKey)); if (string.IsNullOrEmpty(endpoint)) throw new ArgumentNullException(nameof(endpoint)); _httpClient = new HttpClient { BaseAddress = new Uri(endpoint) }; _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey); _httpClient.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json")); // 初始化对话历史,可选添加系统提示 _conversationHistory = new List(); if (!string.IsNullOrEmpty(systemPrompt)) { _conversationHistory.Add(new ChatMessage("system", systemPrompt)); } } /// /// 获取当前对话历史 /// public IReadOnlyList ConversationHistory => _conversationHistory.AsReadOnly(); /// /// 清除对话历史(保留系统提示) /// public void ClearHistory() { if (_conversationHistory.Count > 0 && _conversationHistory[0].Role == "system") { var systemMessage = _conversationHistory[0]; _conversationHistory.Clear(); _conversationHistory.Add(systemMessage); } else { _conversationHistory.Clear(); } } /// /// 发送非流式请求获取完整响应 /// public async Task SendMessageAsync(string userMessage, string model = "qwen-max") { // 添加用户消息到历史 _conversationHistory.Add(new ChatMessage("user", userMessage)); // 创建请求内容(包含完整对话历史) var request = CreateRequestContent(_conversationHistory, model); HttpResponseMessage response = await _httpClient.PostAsync("", request); response.EnsureSuccessStatusCode(); string jsonResponse = await response.Content.ReadAsStringAsync(); // 解析响应并添加到对话历史 var responseObj = JsonConvert.DeserializeObject(jsonResponse); string assistantReply = responseObj?.output?.choices?[0]?.message?.content; if (!string.IsNullOrEmpty(assistantReply)) { _conversationHistory.Add(new ChatMessage("assistant", assistantReply)); } return assistantReply; } // 修正关键:使用SendAsync替代PostAsync解决.NET Framework参数问题 public async Task SendMessageStreamAsync(string userMessage, Action onChunkReceived, string model = "qwen-max", CancellationToken cancellationToken = default) { _conversationHistory.Add(new ChatMessage("user", userMessage)); _conversationHistory.Add(new ChatMessage("assistant", "")); // 占位符 var request = CreateRequestContent(_conversationHistory, model, true); // 创建HttpRequestMessage对象(.NET Framework兼容方式) var httpRequest = new HttpRequestMessage(HttpMethod.Post, _httpClient.BaseAddress) { Content = request }; // 使用SendAsync并指定HttpCompletionOption(.NET Framework兼容) using (var response = await _httpClient.SendAsync( httpRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken)) { response.EnsureSuccessStatusCode(); using (var stream = await response.Content.ReadAsStreamAsync()) using (var reader = new StreamReader(stream, Encoding.UTF8)) { string fullResponse = ""; while (!reader.EndOfStream) { string line = await reader.ReadLineAsync(); if (string.IsNullOrWhiteSpace(line)) continue; // 修正:正确处理阿里云SSE格式(data: {...}) if (line.StartsWith("data: ")) { string jsonData = line.Substring(6); try { if (jsonData.Trim() == "[DONE]") continue; var json = JsonConvert.DeserializeObject(jsonData); string content = json?.output?.choices?[0]?.delta?.content; if (!string.IsNullOrEmpty(content)) { fullResponse += content; onChunkReceived?.Invoke(content); } } catch { // 忽略无法解析的数据 } } } // 更新助手消息的实际内容 if (_conversationHistory.Count > 0) { _conversationHistory[_conversationHistory.Count - 1] = new ChatMessage("assistant", fullResponse); } } } } private StringContent CreateRequestContent(List messages, string model, bool stream = false) { // 构建符合通义千问API的消息结构 var requestBody = new { model, input = new { messages = messages.ConvertAll(m => new { role = m.Role, content = m.Content }) }, parameters = new { result_format = "message" }, stream }; string json = JsonConvert.SerializeObject(requestBody); return new StringContent(json, Encoding.UTF8, "application/json"); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { _httpClient?.Dispose(); } _disposed = true; } } } /// /// 表示对话中的单条消息 /// public class ChatMessage { /// /// 消息角色: user, assistant, system /// public string Role { get; set; } /// /// 消息内容 /// public string Content { get; set; } public ChatMessage(string role, string content) { Role = role; Content = content; } } }