feat(openai): 升级公共组件

This commit is contained in:
Fu Diwei
2024-01-29 23:12:04 +08:00
committed by RHQYZ
parent 5a110785f8
commit fcc5e91510
28 changed files with 278 additions and 440 deletions

View File

@@ -4,7 +4,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Events
/// <para>表示 userEnter 事件的数据。</para> /// <para>表示 userEnter 事件的数据。</para>
/// <para>REF: https://developers.weixin.qq.com/doc/aispeech/confapi/thirdkefu/recivemsg.html </para> /// <para>REF: https://developers.weixin.qq.com/doc/aispeech/confapi/thirdkefu/recivemsg.html </para>
/// </summary> /// </summary>
public class UserEnterEvent : WechatOpenAIEvent, WechatOpenAIEvent.Serialization.IXmlSerializable public class UserEnterEvent : WechatOpenAIEvent
{ {
public static class Types public static class Types
{ {

View File

@@ -1,24 +0,0 @@
using System;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Exceptions
{
public class WechatOpenAIEventSerializationException : WechatOpenAIException
{
/// <inheritdoc/>
internal WechatOpenAIEventSerializationException()
{
}
/// <inheritdoc/>
internal WechatOpenAIEventSerializationException(string message)
: base(message)
{
}
/// <inheritdoc/>
internal WechatOpenAIEventSerializationException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}

View File

@@ -1,24 +0,0 @@
using System;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Exceptions
{
public class WechatOpenAIRequestTimeoutException : WechatOpenAIException
{
/// <inheritdoc/>
internal WechatOpenAIRequestTimeoutException()
{
}
/// <inheritdoc/>
internal WechatOpenAIRequestTimeoutException(string message)
: base(message)
{
}
/// <inheritdoc/>
internal WechatOpenAIRequestTimeoutException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}

View File

@@ -7,19 +7,19 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
/// </summary> /// </summary>
public static class WechatOpenAIClientEventExtensions public static class WechatOpenAIClientEventExtensions
{ {
private static TEvent InnerDeserializeEventFromXml<TEvent>(this WechatOpenAIClient client, string callbackXml) private static TEvent InnerDeserializeEventFromXml<TEvent>(this WechatOpenAIClient client, string webhookXml)
where TEvent : WechatOpenAIEvent where TEvent : WechatOpenAIEvent
{ {
if (client == null) throw new ArgumentNullException(nameof(client)); if (client is null) throw new ArgumentNullException(nameof(client));
if (callbackXml == null) throw new ArgumentNullException(callbackXml); if (webhookXml is null) throw new ArgumentNullException(webhookXml);
try try
{ {
if (!Utilities.WxMsgCryptor.TryParseXml(callbackXml, out string? encryptedXml)) if (!Utilities.WxMsgCryptor.TryParseXml(webhookXml, out string? encryptedXml))
throw new Exceptions.WechatOpenAIEventSerializationException("Failed to encrypt event data, because of empty encrypted data."); throw new WechatOpenAIException("Failed to decrypt event data, because of the encrypted data is empty.");
callbackXml = Utilities.WxMsgCryptor.AESDecrypt(cipherText: encryptedXml!, encodingAESKey: client.Credentials.EncodingAESKey!, out _); webhookXml = Utilities.WxMsgCryptor.AESDecrypt(cipherText: encryptedXml!, encodingAESKey: client.Credentials.EncodingAESKey!, out _);
return Utilities.XmlUtility.Deserialize<TEvent>(callbackXml); return Utilities.XmlHelper.Deserialize<TEvent>(webhookXml);
} }
catch (WechatOpenAIException) catch (WechatOpenAIException)
{ {
@@ -27,7 +27,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
} }
catch (Exception ex) catch (Exception ex)
{ {
throw new Exceptions.WechatOpenAIEventSerializationException("Failed to deserialize event data. Please see the inner exception for more details.", ex); throw new WechatOpenAIException("Failed to deserialize event data. Please see the inner exception for more details.", ex);
} }
} }
@@ -36,23 +36,23 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
/// </summary> /// </summary>
/// <typeparam name="TEvent"></typeparam> /// <typeparam name="TEvent"></typeparam>
/// <param name="client"></param> /// <param name="client"></param>
/// <param name="callbackXml"></param> /// <param name="webhookXml"></param>
/// <returns></returns> /// <returns></returns>
public static TEvent DeserializeEventFromXml<TEvent>(this WechatOpenAIClient client, string callbackXml) public static TEvent DeserializeEventFromXml<TEvent>(this WechatOpenAIClient client, string webhookXml)
where TEvent : WechatOpenAIEvent, WechatOpenAIEvent.Serialization.IXmlSerializable, new() where TEvent : WechatOpenAIEvent, new()
{ {
return InnerDeserializeEventFromXml<TEvent>(client, callbackXml); return InnerDeserializeEventFromXml<TEvent>(client, webhookXml);
} }
/// <summary> /// <summary>
/// <para>从 XML 反序列化得到 <see cref="WechatOpenAIEvent"/> 对象。</para> /// <para>从 XML 反序列化得到 <see cref="WechatOpenAIEvent"/> 对象。</para>
/// </summary> /// </summary>
/// <param name="client"></param> /// <param name="client"></param>
/// <param name="callbackXml"></param> /// <param name="webhookXml"></param>
/// <returns></returns> /// <returns></returns>
public static WechatOpenAIEvent DeserializeEventFromXml(this WechatOpenAIClient client, string callbackXml) public static WechatOpenAIEvent DeserializeEventFromXml(this WechatOpenAIClient client, string webhookXml)
{ {
return InnerDeserializeEventFromXml<WechatOpenAIEvent>(client, callbackXml); return InnerDeserializeEventFromXml<WechatOpenAIEvent>(client, webhookXml);
} }
/// <summary> /// <summary>
@@ -60,26 +60,26 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
/// </summary> /// </summary>
/// <typeparam name="TEvent"></typeparam> /// <typeparam name="TEvent"></typeparam>
/// <param name="client"></param> /// <param name="client"></param>
/// <param name="callbackModel"></param> /// <param name="webhookEvent"></param>
/// <returns></returns> /// <returns></returns>
public static string SerializeEventToXml<TEvent>(this WechatOpenAIClient client, TEvent callbackModel) public static string SerializeEventToXml<TEvent>(this WechatOpenAIClient client, TEvent webhookEvent)
where TEvent : WechatOpenAIEvent, WechatOpenAIEvent.Serialization.IXmlSerializable, new() where TEvent : WechatOpenAIEvent, new()
{ {
string xml; string xml;
try try
{ {
xml = Utilities.XmlUtility.Serialize(callbackModel); xml = Utilities.XmlHelper.Serialize(webhookEvent);
} }
catch (Exception ex) catch (Exception ex)
{ {
throw new Exceptions.WechatOpenAIEventSerializationException("Failed to serialize event data. Please see the inner exception for more details.", ex); throw new WechatOpenAIException("Failed to serialize event data. Please see the inner exception for more details.", ex);
} }
if (string.IsNullOrEmpty(client.Credentials.EncodingAESKey)) if (string.IsNullOrEmpty(client.Credentials.EncodingAESKey))
throw new Exceptions.WechatOpenAIEventSerializationException("Failed to encrypt event data, because there is no encoding AES key."); throw new WechatOpenAIException("Failed to encrypt event data, because the push encoding AES key is not set.");
if (string.IsNullOrEmpty(client.Credentials.Token)) if (string.IsNullOrEmpty(client.Credentials.Token))
throw new Exceptions.WechatOpenAIEventSerializationException("Failed to encrypt event data, because there is no token."); throw new WechatOpenAIException("Failed to encrypt event data, because the push token is not set.");
try try
{ {
@@ -93,7 +93,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
} }
catch (Exception ex) catch (Exception ex)
{ {
throw new Exceptions.WechatOpenAIEventSerializationException("Failed to encrypt event data. Please see the inner exception for more details.", ex); throw new WechatOpenAIException("Failed to encrypt event data. Please see the inner exception for more details.", ex);
} }
return xml; return xml;

View File

@@ -22,9 +22,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "batchimportskill", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "batchimportskill", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.BatchImportSkillResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.BatchImportSkillResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -41,9 +41,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "publish", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "publish", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.PublishResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.PublishResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -60,9 +60,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "publish_progress", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "publish_progress", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.PublishProgressResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.PublishProgressResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -79,9 +79,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "setautoreply", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "setautoreply", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.SetAutoReplyResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.SetAutoReplyResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -98,9 +98,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "label", "batchset", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "label", "batchset", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.LabelBatchSetResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.LabelBatchSetResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
} }
} }

View File

@@ -22,9 +22,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "sign", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "sign", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.SignResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.SignResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -41,9 +41,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "aibot", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "aibot", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.AIBotResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.AIBotResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -60,9 +60,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "feedback", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "feedback", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.FeedbackResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.FeedbackResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -79,9 +79,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "gethotquerylist", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "gethotquerylist", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.GetHotQueryListResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.GetHotQueryListResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -98,9 +98,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "gethotquerydetail", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "gethotquerydetail", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.GetHotQueryDetailResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.GetHotQueryDetailResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
} }
} }

View File

@@ -25,9 +25,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "getbindlink", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "getbindlink", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.GetBindLinkResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.GetBindLinkResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -44,9 +44,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "getbindlist", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "getbindlist", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.GetBindListResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.GetBindListResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -63,9 +63,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "unbindmp", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "unbindmp", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.UnbindMpResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.UnbindMpResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -82,9 +82,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "geth5link", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "geth5link", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.GetH5LinkResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.GetH5LinkResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -100,19 +100,19 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (client is null) throw new ArgumentNullException(nameof(client)); if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
if (request.FileName == null) if (request.FileName is null)
request.FileName = Guid.NewGuid().ToString("N").ToLower() + ".jpg"; request.FileName = Guid.NewGuid().ToString("N").ToLower() + ".jpg";
if (request.FileContentType == null) if (request.FileContentType is null)
request.FileContentType = "image/jpeg"; request.FileContentType = "image/jpeg";
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "assetsupload", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "assetsupload", client.Credentials.Token!);
using var fileContent = new ByteArrayContent(request.FileBytes ?? Array.Empty<byte>()); using var fileContent = new ByteArrayContent(request.FileBytes ?? Array.Empty<byte>());
using var paramContent = new StringContent( using var paramContent = new StringContent(
Utilities.WxMsgCryptor.AESEncrypt( Utilities.WxMsgCryptor.AESEncrypt(
plainText: Utilities.XmlUtility.ConvertFromJson(client.JsonSerializer.Serialize(request)), plainText: Utilities.XmlHelper.ConvertFromJson(client.JsonSerializer.Serialize(request)),
encodingAESKey: client.Credentials.EncodingAESKey!, encodingAESKey: client.Credentials.EncodingAESKey!,
appId: client.Credentials.AppId! appId: client.Credentials.AppId!
), ),
@@ -124,7 +124,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(request.FileContentType); fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(request.FileContentType);
fileContent.Headers.ContentLength = request.FileBytes?.Length; fileContent.Headers.ContentLength = request.FileBytes?.Length;
return await client.SendRequestAsync<Models.AssetsUploadResponse>(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsync<Models.AssetsUploadResponse>(flurlReq, httpContent: httpContent, cancellationToken: cancellationToken);
} }
} }
} }

View File

@@ -21,13 +21,13 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (client is null) throw new ArgumentNullException(nameof(client)); if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
if (request.AppId == null) if (request.AppId is null)
request.AppId = client.Credentials.AppId; request.AppId = client.Credentials.AppId;
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "sendmsg", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "sendmsg", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.SendMessageResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.SendMessageResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -43,13 +43,13 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (client is null) throw new ArgumentNullException(nameof(client)); if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
if (request.AppId == null) if (request.AppId is null)
request.AppId = client.Credentials.AppId; request.AppId = client.Credentials.AppId;
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "kefustate", "get", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "kefustate", "get", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.KefuStateGetResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.KefuStateGetResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
/// <summary> /// <summary>
@@ -65,13 +65,13 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (client is null) throw new ArgumentNullException(nameof(client)); if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request)); if (request is null) throw new ArgumentNullException(nameof(request));
if (request.AppId == null) if (request.AppId is null)
request.AppId = client.Credentials.AppId; request.AppId = client.Credentials.AppId;
IFlurlRequest flurlReq = client IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "kefustate", "change", client.Credentials.Token!); .CreateFlurlRequest(request, HttpMethod.Post, "kefustate", "change", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.KefuStateChangeResponse>(flurlReq, data: request, cancellationToken: cancellationToken); return await client.SendFlurlRequestAsJsonAsync<Models.KefuStateChangeResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
} }
} }
} }

View File

@@ -55,7 +55,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
/// </summary> /// </summary>
[Newtonsoft.Json.JsonProperty("confidence")] [Newtonsoft.Json.JsonProperty("confidence")]
[System.Text.Json.Serialization.JsonPropertyName("confidence")] [System.Text.Json.Serialization.JsonPropertyName("confidence")]
public float Confidence { get; set; } = default!; public decimal Confidence { get; set; } = default!;
/// <summary> /// <summary>
/// 获取或设置消息类型。 /// 获取或设置消息类型。
@@ -156,7 +156,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
/// </summary> /// </summary>
[Newtonsoft.Json.JsonProperty("confidence")] [Newtonsoft.Json.JsonProperty("confidence")]
[System.Text.Json.Serialization.JsonPropertyName("confidence")] [System.Text.Json.Serialization.JsonPropertyName("confidence")]
public double Confidence { get; set; } public decimal Confidence { get; set; }
} }
public class Slot public class Slot
@@ -274,7 +274,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
/// </summary> /// </summary>
[Newtonsoft.Json.JsonProperty("confidence")] [Newtonsoft.Json.JsonProperty("confidence")]
[System.Text.Json.Serialization.JsonPropertyName("confidence")] [System.Text.Json.Serialization.JsonPropertyName("confidence")]
public double Confidence { get; set; } public decimal Confidence { get; set; }
/// <summary> /// <summary>
/// 获取或设置发起查询的用户 ID。 /// 获取或设置发起查询的用户 ID。

View File

@@ -46,7 +46,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
/// </summary> /// </summary>
[Newtonsoft.Json.JsonProperty("score")] [Newtonsoft.Json.JsonProperty("score")]
[System.Text.Json.Serialization.JsonPropertyName("score")] [System.Text.Json.Serialization.JsonPropertyName("score")]
public double Score { get; set; } public decimal Score { get; set; }
} }
} }

View File

@@ -29,7 +29,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
/// </summary> /// </summary>
[Newtonsoft.Json.JsonProperty("score")] [Newtonsoft.Json.JsonProperty("score")]
[System.Text.Json.Serialization.JsonPropertyName("score")] [System.Text.Json.Serialization.JsonPropertyName("score")]
public double Score { get; set; } public decimal Score { get; set; }
} }
} }

View File

@@ -46,45 +46,45 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
/// 获取或设置是否开通微信门店功能。 /// 获取或设置是否开通微信门店功能。
/// </summary> /// </summary>
[Newtonsoft.Json.JsonProperty("open_store")] [Newtonsoft.Json.JsonProperty("open_store")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.NumericalBooleanConverter))] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.NumericalBooleanConverter))]
[System.Text.Json.Serialization.JsonPropertyName("open_store")] [System.Text.Json.Serialization.JsonPropertyName("open_store")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.NumericalBooleanConverter))] [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.NumericalBooleanConverter))]
public bool IsOpenStore { get; set; } public bool IsOpenStore { get; set; }
/// <summary> /// <summary>
/// 获取或设置是否开通微信扫商品功能。 /// 获取或设置是否开通微信扫商品功能。
/// </summary> /// </summary>
[Newtonsoft.Json.JsonProperty("open_scan")] [Newtonsoft.Json.JsonProperty("open_scan")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.NumericalBooleanConverter))] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.NumericalBooleanConverter))]
[System.Text.Json.Serialization.JsonPropertyName("open_scan")] [System.Text.Json.Serialization.JsonPropertyName("open_scan")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.NumericalBooleanConverter))] [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.NumericalBooleanConverter))]
public bool IsOpenScan { get; set; } public bool IsOpenScan { get; set; }
/// <summary> /// <summary>
/// 获取或设置是否开通微信支付功能。 /// 获取或设置是否开通微信支付功能。
/// </summary> /// </summary>
[Newtonsoft.Json.JsonProperty("open_pay")] [Newtonsoft.Json.JsonProperty("open_pay")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.NumericalBooleanConverter))] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.NumericalBooleanConverter))]
[System.Text.Json.Serialization.JsonPropertyName("open_pay")] [System.Text.Json.Serialization.JsonPropertyName("open_pay")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.NumericalBooleanConverter))] [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.NumericalBooleanConverter))]
public bool IsOpenPay { get; set; } public bool IsOpenPay { get; set; }
/// <summary> /// <summary>
/// 获取或设置是否开通微信卡券功能。 /// 获取或设置是否开通微信卡券功能。
/// </summary> /// </summary>
[Newtonsoft.Json.JsonProperty("open_card")] [Newtonsoft.Json.JsonProperty("open_card")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.NumericalBooleanConverter))] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.NumericalBooleanConverter))]
[System.Text.Json.Serialization.JsonPropertyName("open_card")] [System.Text.Json.Serialization.JsonPropertyName("open_card")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.NumericalBooleanConverter))] [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.NumericalBooleanConverter))]
public bool IsOpenCard { get; set; } public bool IsOpenCard { get; set; }
/// <summary> /// <summary>
/// 获取或设置是否开通微信摇一摇功能。 /// 获取或设置是否开通微信摇一摇功能。
/// </summary> /// </summary>
[Newtonsoft.Json.JsonProperty("open_shake")] [Newtonsoft.Json.JsonProperty("open_shake")]
[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.NumericalBooleanConverter))] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.Common.NumericalBooleanConverter))]
[System.Text.Json.Serialization.JsonPropertyName("open_shake")] [System.Text.Json.Serialization.JsonPropertyName("open_shake")]
[System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Converters.NumericalBooleanConverter))] [System.Text.Json.Serialization.JsonConverter(typeof(System.Text.Json.Serialization.Common.NumericalBooleanConverter))]
public bool IsOpenShake { get; set; } public bool IsOpenShake { get; set; }
} }

View File

@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net461; netstandard2.0; net6.0</TargetFrameworks> <TargetFrameworks>net461; netstandard2.0; net6.0</TargetFrameworks>
<LangVersion>8.0</LangVersion> <LangVersion>10.0</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<NullableReferenceTypes>true</NullableReferenceTypes> <NullableReferenceTypes>true</NullableReferenceTypes>
</PropertyGroup> </PropertyGroup>
@@ -14,7 +14,7 @@
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat</PackageProjectUrl> <PackageProjectUrl>https://github.com/fudiwei/DotNetCore.SKIT.FlurlHttpClient.Wechat</PackageProjectUrl>
<PackageTags>Flurl.Http Wechat Weixin MicroMessage WechatAI WechatOpenAI WexinAI WeixinOpenAI 微信 微信智能对话 微信对话开放平台 微信智能对话开放平台 智能对话平台</PackageTags> <PackageTags>Flurl.Http Wechat Weixin MicroMessage WechatAI WechatOpenAI WexinAI WeixinOpenAI 微信 微信智能对话 微信对话开放平台 微信智能对话开放平台 智能对话平台</PackageTags>
<Version>2.0.1</Version> <Version>3.0.0-preview.1</Version>
<Description>基于 Flurl.Http 的微信对话开放平台(微信智能对话) API 客户端,支持智能对话接口、第三方客服接入、机器人配置、公众号/小程序/H5 绑定等功能。</Description> <Description>基于 Flurl.Http 的微信对话开放平台(微信智能对话) API 客户端,支持智能对话接口、第三方客服接入、机器人配置、公众号/小程序/H5 绑定等功能。</Description>
<Authors>Fu Diwei</Authors> <Authors>Fu Diwei</Authors>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
@@ -40,7 +40,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="SKIT.FlurlHttpClient.Common" Version="2.6.0" /> <PackageReference Include="SKIT.FlurlHttpClient.Common" Version="3.0.0-preview.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -21,7 +21,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Settings
internal Credentials(WechatOpenAIClientOptions options) internal Credentials(WechatOpenAIClientOptions options)
{ {
if (options == null) throw new ArgumentNullException(nameof(options)); if (options is null) throw new ArgumentNullException(nameof(options));
AppId = options.AppId; AppId = options.AppId;
Token = options.Token; Token = options.Token;

View File

@@ -1,84 +0,0 @@
using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Serialization;
using Newtonsoft.Json;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
{
internal static class XmlUtility
{
// REF: https://docs.microsoft.com/zh-cn/dotnet/api/system.xml.serialization.xmlserializer#dynamically-generated-assemblies
private static readonly Hashtable _xmlSerializers = new Hashtable();
private static readonly XmlRootAttribute _xmlRoot = new XmlRootAttribute("xml");
private static XmlSerializer GetTypedSerializer(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
string skey = type.AssemblyQualifiedName ?? type.GetHashCode().ToString();
XmlSerializer? xmlSerializer = (XmlSerializer?)_xmlSerializers[skey];
if (xmlSerializer == null)
{
xmlSerializer = new XmlSerializer(type, _xmlRoot);
_xmlSerializers[skey] = xmlSerializer;
}
return xmlSerializer;
}
public static string Serialize(Type type, object obj)
{
string xml;
var settings = new XmlWriterSettings();
settings.Encoding = Encoding.UTF8;
settings.Indent = false;
settings.OmitXmlDeclaration = true;
settings.WriteEndDocumentOnClose = false;
settings.NamespaceHandling = NamespaceHandling.OmitDuplicates;
using var stream = new MemoryStream();
using var writer = XmlWriter.Create(stream, settings);
XmlSerializer serializer = GetTypedSerializer(type);
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
serializer.Serialize(writer, obj, ns);
writer.Flush();
xml = Encoding.UTF8.GetString(stream.ToArray());
xml = Regex.Replace(xml, "\\s*<\\w+ ([a-zA-Z0-9]+):nil=\"true\"[^>]*/>", string.Empty, RegexOptions.IgnoreCase);
xml = Regex.Replace(xml, "<\\?xml[^>]*\\?>", string.Empty, RegexOptions.IgnoreCase);
return xml;
}
public static string Serialize<T>(T obj)
where T : class
{
return Serialize(typeof(T), obj);
}
public static object Deserialize(Type type, string xml)
{
using var reader = new StringReader(xml);
XmlSerializer serializer = GetTypedSerializer(type);
return serializer.Deserialize(reader)!;
}
public static T Deserialize<T>(string xml)
where T : class
{
return (T)Deserialize(typeof(T), xml);
}
public static string ConvertFromJson(string json)
{
XmlDocument xmlDocument = JsonConvert.DeserializeXmlNode(json, "xml")!;
string xml = xmlDocument.InnerXml;
return xml;
}
}
}

View File

@@ -16,7 +16,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
/// <returns>信息摘要字节数组。</returns> /// <returns>信息摘要字节数组。</returns>
public static byte[] Hash(byte[] bytes) public static byte[] Hash(byte[] bytes)
{ {
if (bytes == null) throw new ArgumentNullException(nameof(bytes)); if (bytes is null) throw new ArgumentNullException(nameof(bytes));
using SHA1 sha = SHA1.Create(); using SHA1 sha = SHA1.Create();
return sha.ComputeHash(bytes); return sha.ComputeHash(bytes);
@@ -29,7 +29,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
/// <returns>信息摘要。</returns> /// <returns>信息摘要。</returns>
public static string Hash(string message) public static string Hash(string message)
{ {
if (message == null) throw new ArgumentNullException(nameof(message)); if (message is null) throw new ArgumentNullException(nameof(message));
byte[] msgBytes = Encoding.UTF8.GetBytes(message); byte[] msgBytes = Encoding.UTF8.GetBytes(message);
byte[] hashBytes = Hash(msgBytes); byte[] hashBytes = Hash(msgBytes);

View File

@@ -60,7 +60,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
private static byte[] Decode2(byte[] decryptedBytes) private static byte[] Decode2(byte[] decryptedBytes)
{ {
if (decryptedBytes == null) throw new ArgumentNullException(nameof(decryptedBytes)); if (decryptedBytes is null) throw new ArgumentNullException(nameof(decryptedBytes));
int pad = (int)decryptedBytes[decryptedBytes.Length - 1]; int pad = (int)decryptedBytes[decryptedBytes.Length - 1];
if (pad < 1 || pad > 32) if (pad < 1 || pad > 32)
@@ -75,9 +75,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
private static byte[] AESDecrypt(byte[] keyBytes, byte[] ivBytes, byte[] ciperBytes) private static byte[] AESDecrypt(byte[] keyBytes, byte[] ivBytes, byte[] ciperBytes)
{ {
if (keyBytes == null) throw new ArgumentNullException(nameof(keyBytes)); if (keyBytes is null) throw new ArgumentNullException(nameof(keyBytes));
if (ivBytes == null) throw new ArgumentNullException(nameof(ivBytes)); if (ivBytes is null) throw new ArgumentNullException(nameof(ivBytes));
if (ciperBytes == null) throw new ArgumentNullException(nameof(ciperBytes)); if (ciperBytes is null) throw new ArgumentNullException(nameof(ciperBytes));
using var aes = Aes.Create(); using var aes = Aes.Create();
aes.KeySize = 256; aes.KeySize = 256;
@@ -103,9 +103,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
private static string AESEncrypt(byte[] keyBytes, byte[] ivBytes, byte[] plainBytes) private static string AESEncrypt(byte[] keyBytes, byte[] ivBytes, byte[] plainBytes)
{ {
if (keyBytes == null) throw new ArgumentNullException(nameof(keyBytes)); if (keyBytes is null) throw new ArgumentNullException(nameof(keyBytes));
if (ivBytes == null) throw new ArgumentNullException(nameof(ivBytes)); if (ivBytes is null) throw new ArgumentNullException(nameof(ivBytes));
if (plainBytes == null) throw new ArgumentNullException(nameof(plainBytes)); if (plainBytes is null) throw new ArgumentNullException(nameof(plainBytes));
using var aes = Aes.Create(); using var aes = Aes.Create();
aes.KeySize = AES_KEY_SIZE; aes.KeySize = AES_KEY_SIZE;
@@ -140,8 +140,8 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
/// <returns>解密后的文本内容。</returns> /// <returns>解密后的文本内容。</returns>
public static string AESDecrypt(string cipherText, string encodingAESKey, out string appId) public static string AESDecrypt(string cipherText, string encodingAESKey, out string appId)
{ {
if (cipherText == null) throw new ArgumentNullException(nameof(cipherText)); if (cipherText is null) throw new ArgumentNullException(nameof(cipherText));
if (encodingAESKey == null) throw new ArgumentNullException(nameof(encodingAESKey)); if (encodingAESKey is null) throw new ArgumentNullException(nameof(encodingAESKey));
byte[] cipherBytes = Convert.FromBase64String(cipherText); byte[] cipherBytes = Convert.FromBase64String(cipherText);
byte[] keyBytes = Convert.FromBase64String(encodingAESKey + "="); byte[] keyBytes = Convert.FromBase64String(encodingAESKey + "=");
@@ -170,9 +170,9 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
/// <returns>加密后的文本内容。</returns> /// <returns>加密后的文本内容。</returns>
public static string AESEncrypt(string plainText, string encodingAESKey, string appId) public static string AESEncrypt(string plainText, string encodingAESKey, string appId)
{ {
if (plainText == null) throw new ArgumentNullException(nameof(plainText)); if (plainText is null) throw new ArgumentNullException(nameof(plainText));
if (encodingAESKey == null) throw new ArgumentNullException(nameof(encodingAESKey)); if (encodingAESKey is null) throw new ArgumentNullException(nameof(encodingAESKey));
if (appId == null) throw new ArgumentNullException(nameof(appId)); if (appId is null) throw new ArgumentNullException(nameof(appId));
byte[] keyBytes = Convert.FromBase64String(encodingAESKey + "="); byte[] keyBytes = Convert.FromBase64String(encodingAESKey + "=");
byte[] ivBytes = new byte[16]; byte[] ivBytes = new byte[16];
@@ -204,11 +204,11 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
/// <returns>验证结果。</returns> /// <returns>验证结果。</returns>
public static bool VerifySignature(string sToken, string sTimestamp, string sNonce, string sMsgEncrypt, string sMsgSign) public static bool VerifySignature(string sToken, string sTimestamp, string sNonce, string sMsgEncrypt, string sMsgSign)
{ {
if (sToken == null) throw new ArgumentNullException(nameof(sToken)); if (sToken is null) throw new ArgumentNullException(nameof(sToken));
if (sTimestamp == null) throw new ArgumentNullException(nameof(sTimestamp)); if (sTimestamp is null) throw new ArgumentNullException(nameof(sTimestamp));
if (sNonce == null) throw new ArgumentNullException(nameof(sNonce)); if (sNonce is null) throw new ArgumentNullException(nameof(sNonce));
if (sMsgEncrypt == null) throw new ArgumentNullException(nameof(sMsgEncrypt)); if (sMsgEncrypt is null) throw new ArgumentNullException(nameof(sMsgEncrypt));
if (sMsgSign == null) throw new ArgumentNullException(nameof(sMsgSign)); if (sMsgSign is null) throw new ArgumentNullException(nameof(sMsgSign));
string expectedSign = GenerateSignature(sToken, sTimestamp, sNonce, sMsgEncrypt); string expectedSign = GenerateSignature(sToken, sTimestamp, sNonce, sMsgEncrypt);
return string.Equals(expectedSign, sMsgSign, StringComparison.OrdinalIgnoreCase); return string.Equals(expectedSign, sMsgSign, StringComparison.OrdinalIgnoreCase);
@@ -224,10 +224,10 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
/// <returns>签名。</returns> /// <returns>签名。</returns>
public static string GenerateSignature(string sToken, string sTimestamp, string sNonce, string sMsgEncrypt) public static string GenerateSignature(string sToken, string sTimestamp, string sNonce, string sMsgEncrypt)
{ {
if (sToken == null) throw new ArgumentNullException(nameof(sToken)); if (sToken is null) throw new ArgumentNullException(nameof(sToken));
if (sTimestamp == null) throw new ArgumentNullException(nameof(sTimestamp)); if (sTimestamp is null) throw new ArgumentNullException(nameof(sTimestamp));
if (sNonce == null) throw new ArgumentNullException(nameof(sNonce)); if (sNonce is null) throw new ArgumentNullException(nameof(sNonce));
if (sMsgEncrypt == null) throw new ArgumentNullException(nameof(sMsgEncrypt)); if (sMsgEncrypt is null) throw new ArgumentNullException(nameof(sMsgEncrypt));
List<string> tmp = new List<string>(capacity: 4) { sToken, sTimestamp, sNonce, sMsgEncrypt }; List<string> tmp = new List<string>(capacity: 4) { sToken, sTimestamp, sNonce, sMsgEncrypt };
tmp.Sort(StringComparer.Ordinal); tmp.Sort(StringComparer.Ordinal);
@@ -257,7 +257,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
/// <returns>指示是否是有效的 XML 内容。</returns> /// <returns>指示是否是有效的 XML 内容。</returns>
public static bool TryParseXml(string xml, out string? encryptedMsg, out string? toUserName) public static bool TryParseXml(string xml, out string? encryptedMsg, out string? toUserName)
{ {
if (xml == null) throw new ArgumentNullException(nameof(xml)); if (xml is null) throw new ArgumentNullException(nameof(xml));
encryptedMsg = null; encryptedMsg = null;
toUserName = null; toUserName = null;
@@ -269,7 +269,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
xmlDoc.LoadXml(xml); xmlDoc.LoadXml(xml);
XmlNode? xmlRoot = xmlDoc.FirstChild; XmlNode? xmlRoot = xmlDoc.FirstChild;
if (xmlRoot == null) if (xmlRoot is null)
return false; return false;
encryptedMsg = xmlRoot["Encrypt"]?.InnerText?.ToString(); encryptedMsg = xmlRoot["Encrypt"]?.InnerText?.ToString();
@@ -291,8 +291,8 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
/// <returns></returns> /// <returns></returns>
public static string WrapXml(string sToken, string sMsgEncrypt) public static string WrapXml(string sToken, string sMsgEncrypt)
{ {
if (sToken == null) throw new ArgumentNullException(nameof(sToken)); if (sToken is null) throw new ArgumentNullException(nameof(sToken));
if (sMsgEncrypt == null) throw new ArgumentNullException(nameof(sMsgEncrypt)); if (sMsgEncrypt is null) throw new ArgumentNullException(nameof(sMsgEncrypt));
string sTimestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString(); string sTimestamp = DateTimeOffset.Now.ToLocalTime().ToUnixTimeSeconds().ToString();
string sNonce = DateTimeOffset.Now.Ticks.ToString("x"); string sNonce = DateTimeOffset.Now.Ticks.ToString("x");
@@ -310,10 +310,10 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
/// <returns></returns> /// <returns></returns>
public static string WrapXml(string sTimestamp, string sNonce, string sMsgEncrypt, string sMsgSign) public static string WrapXml(string sTimestamp, string sNonce, string sMsgEncrypt, string sMsgSign)
{ {
if (sTimestamp == null) throw new ArgumentNullException(nameof(sTimestamp)); if (sTimestamp is null) throw new ArgumentNullException(nameof(sTimestamp));
if (sNonce == null) throw new ArgumentNullException(nameof(sNonce)); if (sNonce is null) throw new ArgumentNullException(nameof(sNonce));
if (sMsgEncrypt == null) throw new ArgumentNullException(nameof(sMsgEncrypt)); if (sMsgEncrypt is null) throw new ArgumentNullException(nameof(sMsgEncrypt));
if (sMsgSign == null) throw new ArgumentNullException(nameof(sMsgSign)); if (sMsgSign is null) throw new ArgumentNullException(nameof(sMsgSign));
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.AppendFormat("<xml>"); builder.AppendFormat("<xml>");

View File

@@ -0,0 +1,40 @@
using System;
using System.Xml;
using Newtonsoft.Json;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
{
using SKIT.FlurlHttpClient.Internal;
internal static class XmlHelper
{
public static string Serialize(object obj, Type type)
{
return _XmlSimpleSerializer.Serialize(obj, type);
}
public static string Serialize<T>(T obj)
where T : class
{
return Serialize(obj, typeof(T));
}
public static object Deserialize(string xml, Type type)
{
return _XmlSimpleSerializer.Deserialize(xml, type);
}
public static T Deserialize<T>(string xml)
where T : class
{
return (T)Deserialize(xml, typeof(T));
}
public static string ConvertFromJson(string json)
{
XmlDocument xmlDocument = JsonConvert.DeserializeXmlNode(json, "xml")!;
string xml = xmlDocument.InnerXml;
return xml;
}
}
}

View File

@@ -21,42 +21,37 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
/// </summary> /// </summary>
/// <param name="options">配置项。</param> /// <param name="options">配置项。</param>
public WechatOpenAIClient(WechatOpenAIClientOptions options) public WechatOpenAIClient(WechatOpenAIClientOptions options)
: base() : this(options, null)
{ {
if (options == null) throw new ArgumentNullException(nameof(options)); }
/// <summary>
///
/// </summary>
/// <param name="options"></param>
/// <param name="httpClient"></param>
/// <param name="disposeClient"></param>
internal protected WechatOpenAIClient(WechatOpenAIClientOptions options, HttpClient? httpClient, bool disposeClient = true)
: base(httpClient, disposeClient)
{
if (options is null) throw new ArgumentNullException(nameof(options));
Credentials = new Settings.Credentials(options); Credentials = new Settings.Credentials(options);
FlurlClient.BaseUrl = options.Endpoint ?? WechatOpenAIEndpoints.DEFAULT; FlurlClient.BaseUrl = options.Endpoint ?? WechatOpenAIEndpoints.DEFAULT;
FlurlClient.WithTimeout(TimeSpan.FromMilliseconds(options.Timeout)); FlurlClient.WithTimeout(options.Timeout <= 0 ? Timeout.InfiniteTimeSpan : TimeSpan.FromMilliseconds(options.Timeout));
}
/// <summary>
/// 用指定的微信智能对话 AppId、Token、EncodingAESKey 初始化 <see cref="WechatOpenAIThirdPartyClient"/> 类的新实例。
/// </summary>
/// <param name="appId">微信智能对话 AppId。</param>
/// <param name="token">微信智能对话 Token。</param>
/// <param name="encodingAESKey">微信智能对话 EncodingAESKey。</param>
public WechatOpenAIClient(string appId, string token, string encodingAESKey)
: this(new WechatOpenAIClientOptions() { AppId = appId, Token = token, EncodingAESKey = encodingAESKey })
{
} }
/// <summary> /// <summary>
/// 使用当前客户端生成一个新的 <see cref="IFlurlRequest"/> 对象。 /// 使用当前客户端生成一个新的 <see cref="IFlurlRequest"/> 对象。
/// </summary> /// </summary>
/// <param name="request"></param> /// <param name="request"></param>
/// <param name="method"></param> /// <param name="httpMethod"></param>
/// <param name="urlSegments"></param> /// <param name="urlSegments"></param>
/// <returns></returns> /// <returns></returns>
public IFlurlRequest CreateRequest(WechatOpenAIRequest request, HttpMethod method, params object[] urlSegments) public IFlurlRequest CreateFlurlRequest(WechatOpenAIRequest request, HttpMethod httpMethod, params object[] urlSegments)
{ {
IFlurlRequest flurlRequest = FlurlClient.Request(urlSegments).WithVerb(method); IFlurlRequest flurlRequest = base.CreateFlurlRequest(request, httpMethod, urlSegments);
if (request.Timeout != null)
{
flurlRequest.WithTimeout(TimeSpan.FromMilliseconds(request.Timeout.Value));
}
return flurlRequest; return flurlRequest;
} }
@@ -69,20 +64,13 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
/// <param name="httpContent"></param> /// <param name="httpContent"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public async Task<T> SendRequestAsync<T>(IFlurlRequest flurlRequest, HttpContent? httpContent = null, CancellationToken cancellationToken = default) public async Task<T> SendFlurlRequestAsync<T>(IFlurlRequest flurlRequest, HttpContent? httpContent = null, CancellationToken cancellationToken = default)
where T : WechatOpenAIResponse, new() where T : WechatOpenAIResponse, new()
{ {
if (flurlRequest == null) throw new ArgumentNullException(nameof(flurlRequest)); if (flurlRequest is null) throw new ArgumentNullException(nameof(flurlRequest));
try using IFlurlResponse flurlResponse = await base.SendFlurlRequestAsync(flurlRequest, httpContent, cancellationToken);
{ return await WrapFlurlResponseAsJsonAsync<T>(flurlResponse, cancellationToken);
using IFlurlResponse flurlResponse = await base.SendRequestAsync(flurlRequest, httpContent, cancellationToken);
return await WrapResponseWithJsonAsync<T>(flurlResponse, cancellationToken);
}
catch (FlurlHttpException ex)
{
throw new WechatOpenAIException(ex.Message, ex);
}
} }
/// <summary> /// <summary>
@@ -93,37 +81,26 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
/// <param name="data"></param> /// <param name="data"></param>
/// <param name="cancellationToken"></param> /// <param name="cancellationToken"></param>
/// <returns></returns> /// <returns></returns>
public async Task<T> SendRequestWithJsonAsync<T>(IFlurlRequest flurlRequest, object? data = null, CancellationToken cancellationToken = default) public async Task<T> SendFlurlRequestAsJsonAsync<T>(IFlurlRequest flurlRequest, object? data = null, CancellationToken cancellationToken = default)
where T : WechatOpenAIResponse, new() where T : WechatOpenAIResponse, new()
{ {
if (flurlRequest == null) throw new ArgumentNullException(nameof(flurlRequest)); if (flurlRequest is null) throw new ArgumentNullException(nameof(flurlRequest));
try if (data is WechatOpenAIRequest.Serialization.IEncryptedXmlable)
{ {
if (data is WechatOpenAIRequest.Serialization.IEncryptedXmlable) string plainXml = Utilities.XmlHelper.ConvertFromJson(JsonSerializer.Serialize(data));
{ string encryptedXml = Utilities.WxMsgCryptor.AESEncrypt(plainText: plainXml, encodingAESKey: Credentials.EncodingAESKey!, appId: Credentials.AppId!);
string plainXml = Utilities.XmlUtility.ConvertFromJson(JsonSerializer.Serialize(data)); data = new { encrypt = encryptedXml };
string encryptedXml = Utilities.WxMsgCryptor.AESEncrypt(plainText: plainXml, encodingAESKey: Credentials.EncodingAESKey!, appId: Credentials.AppId!); }
data = new { encrypt = encryptedXml };
}
bool isSimpleRequest = data == null || bool isSimpleRequest = data is null ||
flurlRequest.Verb == HttpMethod.Get || flurlRequest.Verb == HttpMethod.Get ||
flurlRequest.Verb == HttpMethod.Head || flurlRequest.Verb == HttpMethod.Head ||
flurlRequest.Verb == HttpMethod.Options; flurlRequest.Verb == HttpMethod.Options;
using IFlurlResponse flurlResponse = isSimpleRequest ? using IFlurlResponse flurlResponse = isSimpleRequest ?
await base.SendRequestAsync(flurlRequest, null, cancellationToken) : await base.SendFlurlRequestAsync(flurlRequest, null, cancellationToken) :
await base.SendRequestWithJsonAsync(flurlRequest, data, cancellationToken); await base.SendFlurlRequestAsJsonAsync(flurlRequest, data, cancellationToken);
return await WrapResponseWithJsonAsync<T>(flurlResponse, cancellationToken); return await WrapFlurlResponseAsJsonAsync<T>(flurlResponse, cancellationToken);
}
catch (FlurlHttpTimeoutException ex)
{
throw new Exceptions.WechatOpenAIRequestTimeoutException(ex.Message, ex);
}
catch (FlurlHttpException ex)
{
throw new WechatOpenAIException(ex.Message, ex);
}
} }
} }
} }

View File

@@ -1,38 +1,27 @@
using System;
using System.Xml.Serialization;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI namespace SKIT.FlurlHttpClient.Wechat.OpenAI
{ {
/// <summary> /// <summary>
/// 表示微信智能对话 API 回调通知事件的基类。 /// 表示微信智能对话 API 回调通知事件的基类。
/// </summary> /// </summary>
[Serializable] [System.Xml.Serialization.XmlRoot("xml")]
public class WechatOpenAIEvent public class WechatOpenAIEvent : ICommonWebhookEvent
{ {
public static class Serialization
{
[XmlRoot("xml")]
public interface IXmlSerializable
{
}
}
/// <summary> /// <summary>
/// 获取或设置 AppId。 /// 获取或设置 AppId。
/// </summary> /// </summary>
[XmlElement("appid", IsNullable = true)] [System.Xml.Serialization.XmlElement("appid", IsNullable = true)]
public string? AppId { get; set; } public string? AppId { get; set; }
/// <summary> /// <summary>
/// 获取或设置事件类型。 /// 获取或设置事件类型。
/// </summary> /// </summary>
[XmlElement("event", IsNullable = true)] [System.Xml.Serialization.XmlElement("event", IsNullable = true)]
public string? Event { get; set; } public string? Event { get; set; }
/// <summary> /// <summary>
/// 获取或设置消息创建时间戳。 /// 获取或设置消息创建时间戳。
/// </summary> /// </summary>
[XmlElement("createtime", IsNullable = true)] [System.Xml.Serialization.XmlElement("createtime", IsNullable = true)]
public long? CreateTimestamp { get; set; } public long? CreateTimestamp { get; set; }
} }
} }

View File

@@ -1,11 +1,11 @@
using System; using System;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI namespace SKIT.FlurlHttpClient.Wechat.OpenAI
{ {
/// <summary> /// <summary>
/// 当调用微信智能对话 API 出错时引发的异常。 /// 当调用微信智能对话 API 出错时引发的异常。
/// </summary> /// </summary>
public class WechatOpenAIException : CommonExceptionBase public class WechatOpenAIException : CommonException
{ {
/// <inheritdoc/> /// <inheritdoc/>
public WechatOpenAIException() public WechatOpenAIException()

View File

@@ -3,7 +3,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
/// <summary> /// <summary>
/// 表示微信智能对话 API 请求的基类。 /// 表示微信智能对话 API 请求的基类。
/// </summary> /// </summary>
public abstract class WechatOpenAIRequest : ICommonRequest public abstract class WechatOpenAIRequest : CommonRequestBase, ICommonRequest
{ {
public static class Serialization public static class Serialization
{ {
@@ -11,14 +11,5 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
{ {
} }
} }
/// <summary>
/// 获取或设置请求超时时间(单位:毫秒)。如果不指定将使用构造 <see cref="WechatOpenAIClient"/> 时的 <see cref="WechatOpenAIClientOptions.Timeout"/> 参数,这在需要指定特定耗时请求(比如上传或下载文件)的超时时间时很有用。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
[System.Xml.Serialization.XmlIgnore]
[System.Xml.Serialization.SoapIgnore]
public virtual int? Timeout { get; set; }
} }
} }

View File

@@ -1,60 +1,10 @@
using System.Collections.Generic;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI namespace SKIT.FlurlHttpClient.Wechat.OpenAI
{ {
/// <summary> /// <summary>
/// 表示微信智能对话 API 响应的基类。 /// 表示微信智能对话 API 响应的基类。
/// </summary> /// </summary>
public abstract class WechatOpenAIResponse : ICommonResponse public abstract class WechatOpenAIResponse : CommonResponseBase, ICommonResponse
{ {
/// <summary>
///
/// </summary>
int ICommonResponse.RawStatus { get; set; }
/// <summary>
///
/// </summary>
IDictionary<string, string> ICommonResponse.RawHeaders { get; set; } = default!;
/// <summary>
///
/// </summary>
byte[] ICommonResponse.RawBytes { get; set; } = default!;
/// <summary>
/// 获取原始的 HTTP 响应状态码。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public int RawStatus
{
get { return ((ICommonResponse)this).RawStatus; }
internal set { ((ICommonResponse)this).RawStatus = value; }
}
/// <summary>
/// 获取原始的 HTTP 响应表头集合。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public IDictionary<string, string> RawHeaders
{
get { return ((ICommonResponse)this).RawHeaders; }
internal set { ((ICommonResponse)this).RawHeaders = value; }
}
/// <summary>
/// 获取原始的 HTTP 响应正文。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public byte[] RawBytes
{
get { return ((ICommonResponse)this).RawBytes; }
internal set { ((ICommonResponse)this).RawBytes = value; }
}
/// <summary> /// <summary>
/// 获取微信智能对话 API 返回的错误码。 /// 获取微信智能对话 API 返回的错误码。
/// </summary> /// </summary>
@@ -84,12 +34,15 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
public virtual string? ReturnError { get; set; } public virtual string? ReturnError { get; set; }
/// <summary> /// <summary>
/// 获取一个值,该值指示调用微信 API 是否成功(即 HTTP 状态码为 200、且 errcode/ret 值都为 0 /// 获取一个值,该值指示调用微信 API 是否成功。
/// <para>
/// (即 HTTP 状态码为 200且 <see cref="ErrorCode"/>、<see cref="ReturnCode"/> 值都为 0
/// </para>
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public virtual bool IsSuccessful() public override bool IsSuccessful()
{ {
return RawStatus == 200 && ErrorCode.GetValueOrDefault() == 0 && ReturnCode.GetValueOrDefault() == 0 && string.IsNullOrEmpty(ReturnError); return GetRawStatus() == 200 && ErrorCode.GetValueOrDefault() == 0 && ReturnCode.GetValueOrDefault() == 0 && string.IsNullOrEmpty(ReturnError);
} }
} }

View File

@@ -0,0 +1,56 @@
using System;
using System.IO;
using System.Reflection;
using SKIT.FlurlHttpClient.Tools.CodeAnalyzer;
using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests
{
public class CodeAnalyzeTests
{
[Fact(DisplayName = "代码质量分析")]
public void CodeAnalyze()
{
Assert.Null(Record.Exception(() =>
{
var options = new TypeDeclarationAnalyzerOptions()
{
SdkAssembly = Assembly.GetAssembly(typeof(WechatOpenAIClient))!,
SdkRequestModelDeclarationNamespace = "SKIT.FlurlHttpClient.Wechat.OpenAI.Models",
SdkResponseModelDeclarationNamespace = "SKIT.FlurlHttpClient.Wechat.OpenAI.Models",
SdkExecutingExtensionDeclarationNamespace = "SKIT.FlurlHttpClient.Wechat.OpenAI",
SdkWebhookEventDeclarationNamespace = "SKIT.FlurlHttpClient.Wechat.OpenAI.Events",
ThrowOnNotFoundRequestModelTypes = true,
ThrowOnNotFoundResponseModelTypes = true,
ThrowOnNotFoundExecutingExtensionTypes = true,
ThrowOnNotFoundWebhookEventTypes = true
};
new TypeDeclarationAnalyzer(options).AssertNoIssues();
}));
Assert.Null(Record.Exception(() =>
{
string workdir = Environment.CurrentDirectory;
string projdir = Path.Combine(workdir, "../../../../../");
var options = new SourceFileAnalyzerOptions()
{
SdkAssembly = Assembly.GetAssembly(typeof(WechatOpenAIClient))!,
SdkRequestModelDeclarationNamespace = "SKIT.FlurlHttpClient.Wechat.OpenAI.Models",
SdkResponseModelDeclarationNamespace = "SKIT.FlurlHttpClient.Wechat.OpenAI.Models",
SdkWebhookEventDeclarationNamespace = "SKIT.FlurlHttpClient.Wechat.OpenAI.Events",
ProjectSourceRootDirectory = Path.Combine(projdir, "./src/SKIT.FlurlHttpClient.Wechat.OpenAI/"),
ProjectTestRootDirectory = Path.Combine(projdir, "./test/SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests/"),
ThrowOnNotFoundRequestModelClassCodeFiles = true,
ThrowOnNotFoundResponseModelClassCodeFiles = true,
ThrowOnNotFoundExecutingExtensionClassCodeFiles = true,
ThrowOnNotFoundWebhookEventClassCodeFiles = true,
ThrowOnNotFoundRequestModelSerializationSampleFiles = true,
ThrowOnNotFoundResponseModelSerializationSampleFiles = true,
ThrowOnNotFoundWebhookEventSerializationSampleFiles = true
};
new SourceFileAnalyzer(options).AssertNoIssues();
}));
}
}
}

View File

@@ -10,23 +10,23 @@
<ItemGroup> <ItemGroup>
<None Remove=".gitignore" /> <None Remove=".gitignore" />
<Content Include="appsettings.json"> <Content Include="appsettings.json">
<CopyToOutputDirectory>Never</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content> </Content>
<Content Include="appsettings.*.json" Condition="'$(Configuration)' == 'Debug'"> <Content Include="appsettings.*.json" Condition="'$(Configuration)' == 'Debug'">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> <CopyToPublishDirectory>Always</CopyToPublishDirectory>
</Content> </Content>
<Content Include="ModelSamples/**/*.json" /> <Content Include="ModelSamples/**/*.json" />
<Content Include="EventSamples/**/*.xml" /> <Content Include="EventSamples/**/*.xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="SKIT.FlurlHttpClient.Tools.CodeAnalyzer" Version="0.1.0-alpha.1" /> <PackageReference Include="SKIT.FlurlHttpClient.Tools.CodeAnalyzer" Version="0.3.0-preview.1" />
<PackageReference Include="xunit" Version="2.4.2" /> <PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5"> <PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@@ -1,28 +0,0 @@
using SKIT.FlurlHttpClient.Tools.CodeAnalyzer;
using Xunit;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests
{
public class TestCase_CodeReview
{
[Fact(DisplayName = "测试用例:代码质量分析")]
public void TestCodeAnalyzer()
{
Assert.Null(Record.Exception(() =>
{
CodeAnalyzerOptions options = new CodeAnalyzerOptions()
{
AssemblyName = "SKIT.FlurlHttpClient.Wechat.OpenAI",
WorkDirectoryForSourceCode = TestConfigs.WorkDirectoryForSdk,
WorkDirectoryForTestSample = TestConfigs.WorkDirectoryForTest,
AllowNotFoundEventTypes = true,
AllowNotFoundEventSamples = true
};
CodeAnalyzer analyzer = new CodeAnalyzer(options);
analyzer.Start();
analyzer.Assert();
analyzer.Flush();
}));
}
}
}

View File

@@ -17,14 +17,11 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests
using var stream = File.OpenRead("appsettings.local.json"); using var stream = File.OpenRead("appsettings.local.json");
using var jdoc = JsonDocument.Parse(stream); using var jdoc = JsonDocument.Parse(stream);
var config = jdoc.RootElement.GetProperty("TestConfig"); var config = jdoc.RootElement.GetProperty("TestConfigs");
WechatAppId = config.GetProperty("AppId").GetString()!; WechatAppId = config.GetProperty("AppId").GetString()!;
WechatToken = config.GetProperty("Token").GetString()!; WechatToken = config.GetProperty("Token").GetString()!;
WechatEncodingAESKey = config.GetProperty("EncodingAESKey").GetString()!; WechatEncodingAESKey = config.GetProperty("EncodingAESKey").GetString()!;
WechatAccessToken = config.GetProperty("AccessToken").GetString()!; WechatAccessToken = config.GetProperty("AccessToken").GetString()!;
WorkDirectoryForSdk = jdoc.RootElement.GetProperty("WorkDirectoryForSdk").GetString()!;
WorkDirectoryForTest = jdoc.RootElement.GetProperty("WorkDirectoryForTest").GetString()!;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -36,8 +33,5 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests
public static readonly string WechatToken; public static readonly string WechatToken;
public static readonly string WechatEncodingAESKey; public static readonly string WechatEncodingAESKey;
public static readonly string WechatAccessToken; public static readonly string WechatAccessToken;
public static readonly string WorkDirectoryForSdk;
public static readonly string WorkDirectoryForTest;
} }
} }

View File

@@ -1,10 +1,8 @@
{ {
"TestConfig": { "TestConfigs": {
"AppId": "请在此填写用于测试的微信智能对话 AppId", "AppId": "请在此填写用于测试的微信智能对话 AppId",
"Token": "请在此填写用于测试的微信智能对话 Token", "Token": "请在此填写用于测试的微信智能对话 Token",
"EncodingAESKey": "请在此填写用于测试的微信智能对话 EncodingAESKey", "EncodingAESKey": "请在此填写用于测试的微信智能对话 EncodingAESKey",
"AccessToken": "请在此填写用于测试的微信智能对话 AccessToken" "AccessToken": "请在此填写用于测试的微信智能对话 AccessToken"
}, }
"WorkDirectoryForSdk": "请输入当前 SDK 项目所在的目录完整路径,如 C:\\Project\\src\\SKIT.FlurlHttpClient.Wechat.OpenAI\\",
"WorkDirectoryForTest": "请输入当前测试项目所在的目录完整路径,如 C:\\Project\\test\\SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests\\"
} }