using System.Net.Http.Headers; namespace Service; public interface IOpenAiService { Task ChatAsync(string systemPrompt, string userPrompt); } public class OpenAiService( IOptions aiSettings, ILogger logger ) : IOpenAiService { public async Task ChatAsync(string systemPrompt, string userPrompt) { var cfg = aiSettings.Value; if (string.IsNullOrWhiteSpace(cfg.Endpoint) || string.IsNullOrWhiteSpace(cfg.Key) || string.IsNullOrWhiteSpace(cfg.Model)) { logger.LogWarning("未配置 OpenAI/DeepSeek 接口,无法调用 AI"); return null; } using var http = new HttpClient(); http.Timeout = TimeSpan.FromSeconds(15); http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", cfg.Key); var payload = new { model = cfg.Model, temperature = 0, messages = new object[] { new { role = "system", content = systemPrompt }, new { role = "user", content = userPrompt } } }; var url = cfg.Endpoint.TrimEnd('/') + "/chat/completions"; var json = JsonSerializer.Serialize(payload); using var content = new StringContent(json, Encoding.UTF8, "application/json"); try { using var resp = await http.PostAsync(url, content); if (!resp.IsSuccessStatusCode) { var err = await resp.Content.ReadAsStringAsync(); throw new InvalidOperationException($"AI接口调用失败: {(int)resp.StatusCode} {resp.ReasonPhrase}, {err}"); } var respText = await resp.Content.ReadAsStringAsync(); using var doc = JsonDocument.Parse(respText); var root = doc.RootElement; var contentText = root.GetProperty("choices")[0] .GetProperty("message") .GetProperty("content") .GetString(); return contentText; } catch (Exception ex) { logger.LogError(ex, "AI 调用失败"); throw; } } }