Skip to content

Commit

Permalink
feat: nativeaot support for nuget package
Browse files Browse the repository at this point in the history
- switch to sourcegen serialization
- fix minor warnings
- move some array allocations to constants
- rename some types to resolve name conflicts (request vs response)
  • Loading branch information
neon-sunset authored and bsdayo committed May 21, 2023
1 parent debf3b9 commit 916ce5d
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 97 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ obj/
riderModule.iml
/_ReSharper.Caches/
.idea/
build/
.DS_Store
build/
publish/
9 changes: 5 additions & 4 deletions src/BingChat/BingChatClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public async Task<IBingChattable> CreateConversation()
{
JsonNode? cookieJson = JsonNode.Parse(File.ReadAllText(_options.CookieFilePath));
cookies = new CookieContainer();
foreach (var cookieItemJson in (JsonArray)cookieJson)
foreach (var cookieItemJson in (JsonArray)cookieJson!)
{
if (cookieItemJson is null)
continue;
Expand Down Expand Up @@ -92,8 +92,9 @@ public async Task<IBingChattable> CreateConversation()
headers.Add("referer", "https://www.bing.com/search");
headers.Add("referer-policy", "origin-when-cross-origin");

var response = await client.GetFromJsonAsync<BingCreateConversationResponse>(
"https://www.bing.com/turing/conversation/create");
var response = await client.GetFromJsonAsync(
"https://www.bing.com/turing/conversation/create",
SerializerContext.Default.BingCreateConversationResponse);

if (response!.Result is { } errResult &&
!errResult.Value.Equals("Success", StringComparison.OrdinalIgnoreCase))
Expand Down Expand Up @@ -129,7 +130,7 @@ internal class CreateConversationResult
public string Message { get; set; } = null!;
}

public CreateConversationResult? Result { get; set; } = null;
public CreateConversationResult? Result { get; set; }

public string ConversationId { get; set; } = null!;
public string ClientId { get; set; } = null!;
Expand Down
48 changes: 48 additions & 0 deletions src/BingChat/BingChatConstants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
namespace BingChat;

internal static class BingChatConstants
{
internal static readonly string[] OptionSets = new[]
{
"nlu_direct_response_filter",
"deepleo",
"enable_debug_commands",
"disable_emoji_spoken_text",
"responsible_ai_policy_235",
"enablemm",
"cachewriteext",
"e2ecachewrite",
"nodlcpcwrite",
"nointernalsugg",
"saharasugg",
"rai267",
"sportsansgnd",
"enablenewsfc",
"dv3sugg",
"autosave",
"dlislog"
};

internal static readonly string[] CreativeOptionSets = OptionSets
.Concat(new[] { "h3imaginative", "clgalileo", "gencontentv3" })
.ToArray();

internal static readonly string[] PreciseOptionSets = OptionSets
.Concat(new[] { "h3precise", "clgalileo", "gencontentv3" })
.ToArray();

internal static readonly string[] BalancedOptionSets = OptionSets
.Concat(new[] { "galileo" })
.ToArray();

internal static readonly string[] AllowedMessageTypes = new[]
{
"Chat",
"InternalSearchQuery",
"InternalSearchResult",
"InternalLoaderMessage",
"RenderCardRequest",
"AdsQuery",
"SemanticSerp"
};
}
3 changes: 1 addition & 2 deletions src/BingChat/BingChatConversation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ internal BingChatConversation(
_request = new BingChatRequest(clientId, conversationId, conversationSignature, tone);
}


/// <inheritdoc/>
public Task<string> AskAsync(string message)
{
Expand Down Expand Up @@ -61,7 +60,7 @@ void OnMessageReceived(string text)
{
foreach (var part in text.Split(TerminalChar, StringSplitOptions.RemoveEmptyEntries))
{
var json = JsonSerializer.Deserialize<BingChatConversationResponse>(part);
var json = JsonSerializer.Deserialize(part, SerializerContext.Default.BingChatConversationResponse);

if (json is not { Type: 2 }) continue;

Expand Down
91 changes: 91 additions & 0 deletions src/BingChat/BingChatConversationRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
using System.Text.Json.Serialization;

// ReSharper disable MemberCanBeInternal
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global

#pragma warning disable CS8618

namespace BingChat;

internal sealed class BingChatConversationRequest
{
[JsonPropertyName("type")]
public int Type { get; set; }

[JsonPropertyName("invocationId")]
public string InvocationId { get; set; }

[JsonPropertyName("target")]
public string Target { get; set; }

[JsonPropertyName("arguments")]
public RequestArgument[] Arguments { get; set; }
}

internal sealed class RequestArgument
{
[JsonPropertyName("source")]
public string Source { get; set; }

[JsonPropertyName("optionsSets")]
public string[] OptionsSets { get; set; }

[JsonPropertyName("allowedMessageTypes")]
public string[] AllowedMessageTypes { get; set; }

[JsonPropertyName("sliceIds")]
public string[] SliceIds { get; set; }

[JsonPropertyName("traceId")]
public string TraceId { get; set; }

[JsonPropertyName("isStartOfSession")]
public bool IsStartOfSession { get; set; }

[JsonPropertyName("message")]
public RequestMessage Message { get; set; }

[JsonPropertyName("tone")]
public string Tone { get; set; }

[JsonPropertyName("conversationSignature")]
public string ConversationSignature { get; set; }

[JsonPropertyName("participant")]
public Participant Participant { get; set; }

[JsonPropertyName("conversationId")]
public string ConversationId { get; set; }
}

internal sealed class RequestMessage
{
// Are these needed?
// locale = ,
// market = ,
// region = ,
// location = ,
// locationHints: [],

[JsonPropertyName("timestamp")]
public DateTime Timestamp { get; set; }

[JsonPropertyName("author")]
public string Author { get; set; }

[JsonPropertyName("inputMethod")]
public string InputMethod { get; set; }

[JsonPropertyName("messageType")]
public string MessageType { get; set; }

[JsonPropertyName("text")]
public string Text { get; set; }
}

internal struct Participant
{
[JsonPropertyName("id")]
public string Id { get; set; }
}
16 changes: 8 additions & 8 deletions src/BingChat/BingChatConversationResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ internal sealed class BingChatConversationResponse
public int Type { get; set; }

[JsonPropertyName("item")]
public Item Item { get; set; }
public ResponseItem Item { get; set; }
}

internal sealed class Item
internal sealed class ResponseItem
{
[JsonPropertyName("messages")]
public Message[] Messages { get; set; }
public ResponseMessage[] Messages { get; set; }

[JsonPropertyName("result")]
public Result Result { get; set; }
public ResponseResult Result { get; set; }
}

internal sealed class Message
internal sealed class ResponseMessage
{
[JsonPropertyName("text")]
public string Text { get; set; }
Expand All @@ -44,10 +44,10 @@ internal sealed class Message
internal sealed class AdaptiveCard
{
[JsonPropertyName("body")]
public Body[] Body { get; set; }
public ResponseBody[] Body { get; set; }
}

internal sealed class Body
internal sealed class ResponseBody
{
[JsonPropertyName("type")]
public string Type { get; set; }
Expand All @@ -59,7 +59,7 @@ internal sealed class Body
public bool Wrap { get; set; }
}

internal sealed class Result
internal sealed class ResponseResult
{
[JsonPropertyName("value")]
public string Value { get; set; }
Expand Down
113 changes: 31 additions & 82 deletions src/BingChat/BingChatRequest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.Linq;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace BingChat;

Expand All @@ -12,12 +11,6 @@ internal sealed class BingChatRequest
private readonly BingChatTone _tone;
private int _invocationId;

private static readonly JsonSerializerOptions JsonSerializerOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};

internal BingChatRequest(
string clientId, string conversationId, string conversationSignature, BingChatTone tone)
{
Expand All @@ -30,94 +23,50 @@ internal BingChatRequest(
/// <summary>
/// Construct the initial payload for each message
/// </summary>
/// <param name="message">User message to Bing Chat</param>
internal string ConstructInitialPayload(string message)
{
var fnGetToneOptions = (BingChatTone tone) =>
{
if (tone == BingChatTone.Creative)
{
return new string[] { "h3imaginative", "clgalileo", "gencontentv3" };
}
else if (tone == BingChatTone.Precise)
{
return new string[] { "h3precise", "clgalileo", "gencontentv3" };
}
else
{
return new string[] { "galileo" };
}
};

var bytes = new byte[16];
var bytes = (stackalloc byte[16]);
Random.Shared.NextBytes(bytes);
var traceId = BitConverter.ToString(bytes).Replace("-", string.Empty).ToLower();
var traceId = Convert.ToHexString(bytes).ToLowerInvariant();

var payload = new
var payload = new BingChatConversationRequest
{
type = 4,
invocationId = _invocationId.ToString(),
target = "chat",
arguments = new[]
Type = 4,
InvocationId = _invocationId.ToString(CultureInfo.InvariantCulture),
Target = "chat",
Arguments = new[]
{
new
new RequestArgument
{
source = "cib",
optionsSets = new[]
Source = "cib",
OptionsSets = _tone switch
{
"nlu_direct_response_filter",
"deepleo",
"enable_debug_commands",
"disable_emoji_spoken_text",
"responsible_ai_policy_235",
"enablemm",
"cachewriteext",
"e2ecachewrite",
"nodlcpcwrite",
"nointernalsugg",
"saharasugg",
"rai267",
"sportsansgnd",
"enablenewsfc",
"dv3sugg",
"autosave",
"dlislog"
}.Concat(fnGetToneOptions(_tone)),
allowedMessageTypes = new[]
{
"Chat",
"InternalSearchQuery",
"InternalSearchResult",
"InternalLoaderMessage",
"RenderCardRequest",
"AdsQuery",
"SemanticSerp"
BingChatTone.Creative => BingChatConstants.CreativeOptionSets,
BingChatTone.Precise => BingChatConstants.PreciseOptionSets,
BingChatTone.Balanced or _ => BingChatConstants.BalancedOptionSets
},
sliceIds = Array.Empty<string>(),
traceId,
isStartOfSession = _invocationId == 0,
message = new
AllowedMessageTypes = BingChatConstants.AllowedMessageTypes,
SliceIds = Array.Empty<string>(),
TraceId = traceId,
IsStartOfSession = _invocationId == 0,
Message = new RequestMessage
{
// Are these needed?
// locale = ,
// market = ,
// region = ,
// location = ,
// locationHints: [],

timestamp = DateTime.Now,
author = "user",
inputMethod = "Keyboard",
messageType = "Chat",
text = message
Timestamp = DateTime.Now,
Author = "user",
InputMethod = "Keyboard",
MessageType = "Chat",
Text = message
},
tone = _tone.ToString(),
conversationSignature = _conversationSignature,
participant = new { id = _clientId },
conversationId = _conversationId
Tone = _tone.ToString(),
ConversationSignature = _conversationSignature,
Participant = new() { Id = _clientId },
ConversationId = _conversationId
}
}
};

_invocationId++;
return JsonSerializer.Serialize(payload, JsonSerializerOptions);
return JsonSerializer.Serialize(payload, SerializerContext.Default.BingChatConversationRequest);
}
}
Loading

0 comments on commit 916ce5d

Please # to comment.