feat(openai): 新增 NLP 相关接口

This commit is contained in:
Fu Diwei
2021-10-11 18:34:21 +08:00
parent 38f05bc467
commit 592e4e3587
38 changed files with 1617 additions and 42 deletions

View File

@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("SKIT.FlurlHttpClient.Wechat.OpenAI.UnitTests")]

View File

@@ -43,7 +43,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (!Utilities.WxBizMsgCryptor.TryParseXml(callbackXml, out string? encryptedXml))
throw new Exceptions.WechatOpenAIEventSerializationException("Encrypt event failed, because of empty encrypted data.");
callbackXml = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText: encryptedXml!, encodingAESKey: client.Credentials.PushEncodingAESKey!, out _);
callbackXml = Utilities.WxBizMsgCryptor.AESDecrypt(cipherText: encryptedXml!, encodingAESKey: client.Credentials.EncodingAESKey!, out _);
using var reader = new StringReader(callbackXml);
@@ -106,20 +106,20 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
}
if (string.IsNullOrEmpty(client.Credentials.PushEncodingAESKey))
if (string.IsNullOrEmpty(client.Credentials.EncodingAESKey))
throw new Exceptions.WechatOpenAIEventSerializationException("Encrypt event failed, because there is no encoding AES key.");
if (string.IsNullOrEmpty(client.Credentials.PushToken))
if (string.IsNullOrEmpty(client.Credentials.Token))
throw new Exceptions.WechatOpenAIEventSerializationException("Encrypt event failed, because there is no token.");
try
{
string cipher = Utilities.WxBizMsgCryptor.AESEncrypt(
plainText: xml,
encodingAESKey: client.Credentials.PushEncodingAESKey!,
encodingAESKey: client.Credentials.EncodingAESKey!,
appId: client.Credentials.AppId!
);
xml = Utilities.WxBizMsgCryptor.WrapXml(sToken: client.Credentials.PushToken!, sMsgEncrypt: cipher);
xml = Utilities.WxBizMsgCryptor.WrapXml(sToken: client.Credentials.Token!, sMsgEncrypt: cipher);
}
catch (Exception ex)
{

View File

@@ -22,7 +22,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "batchimportskill", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "batchimportskill", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiBatchImportSkillResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -41,7 +41,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "publish", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "publish", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiPublishResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -60,7 +60,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "publish_progress", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "publish_progress", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiPublishProgressResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -80,7 +80,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "setautoreply", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "setautoreply", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiSetAutoReplyResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -99,7 +99,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "label", "batchset", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "label", "batchset", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiLabelBatchSetResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}

View File

@@ -22,7 +22,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "batchreply", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "batchreply", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiBatchReplyResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -41,7 +41,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "generatereport", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "generatereport", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiGenerateReportResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}

View File

@@ -25,7 +25,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "getbindlink", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "getbindlink", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiGetBindLinkResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -44,7 +44,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "getbindlist", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "getbindlist", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiGetBindListResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -63,7 +63,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "unbindmp", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "unbindmp", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiUnbindMpResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -82,7 +82,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "geth5link", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "geth5link", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiGetH5LinkResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -108,13 +108,13 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
request.FileContentType = "image/jpeg";
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "assetsupload", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "assetsupload", client.Credentials.Token!);
using var fileContent = new ByteArrayContent(request.FileBytes ?? new byte[0]);
using var paramContent = new StringContent(
Utilities.WxBizMsgCryptor.AESEncrypt(
plainText: Utilities.XmlUtility.Serialize(request),
encodingAESKey: client.Credentials.PushEncodingAESKey!,
encodingAESKey: client.Credentials.EncodingAESKey!,
appId: client.Credentials.AppId!
),
Encoding.UTF8

View File

@@ -0,0 +1,106 @@
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Flurl.Http;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI
{
public static class WechatOpenAIClientExecuteOpenApiNLPExtensions
{
/// <summary>
/// <para>异步调用 [POST] /openapi/nlp/tokenize/{TOKEN} 接口。</para>
/// <para>REF: https://developers.weixin.qq.com/doc/aispeech/platform/nlp/tokenize.html </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.OpenApiNLPTokenizeResponse> ExecuteOpenApiNLPTokenizeAsync(this WechatOpenAIClient client, Models.OpenApiNLPTokenizeRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "nlp", "tokenize", client.Credentials.Token!);
return await client.SendRequestWithUrlEncodedAsync<Models.OpenApiNLPTokenizeResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
/// <summary>
/// <para>异步调用 [POST] /openapi/nlp/ner/{TOKEN} 接口。</para>
/// <para>REF: https://developers.weixin.qq.com/doc/aispeech/platform/nlp/ner.html </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.OpenApiNLPNERResponse> ExecuteOpenApiNLPNERAsync(this WechatOpenAIClient client, Models.OpenApiNLPNERRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "nlp", "ner", client.Credentials.Token!);
return await client.SendRequestWithUrlEncodedAsync<Models.OpenApiNLPNERResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
/// <summary>
/// <para>异步调用 [POST] /openapi/nlp/sentiment/{TOKEN} 接口。</para>
/// <para>REF: https://developers.weixin.qq.com/doc/aispeech/platform/nlp/sentiment.html </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.OpenApiNLPSentimentResponse> ExecuteOpenApiNLPSentimentAsync(this WechatOpenAIClient client, Models.OpenApiNLPSentimentRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "nlp", "sentiment", client.Credentials.Token!);
return await client.SendRequestWithUrlEncodedAsync<Models.OpenApiNLPSentimentResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
/// <summary>
/// <para>异步调用 [POST] /openapi/nlp/ner-product/{TOKEN} 接口。</para>
/// <para>REF: https://developers.weixin.qq.com/doc/aispeech/platform/nlp/nerproduct.html </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.OpenApiNLPNERProductResponse> ExecuteOpenApiNLPNERProductAsync(this WechatOpenAIClient client, Models.OpenApiNLPNERProductRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "nlp", "ner-product", client.Credentials.Token!);
return await client.SendRequestWithUrlEncodedAsync<Models.OpenApiNLPNERProductResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
/// <summary>
/// <para>异步调用 [POST] /openapi/nlp/sensitive/{TOKEN} 接口。</para>
/// <para>REF: https://developers.weixin.qq.com/doc/aispeech/platform/nlp/sensitive.html </para>
/// </summary>
/// <param name="client"></param>
/// <param name="request"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public static async Task<Models.OpenApiNLPSensitiveResponse> ExecuteOpenApiNLPSensitiveAsync(this WechatOpenAIClient client, Models.OpenApiNLPSensitiveRequest request, CancellationToken cancellationToken = default)
{
if (client is null) throw new ArgumentNullException(nameof(client));
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "nlp", "sensitive", client.Credentials.Token!);
return await client.SendRequestWithUrlEncodedAsync<Models.OpenApiNLPSensitiveResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
}
}

View File

@@ -22,7 +22,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "sign", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "sign", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiSignResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -41,7 +41,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "aibot", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "aibot", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiAIBotResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -60,7 +60,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (request is null) throw new ArgumentNullException(nameof(request));
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "gethotquerylist", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "gethotquerylist", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiGetHotQueryListResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}

View File

@@ -26,7 +26,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
request.AppId = client.Credentials.AppId;
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "sendmsg", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "sendmsg", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiSendMessageResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -48,7 +48,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
request.AppId = client.Credentials.AppId;
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "kefustate", "get", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "kefustate", "get", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiKefuStateGetResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}
@@ -70,7 +70,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
request.AppId = client.Credentials.AppId;
IFlurlRequest flurlReq = client
.CreateRequest(request, HttpMethod.Post, "openapi", "kefustate", "change", client.Credentials.PushToken!);
.CreateRequest(request, HttpMethod.Post, "openapi", "kefustate", "change", client.Credentials.Token!);
return await client.SendRequestWithJsonAsync<Models.OpenApiKefuStateChangeResponse>(flurlReq, data: request, cancellationToken: cancellationToken);
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
{
/// <summary>
/// <para>表示 [POST] /openapi/nlp/ner-product/{TOKEN} 接口的请求。</para>
/// </summary>
public class OpenApiNLPNERProductRequest : WechatOpenAIRequest, WechatOpenAIRequest.Serialization.IEncryptedUrlEncodedFormData
{
public static class Types
{
public class Data
{
/// <summary>
/// 获取或设置输入文本。
/// </summary>
[Newtonsoft.Json.JsonProperty("q")]
[System.Text.Json.Serialization.JsonPropertyName("q")]
public string QueryString { get; set; } = string.Empty;
}
}
/// <summary>
/// 获取或设置用户 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("uid")]
[System.Text.Json.Serialization.JsonPropertyName("uid")]
public string UserId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置请求数据。
/// </summary>
[Newtonsoft.Json.JsonProperty("data")]
[System.Text.Json.Serialization.JsonPropertyName("data")]
public Types.Data Data { get; set; } = new Types.Data();
}
}

View File

@@ -0,0 +1,264 @@
using System;
using System.Collections.Generic;
using System.Linq;
/* @codestyle-disable no-instantiated-property-in-response */
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
{
/// <summary>
/// <para>表示 [POST] /openapi/nlp/ner-product/{TOKEN} 接口的响应。</para>
/// </summary>
public class OpenApiNLPNERProductResponse : WechatOpenAIResponse<OpenApiNLPNERProductResponse.Types.Data>
{
public static class Types
{
public class Data
{
public static class Types
{
public class Result
{
public static class Types
{
public class ProductProperty
{
/// <summary>
/// 获取或设置商品属性名。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string Name { get; set; } = default!;
/// <summary>
/// 获取或设置商品属性值。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string Value { get; set; } = default!;
/// <summary>
/// 获取或设置起始字符位置。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public int StartIndex { get; set; }
/// <summary>
/// 获取或设置结束字符位置。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public int EndIndex { get; set; }
}
}
/// <summary>
/// 获取或设置结果。
/// </summary>
[Newtonsoft.Json.JsonProperty("product")]
[Newtonsoft.Json.JsonConverter(typeof(Converters.NewtonsoftJsonProductPropertyArrayConverter))]
[System.Text.Json.Serialization.JsonPropertyName("product")]
[System.Text.Json.Serialization.JsonConverter(typeof(Converters.SystemTextJsonProductPropertyArrayConverter))]
public Types.ProductProperty[] ProductPropertyList { get; set; } = default!;
}
}
/// <summary>
/// 获取或设置预处理后的文本。
/// </summary>
[Newtonsoft.Json.JsonProperty("preprocessed_text")]
[System.Text.Json.Serialization.JsonPropertyName("preprocessed_text")]
public string PreprocessedText { get; set; } = default!;
/// <summary>
/// 获取或设置抽取结果信息。
/// </summary>
[Newtonsoft.Json.JsonProperty("entities")]
[Newtonsoft.Json.JsonConverter(typeof(Converters.NewtonsoftJsonProductPropertyArrayConverter))]
[System.Text.Json.Serialization.JsonPropertyName("entities")]
[System.Text.Json.Serialization.JsonConverter(typeof(Converters.SystemTextJsonProductPropertyArrayConverter))]
public Types.Result Result { get; set; } = default!;
}
}
internal static class Converters
{
internal class NewtonsoftJsonProductPropertyArrayConverter : Newtonsoft.Json.JsonConverter<Types.Data.Types.Result.Types.ProductProperty[]?>
{
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override Types.Data.Types.Result.Types.ProductProperty[]? ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, Types.Data.Types.Result.Types.ProductProperty[]? existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
{
if (reader.TokenType == Newtonsoft.Json.JsonToken.Null)
{
return existingValue;
}
else if (reader.TokenType == Newtonsoft.Json.JsonToken.StartArray)
{
reader.Read();
var tmpList = new List<Types.Data.Types.Result.Types.ProductProperty>();
while (reader.TokenType != Newtonsoft.Json.JsonToken.EndArray)
{
if (reader.TokenType == Newtonsoft.Json.JsonToken.StartArray)
{
reader.Read();
int offset = 0;
var tmpItem = new Types.Data.Types.Result.Types.ProductProperty();
while (reader.TokenType != Newtonsoft.Json.JsonToken.EndArray)
{
if (offset == 0)
{
tmpItem.Value = serializer.Deserialize<string>(reader)!;
}
else if (offset == 1)
{
tmpItem.Name = serializer.Deserialize<string>(reader)!;
}
else if (offset == 2)
{
tmpItem.StartIndex = serializer.Deserialize<int>(reader);
}
else if (offset == 3)
{
tmpItem.EndIndex = serializer.Deserialize<int>(reader);
}
offset++;
reader.Read();
}
tmpList.Add(tmpItem);
}
reader.Read();
}
return tmpList.ToArray();
}
throw new Newtonsoft.Json.JsonReaderException();
}
public override void WriteJson(Newtonsoft.Json.JsonWriter writer, Types.Data.Types.Result.Types.ProductProperty[]? value, Newtonsoft.Json.JsonSerializer serializer)
{
if (value != null)
{
writer.WriteStartArray();
foreach (var item in value)
{
writer.WriteStartArray();
writer.WriteValue(item.Value);
writer.WriteValue(item.Name);
writer.WriteValue(item.StartIndex);
writer.WriteValue(item.EndIndex);
writer.WriteEndArray();
}
writer.WriteEndArray();
}
else
{
writer.WriteNull();
}
}
}
internal class SystemTextJsonProductPropertyArrayConverter : System.Text.Json.Serialization.JsonConverter<Types.Data.Types.Result.Types.ProductProperty[]?>
{
public override Types.Data.Types.Result.Types.ProductProperty[]? Read(ref System.Text.Json.Utf8JsonReader reader, Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
{
if (reader.TokenType == System.Text.Json.JsonTokenType.Null)
{
return null;
}
else if (reader.TokenType == System.Text.Json.JsonTokenType.StartArray)
{
reader.Read();
var tmpList = new List<Types.Data.Types.Result.Types.ProductProperty>();
var tmpOptions = new System.Text.Json.JsonSerializerOptions(options);
while (reader.TokenType != System.Text.Json.JsonTokenType.EndArray)
{
if (reader.TokenType == System.Text.Json.JsonTokenType.StartArray)
{
reader.Read();
int offset = 0;
var tmpItem = new Types.Data.Types.Result.Types.ProductProperty();
while (reader.TokenType != System.Text.Json.JsonTokenType.EndArray)
{
if (offset == 0)
{
tmpItem.Value = System.Text.Json.JsonSerializer.Deserialize<string>(ref reader, tmpOptions)!;
}
else if (offset == 1)
{
tmpItem.Name = System.Text.Json.JsonSerializer.Deserialize<string>(ref reader, tmpOptions)!;
}
else if (offset == 2)
{
tmpItem.StartIndex = System.Text.Json.JsonSerializer.Deserialize<int>(ref reader, tmpOptions);
}
else if (offset == 3)
{
tmpItem.EndIndex = System.Text.Json.JsonSerializer.Deserialize<int>(ref reader, tmpOptions);
}
offset++;
reader.Read();
}
tmpList.Add(tmpItem);
}
reader.Read();
}
return tmpList.ToArray();
}
throw new System.Text.Json.JsonException();
}
public override void Write(System.Text.Json.Utf8JsonWriter writer, Types.Data.Types.Result.Types.ProductProperty[]? value, System.Text.Json.JsonSerializerOptions options)
{
if (value != null)
{
writer.WriteStartArray();
foreach (var item in value)
{
writer.WriteStartArray();
writer.WriteStringValue(item.Value);
writer.WriteStringValue(item.Name);
writer.WriteNumberValue(item.StartIndex);
writer.WriteNumberValue(item.EndIndex);
writer.WriteEndArray();
}
writer.WriteEndArray();
}
else
{
writer.WriteNullValue();
}
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
{
/// <summary>
/// <para>表示 [POST] /openapi/nlp/ner/{TOKEN} 接口的请求。</para>
/// </summary>
public class OpenApiNLPNERRequest : WechatOpenAIRequest, WechatOpenAIRequest.Serialization.IEncryptedUrlEncodedFormData
{
public static class Types
{
public class Data
{
/// <summary>
/// 获取或设置输入文本。
/// </summary>
[Newtonsoft.Json.JsonProperty("q")]
[System.Text.Json.Serialization.JsonPropertyName("q")]
public string QueryString { get; set; } = string.Empty;
}
}
/// <summary>
/// 获取或设置用户 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("uid")]
[System.Text.Json.Serialization.JsonPropertyName("uid")]
public string UserId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置请求数据。
/// </summary>
[Newtonsoft.Json.JsonProperty("data")]
[System.Text.Json.Serialization.JsonPropertyName("data")]
public Types.Data Data { get; set; } = new Types.Data();
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
{
/// <summary>
/// <para>表示 [POST] /openapi/nlp/ner/{TOKEN} 接口的响应。</para>
/// </summary>
public class OpenApiNLPNERResponse : WechatOpenAIResponse<OpenApiNLPNERResponse.Types.Result[]>
{
public static class Types
{
public class Result
{
/// <summary>
/// 获取或设置结果类型。
/// </summary>
[Newtonsoft.Json.JsonProperty("type")]
[System.Text.Json.Serialization.JsonPropertyName("type")]
public string Type { get; set; } = default!;
/// <summary>
/// 获取或设置范围列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("span")]
[System.Text.Json.Serialization.JsonPropertyName("span")]
public int[] SpanList { get; set; } = default!;
/// <summary>
/// 获取或设置文本。
/// </summary>
[Newtonsoft.Json.JsonProperty("text")]
[System.Text.Json.Serialization.JsonPropertyName("text")]
public string Text { get; set; } = default!;
/// <summary>
/// 获取或设置范数。
/// </summary>
[Newtonsoft.Json.JsonProperty("norm")]
[System.Text.Json.Serialization.JsonPropertyName("norm")]
public object Norm { get; set; } = default!;
}
}
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
{
/// <summary>
/// <para>表示 [POST] /openapi/nlp/sensitive/{TOKEN} 接口的请求。</para>
/// </summary>
public class OpenApiNLPSensitiveRequest : WechatOpenAIRequest, WechatOpenAIRequest.Serialization.IEncryptedUrlEncodedFormData
{
public static class Types
{
public class Data
{
/// <summary>
/// 获取或设置输入文本。
/// </summary>
[Newtonsoft.Json.JsonProperty("q")]
[System.Text.Json.Serialization.JsonPropertyName("q")]
public string QueryString { get; set; } = string.Empty;
/// <summary>
/// 获取或设置模型。
/// </summary>
[Newtonsoft.Json.JsonProperty("model")]
[System.Text.Json.Serialization.JsonPropertyName("model")]
public string? Model { get; set; }
}
}
/// <summary>
/// 获取或设置用户 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("uid")]
[System.Text.Json.Serialization.JsonPropertyName("uid")]
public string UserId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置请求数据。
/// </summary>
[Newtonsoft.Json.JsonProperty("data")]
[System.Text.Json.Serialization.JsonPropertyName("data")]
public Types.Data Data { get; set; } = new Types.Data();
}
}

View File

@@ -0,0 +1,208 @@
using System;
using System.Collections.Generic;
using System.Linq;
/* @codestyle-disable no-instantiated-property-in-response */
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
{
/// <summary>
/// <para>表示 [POST] /openapi/nlp/sensitive/{TOKEN} 接口的响应。</para>
/// </summary>
public class OpenApiNLPSensitiveResponse : WechatOpenAIResponse<OpenApiNLPSensitiveResponse.Types.Data>
{
public static class Types
{
public class Data
{
public static class Types
{
public class Result
{
/// <summary>
/// 获取或设置敏感信息项。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string Sensitive { get; set; } = default!;
/// <summary>
/// 获取或设置分值范围01
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public double Score { get; set; }
}
}
/// <summary>
/// 获取或设置结果。
/// </summary>
[Newtonsoft.Json.JsonProperty("result")]
[Newtonsoft.Json.JsonConverter(typeof(Converters.NewtonsoftJsonResultArrayConverter))]
[System.Text.Json.Serialization.JsonPropertyName("result")]
[System.Text.Json.Serialization.JsonConverter(typeof(Converters.SystemTextJsonResultArrayConverter))]
public Types.Result[] ResultList { get; set; } = default!;
}
}
internal static class Converters
{
internal class NewtonsoftJsonResultArrayConverter : Newtonsoft.Json.JsonConverter<Types.Data.Types.Result[]?>
{
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override Types.Data.Types.Result[]? ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, Types.Data.Types.Result[]? existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
{
if (reader.TokenType == Newtonsoft.Json.JsonToken.Null)
{
return existingValue;
}
else if (reader.TokenType == Newtonsoft.Json.JsonToken.StartArray)
{
reader.Read();
var tmpList = new List<Types.Data.Types.Result>();
while (reader.TokenType != Newtonsoft.Json.JsonToken.EndArray)
{
if (reader.TokenType == Newtonsoft.Json.JsonToken.StartArray)
{
reader.Read();
int offset = 0;
var tmpItem = new Types.Data.Types.Result();
while (reader.TokenType != Newtonsoft.Json.JsonToken.EndArray)
{
if (offset == 0)
{
tmpItem.Sensitive = serializer.Deserialize<string>(reader)!;
}
else if (offset == 1)
{
tmpItem.Score = serializer.Deserialize<double>(reader);
}
offset++;
reader.Read();
}
tmpList.Add(tmpItem);
}
reader.Read();
}
return tmpList.ToArray();
}
throw new Newtonsoft.Json.JsonReaderException();
}
public override void WriteJson(Newtonsoft.Json.JsonWriter writer, Types.Data.Types.Result[]? value, Newtonsoft.Json.JsonSerializer serializer)
{
if (value != null)
{
writer.WriteStartArray();
foreach (var item in value)
{
writer.WriteStartArray();
writer.WriteValue(item.Sensitive);
writer.WriteValue(item.Score);
writer.WriteEndArray();
}
writer.WriteEndArray();
}
else
{
writer.WriteNull();
}
}
}
internal class SystemTextJsonResultArrayConverter : System.Text.Json.Serialization.JsonConverter<Types.Data.Types.Result[]?>
{
public override Types.Data.Types.Result[]? Read(ref System.Text.Json.Utf8JsonReader reader, Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
{
if (reader.TokenType == System.Text.Json.JsonTokenType.Null)
{
return null;
}
else if (reader.TokenType == System.Text.Json.JsonTokenType.StartArray)
{
reader.Read();
var tmpList = new List<Types.Data.Types.Result>();
var tmpOptions = new System.Text.Json.JsonSerializerOptions(options);
while (reader.TokenType != System.Text.Json.JsonTokenType.EndArray)
{
if (reader.TokenType == System.Text.Json.JsonTokenType.StartArray)
{
reader.Read();
int offset = 0;
var tmpItem = new Types.Data.Types.Result();
while (reader.TokenType != System.Text.Json.JsonTokenType.EndArray)
{
if (offset == 0)
{
tmpItem.Sensitive = System.Text.Json.JsonSerializer.Deserialize<string>(ref reader, tmpOptions)!;
}
else if (offset == 1)
{
tmpItem.Score = System.Text.Json.JsonSerializer.Deserialize<double>(ref reader, tmpOptions);
}
offset++;
reader.Read();
}
tmpList.Add(tmpItem);
}
reader.Read();
}
return tmpList.ToArray();
}
throw new System.Text.Json.JsonException();
}
public override void Write(System.Text.Json.Utf8JsonWriter writer, Types.Data.Types.Result[]? value, System.Text.Json.JsonSerializerOptions options)
{
if (value != null)
{
writer.WriteStartArray();
foreach (var item in value)
{
writer.WriteStartArray();
writer.WriteStringValue(item.Sensitive);
writer.WriteNumberValue(item.Score);
writer.WriteEndArray();
}
writer.WriteEndArray();
}
else
{
writer.WriteNullValue();
}
}
}
}
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
{
/// <summary>
/// <para>表示 [POST] /openapi/nlp/sentiment/{TOKEN} 接口的请求。</para>
/// </summary>
public class OpenApiNLPSentimentRequest : WechatOpenAIRequest, WechatOpenAIRequest.Serialization.IEncryptedUrlEncodedFormData
{
public static class Types
{
public class Data
{
/// <summary>
/// 获取或设置输入文本。
/// </summary>
[Newtonsoft.Json.JsonProperty("q")]
[System.Text.Json.Serialization.JsonPropertyName("q")]
public string QueryString { get; set; } = string.Empty;
/// <summary>
/// 获取或设置模式。
/// </summary>
[Newtonsoft.Json.JsonProperty("mode")]
[System.Text.Json.Serialization.JsonPropertyName("mode")]
public string? Mode { get; set; }
}
}
/// <summary>
/// 获取或设置用户 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("uid")]
[System.Text.Json.Serialization.JsonPropertyName("uid")]
public string UserId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置请求数据。
/// </summary>
[Newtonsoft.Json.JsonProperty("data")]
[System.Text.Json.Serialization.JsonPropertyName("data")]
public Types.Data Data { get; set; } = new Types.Data();
}
}

View File

@@ -0,0 +1,208 @@
using System;
using System.Collections.Generic;
using System.Linq;
/* @codestyle-disable no-instantiated-property-in-response */
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
{
/// <summary>
/// <para>表示 [POST] /openapi/nlp/sentiment/{TOKEN} 接口的响应。</para>
/// </summary>
public class OpenApiNLPSentimentResponse : WechatOpenAIResponse<OpenApiNLPSentimentResponse.Types.Data>
{
public static class Types
{
public class Data
{
public static class Types
{
public class Result
{
/// <summary>
/// 获取或设置情感信息项。
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public string Sentiment { get; set; } = default!;
/// <summary>
/// 获取或设置分值范围01
/// </summary>
[Newtonsoft.Json.JsonIgnore]
[System.Text.Json.Serialization.JsonIgnore]
public double Score { get; set; }
}
}
/// <summary>
/// 获取或设置结果。
/// </summary>
[Newtonsoft.Json.JsonProperty("result")]
[Newtonsoft.Json.JsonConverter(typeof(Converters.NewtonsoftJsonResultArrayConverter))]
[System.Text.Json.Serialization.JsonPropertyName("result")]
[System.Text.Json.Serialization.JsonConverter(typeof(Converters.SystemTextJsonResultArrayConverter))]
public Types.Result[] ResultList { get; set; } = default!;
}
}
internal static class Converters
{
internal class NewtonsoftJsonResultArrayConverter : Newtonsoft.Json.JsonConverter<Types.Data.Types.Result[]?>
{
public override bool CanRead
{
get { return true; }
}
public override bool CanWrite
{
get { return true; }
}
public override Types.Data.Types.Result[]? ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, Types.Data.Types.Result[]? existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
{
if (reader.TokenType == Newtonsoft.Json.JsonToken.Null)
{
return existingValue;
}
else if (reader.TokenType == Newtonsoft.Json.JsonToken.StartArray)
{
reader.Read();
var tmpList = new List<Types.Data.Types.Result>();
while (reader.TokenType != Newtonsoft.Json.JsonToken.EndArray)
{
if (reader.TokenType == Newtonsoft.Json.JsonToken.StartArray)
{
reader.Read();
int offset = 0;
var tmpItem = new Types.Data.Types.Result();
while (reader.TokenType != Newtonsoft.Json.JsonToken.EndArray)
{
if (offset == 0)
{
tmpItem.Sentiment = serializer.Deserialize<string>(reader)!;
}
else if (offset == 1)
{
tmpItem.Score = serializer.Deserialize<double>(reader);
}
offset++;
reader.Read();
}
tmpList.Add(tmpItem);
}
reader.Read();
}
return tmpList.ToArray();
}
throw new Newtonsoft.Json.JsonReaderException();
}
public override void WriteJson(Newtonsoft.Json.JsonWriter writer, Types.Data.Types.Result[]? value, Newtonsoft.Json.JsonSerializer serializer)
{
if (value != null)
{
writer.WriteStartArray();
foreach (var item in value)
{
writer.WriteStartArray();
writer.WriteValue(item.Sentiment);
writer.WriteValue(item.Score);
writer.WriteEndArray();
}
writer.WriteEndArray();
}
else
{
writer.WriteNull();
}
}
}
internal class SystemTextJsonResultArrayConverter : System.Text.Json.Serialization.JsonConverter<Types.Data.Types.Result[]?>
{
public override Types.Data.Types.Result[]? Read(ref System.Text.Json.Utf8JsonReader reader, Type typeToConvert, System.Text.Json.JsonSerializerOptions options)
{
if (reader.TokenType == System.Text.Json.JsonTokenType.Null)
{
return null;
}
else if (reader.TokenType == System.Text.Json.JsonTokenType.StartArray)
{
reader.Read();
var tmpList = new List<Types.Data.Types.Result>();
var tmpOptions = new System.Text.Json.JsonSerializerOptions(options);
while (reader.TokenType != System.Text.Json.JsonTokenType.EndArray)
{
if (reader.TokenType == System.Text.Json.JsonTokenType.StartArray)
{
reader.Read();
int offset = 0;
var tmpItem = new Types.Data.Types.Result();
while (reader.TokenType != System.Text.Json.JsonTokenType.EndArray)
{
if (offset == 0)
{
tmpItem.Sentiment = System.Text.Json.JsonSerializer.Deserialize<string>(ref reader, tmpOptions)!;
}
else if (offset == 1)
{
tmpItem.Score = System.Text.Json.JsonSerializer.Deserialize<double>(ref reader, tmpOptions);
}
offset++;
reader.Read();
}
tmpList.Add(tmpItem);
}
reader.Read();
}
return tmpList.ToArray();
}
throw new System.Text.Json.JsonException();
}
public override void Write(System.Text.Json.Utf8JsonWriter writer, Types.Data.Types.Result[]? value, System.Text.Json.JsonSerializerOptions options)
{
if (value != null)
{
writer.WriteStartArray();
foreach (var item in value)
{
writer.WriteStartArray();
writer.WriteStringValue(item.Sentiment);
writer.WriteNumberValue(item.Score);
writer.WriteEndArray();
}
writer.WriteEndArray();
}
else
{
writer.WriteNullValue();
}
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
{
/// <summary>
/// <para>表示 [POST] /openapi/nlp/tokenize/{TOKEN} 接口的请求。</para>
/// </summary>
public class OpenApiNLPTokenizeRequest : WechatOpenAIRequest, WechatOpenAIRequest.Serialization.IEncryptedUrlEncodedFormData
{
public static class Types
{
public class Data
{
/// <summary>
/// 获取或设置输入文本。
/// </summary>
[Newtonsoft.Json.JsonProperty("q")]
[System.Text.Json.Serialization.JsonPropertyName("q")]
public string QueryString { get; set; } = string.Empty;
}
}
/// <summary>
/// 获取或设置用户 ID。
/// </summary>
[Newtonsoft.Json.JsonProperty("uid")]
[System.Text.Json.Serialization.JsonPropertyName("uid")]
public string UserId { get; set; } = string.Empty;
/// <summary>
/// 获取或设置请求数据。
/// </summary>
[Newtonsoft.Json.JsonProperty("data")]
[System.Text.Json.Serialization.JsonPropertyName("data")]
public Types.Data Data { get; set; } = new Types.Data();
}
}

View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
{
/// <summary>
/// <para>表示 [POST] /openapi/nlp/tokenize/{TOKEN} 接口的响应。</para>
/// </summary>
public class OpenApiNLPTokenizeResponse : WechatOpenAIResponse<OpenApiNLPTokenizeResponse.Types.Data>
{
public static class Types
{
public class Data
{
/// <summary>
/// 获取或设置常规粒度分词结果列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("words")]
[System.Text.Json.Serialization.JsonPropertyName("words")]
public string[] WordList { get; set; } = default!;
/// <summary>
/// 获取或设置常规粒度词性标签列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("POSs")]
[System.Text.Json.Serialization.JsonPropertyName("POSs")]
public int[] POSList { get; set; } = default!;
/// <summary>
/// 获取或设置混合粒度分词结果列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("words_mix")]
[System.Text.Json.Serialization.JsonPropertyName("words_mix")]
public string[] WordMixList { get; set; } = default!;
/// <summary>
/// 获取或设置混合粒度词性标签列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("POSs_mix")]
[System.Text.Json.Serialization.JsonPropertyName("POSs_mix")]
public int[] POSMixList { get; set; } = default!;
/// <summary>
/// 获取或设置短语提取结果列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("entities")]
[System.Text.Json.Serialization.JsonPropertyName("entities")]
public string[] EntityList { get; set; } = default!;
/// <summary>
/// 获取或设置短语类型标签列表。
/// </summary>
[Newtonsoft.Json.JsonProperty("entity_types")]
[System.Text.Json.Serialization.JsonPropertyName("entity_types")]
public int[] EntityTypeList { get; set; } = default!;
}
}
}
}

View File

@@ -9,7 +9,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Models
public class UserRegisterRequest : WechatOpenAIRequest
{
/// <summary>
/// 获取或设置平台自定义用户名
/// 获取或设置用户 ID
/// </summary>
[Newtonsoft.Json.JsonProperty("uid")]
[System.Text.Json.Serialization.JsonPropertyName("uid")]

View File

@@ -27,6 +27,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="JWT" Version="8.4.2" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>

View File

@@ -24,14 +24,14 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Settings
public string? AppId { get; }
/// <summary>
/// 初始化客户端时 <see cref="WechatOpenAIClientOptions.PushToken"/> 的副本。
/// 初始化客户端时 <see cref="WechatOpenAIClientOptions.Token"/> 的副本。
/// </summary>
public string? PushToken { get; }
public string? Token { get; }
/// <summary>
/// 初始化客户端时 <see cref="WechatOpenAIClientOptions.PushEncodingAESKey"/> 的副本。
/// 初始化客户端时 <see cref="WechatOpenAIClientOptions.EncodingAESKey"/> 的副本。
/// </summary>
public string? PushEncodingAESKey { get; }
public string? EncodingAESKey { get; }
internal Credentials(WechatOpenAIClientOptions options)
{
@@ -40,8 +40,8 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Settings
ClientId = options.ClientId;
ClientKey = options.ClientKey;
AppId = options.AppId;
PushToken = options.PushToken;
PushEncodingAESKey = options.PushEncodingAESKey;
Token = options.Token;
EncodingAESKey = options.EncodingAESKey;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using JWT;
using JWT.Algorithms;
using JWT.Serializers;
using Newtonsoft.Json;
namespace SKIT.FlurlHttpClient.Wechat.OpenAI.Utilities
{
internal static class JWTUtility
{
private static readonly Lazy<IJwtEncoder> _encoder = new Lazy<IJwtEncoder>(() =>
{
IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
IJsonSerializer serializer = new JsonNetSerializer(new JsonSerializer() { NullValueHandling = NullValueHandling.Ignore });
IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
return encoder;
}, isThreadSafe: true);
public static string EncodeWithHS256(object payload, string secret)
{
return _encoder.Value.Encode(payload, secret);
}
}
}

View File

@@ -115,7 +115,7 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
if (data is WechatOpenAIRequest.Serialization.IEncryptedXmlable)
{
string plainXml = Utilities.XmlUtility.Serialize(data);
string encryptedXml = Utilities.WxBizMsgCryptor.AESEncrypt(plainText: plainXml, encodingAESKey: Credentials.PushEncodingAESKey!, appId: Credentials.AppId!);
string encryptedXml = Utilities.WxBizMsgCryptor.AESEncrypt(plainText: plainXml, encodingAESKey: Credentials.EncodingAESKey!, appId: Credentials.AppId!);
data = new { encrypt = encryptedXml };
}
@@ -128,6 +128,38 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
}
}
/// <summary>
/// 异步发起请求。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="flurlRequest"></param>
/// <param name="data"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public async Task<T> SendRequestWithUrlEncodedAsync<T>(IFlurlRequest flurlRequest, object? data = null, CancellationToken cancellationToken = default)
where T : WechatOpenAIResponse, new()
{
try
{
if (data is WechatOpenAIRequest.Serialization.IEncryptedUrlEncodedFormData)
{
string jwt = Utilities.JWTUtility.EncodeWithHS256(payload: data, secret: Credentials.EncodingAESKey!);
data = new { query = jwt };
}
using IFlurlResponse flurlResponse = await flurlRequest
.WithClient(FlurlClient)
.AllowAnyHttpStatus()
.SendUrlEncodedAsync(flurlRequest.Verb, data, cancellationToken)
.ConfigureAwait(false);
return await GetResposneAsync<T>(flurlResponse).ConfigureAwait(false);
}
catch (FlurlHttpException ex)
{
throw new WechatOpenAIException(ex.Message, ex);
}
}
private async Task<T> GetResposneAsync<T>(IFlurlResponse flurlResponse)
where T : WechatOpenAIResponse, new()
{

View File

@@ -33,13 +33,13 @@
public string? AppId { get; set; }
/// <summary>
/// 获取或设置微信智能对话服务器推送的 EncodingAESKey。仅限平台接入时使用。
/// 获取或设置微信智能对话 Token。仅限平台接入时使用。
/// </summary>
public string? PushEncodingAESKey { get; set; }
public string? Token { get; set; }
/// <summary>
/// 获取或设置微信智能对话服务器推送的 Token。仅限平台接入时使用。
/// 获取或设置微信智能对话 EncodingAESKey。仅限平台接入时使用。
/// </summary>
public string? PushToken { get; set; }
public string? EncodingAESKey { get; set; }
}
}

View File

@@ -12,6 +12,10 @@ namespace SKIT.FlurlHttpClient.Wechat.OpenAI
public interface IEncryptedXmlable
{
}
public interface IEncryptedUrlEncodedFormData
{
}
}
/// <summary>