using Dpz.Core.Service.Network.Models.XunFei;
namespace Dpz.Core.Service.Network;
public class XunFeiService(IConfiguration configuration, ILogger<XunFeiService> logger)
{
private readonly string _host = "spark-api.xf-yun.com";
private readonly string _path = "/v3.5/chat";
private readonly string _date = DateTime.UtcNow.ToString("R");
private readonly JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
public async Task<List<XunFeiResponse?>> ChatAsync(XunFeiRequest request)
{
var authorization = GetAuthorization();
var serverUri = new Uri(
$"wss://{_host}{_path}?authorization={Uri.EscapeDataString(authorization)}&date={Uri.EscapeDataString(_date)}&host={_host}"
);
using var ws = new ClientWebSocket();
var source = new CancellationTokenSource();
//source.CancelAfter(5000);
try
{
await ws.ConnectAsync(serverUri, source.Token);
logger.LogInformation("websocket {@ServerUri} connected", serverUri);
}
catch (Exception e)
{
logger.LogError(e, "connection fail");
return [];
}
var requestMessage = JsonSerializer.Serialize(request, _jsonSerializerOptions);
const int retry = 5;
return await ApplicationTools.RetryAsync(
async () => await CommunicationAsync(),
TimeSpan.FromSeconds(1),
retry
);
async Task<List<XunFeiResponse?>> CommunicationAsync()
{
List<XunFeiResponse?> list = [];
try
{
if (ws.State != WebSocketState.Open)
{
throw new BusinessException($"websocket state {ws.State}");
}
var bytesToSend = new ArraySegment<byte>(Encoding.UTF8.GetBytes(requestMessage));
await ws.SendAsync(bytesToSend, WebSocketMessageType.Text, true, source.Token);
var receiveBuffer = new byte[1 << 10];
var result = await ws.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), source.Token);
while (!result.CloseStatus.HasValue)
{
if (result.MessageType == WebSocketMessageType.Text)
{
var receivedMessage = Encoding.UTF8.GetString(receiveBuffer, 0, result.Count);
var response = JsonSerializer.Deserialize<XunFeiResponse>(receivedMessage, _jsonSerializerOptions);
if (response == null)
{
logger.LogWarning(
"response is null,response message:{Message}",
receivedMessage
);
}
if (response != null && response.Header?.Code != 0)
{
logger.LogWarning("response code is error,response :{Response}", response);
}
list.Add(response);
}
else if (result.MessageType == WebSocketMessageType.Close)
{
logger.LogInformation("websocket {@ServerUri} disconnect", serverUri);
break;
}
result = await ws.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), source.Token);
}
}
catch (Exception e)
{
logger.LogInformation(e, "communication fail");
}
return list;
}
}
private string GetAuthorization()
{
var apiKey =
configuration["XunFei:ApiKey"] ?? throw new Exception("XunFei:ApiKey is null or empty");
var apiSecret =
configuration["XunFei:ApiSecret"]
?? throw new Exception("XunFei:ApiSecret is null or empty");
var parameters = new List<string>
{
$"host: {_host}",
$"date: {_date}",
$"GET {_path} HTTP/1.1",
};
var buffer = Encoding.UTF8.GetBytes(string.Join("\n", parameters));
var hashBytes = HMACSHA256.HashData(Encoding.UTF8.GetBytes(apiSecret), buffer);
var signature = Convert.ToBase64String(hashBytes);
var authorizationOrigin =
$"api_key=\"{apiKey}\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"{signature}\"";
var authorizationOriginBytes = Encoding.UTF8.GetBytes(authorizationOrigin);
return Convert.ToBase64String(authorizationOriginBytes);
}
}