72 lines
2.2 KiB
C#
72 lines
2.2 KiB
C#
|
|
using System.Net.Http.Headers;
|
|||
|
|
|
|||
|
|
namespace Service;
|
|||
|
|
|
|||
|
|
public interface IOpenAiService
|
|||
|
|
{
|
|||
|
|
Task<string?> ChatAsync(string systemPrompt, string userPrompt);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class OpenAiService(
|
|||
|
|
IOptions<AISettings> aiSettings,
|
|||
|
|
ILogger<OpenAiService> logger
|
|||
|
|
) : IOpenAiService
|
|||
|
|
{
|
|||
|
|
public async Task<string?> 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;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|