From 72abc9403bc98e62a49d50a427a8a1b94e84bf3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Tue, 11 Jul 2023 09:47:30 +0200 Subject: [PATCH 01/28] Add Function role to message --- src/ChatGPT.UI/Themes/Icons.axaml | 1 + src/ChatGPT.UI/Views/Chat/ChatMessageRoleView.axaml | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/ChatGPT.UI/Themes/Icons.axaml b/src/ChatGPT.UI/Themes/Icons.axaml index aafd8d36..fb247ff8 100644 --- a/src/ChatGPT.UI/Themes/Icons.axaml +++ b/src/ChatGPT.UI/Themes/Icons.axaml @@ -26,4 +26,5 @@ M4.75 5h14.5A2.75 2.75 0 0 1 22 7.75v8.5A2.75 2.75 0 0 1 19.25 19H4.75A2.75 2.75 0 0 1 2 16.25v-8.5A2.75 2.75 0 0 1 4.75 5Zm0 1.5c-.69 0-1.25.56-1.25 1.25v8.5c0 .69.56 1.25 1.25 1.25h14.5c.69 0 1.25-.56 1.25-1.25v-8.5c0-.69-.56-1.25-1.25-1.25H4.75Z m16.242 2.932 4.826 4.826a2.75 2.75 0 0 1-.715 4.404l-4.87 2.435a.75.75 0 0 0-.374.426l-1.44 4.166a1.25 1.25 0 0 1-2.065.476L8.5 16.561 4.06 21H3v-1.06l4.44-4.44-3.105-3.104a1.25 1.25 0 0 1 .476-2.066l4.166-1.44a.75.75 0 0 0 .426-.373l2.435-4.87a2.75 2.75 0 0 1 4.405-.715Zm3.766 5.886-4.826-4.826a1.25 1.25 0 0 0-2.002.325l-2.435 4.871a2.25 2.25 0 0 1-1.278 1.12l-3.789 1.31 6.705 6.704 1.308-3.789a2.25 2.25 0 0 1 1.12-1.277l4.872-2.436a1.25 1.25 0 0 0 .325-2.002Z M3.28 2.22a.75.75 0 0 0-1.06 1.06l5.905 5.905L4.81 10.33a1.25 1.25 0 0 0-.476 2.065L7.439 15.5 3 19.94V21h1.06l4.44-4.44 3.105 3.105a1.25 1.25 0 0 0 2.065-.476l1.145-3.313 5.905 5.904a.75.75 0 0 0 1.06-1.06L3.28 2.22Zm10.355 12.476-1.252 3.626-6.705-6.705 3.626-1.252 4.331 4.331Zm6.048-3.876-3.787 1.894 1.118 1.118 3.34-1.67a2.75 2.75 0 0 0 .714-4.404l-4.825-4.826a2.75 2.75 0 0 0-4.405.715l-1.67 3.34 1.118 1.117 1.894-3.787a1.25 1.25 0 0 1 2.002-.325l4.826 4.826a1.25 1.25 0 0 1-.325 2.002Z + m8.086 18.611 5.996-14.004a1 1 0 0 1 1.878.677l-.04.11-5.996 14.004a1 1 0 0 1-1.878-.677l.04-.11 5.996-14.004L8.086 18.61Zm-5.793-7.318 4-4a1 1 0 0 1 1.497 1.32l-.083.094L4.414 12l3.293 3.293a1 1 0 0 1-1.32 1.498l-.094-.084-4-4a1 1 0 0 1-.083-1.32l.083-.094 4-4-4 4Zm14-4.001a1 1 0 0 1 1.32-.083l.093.083 4.001 4.001a1 1 0 0 1 .083 1.32l-.083.095-4.001 3.995a1 1 0 0 1-1.497-1.32l.084-.095L19.584 12l-3.293-3.294a1 1 0 0 1 0-1.414Z diff --git a/src/ChatGPT.UI/Views/Chat/ChatMessageRoleView.axaml b/src/ChatGPT.UI/Views/Chat/ChatMessageRoleView.axaml index 1cab87e8..6153034e 100644 --- a/src/ChatGPT.UI/Views/Chat/ChatMessageRoleView.axaml +++ b/src/ChatGPT.UI/Views/Chat/ChatMessageRoleView.axaml @@ -79,6 +79,16 @@ Foreground="{DynamicResource ActionIconBrush}"/> + + + + + From 2c09bfa59ff7335df018786327ac042a74008a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20=C5=A0olt=C3=A9s?= Date: Tue, 11 Jul 2023 10:35:28 +0200 Subject: [PATCH 02/28] Add function calling json api --- src/ChatGPT/Model/Json/Chat/ChatFunction.cs | 22 +++++++++++++++++++ .../Model/Json/Chat/ChatFunctionCall.cs | 12 ++++++++++ src/ChatGPT/Model/Json/Chat/ChatMessage.cs | 8 +++++++ .../Json/Chat/ChatMessageFunctionCall.cs | 17 ++++++++++++++ .../Model/Json/Chat/ChatRequestBody.cs | 10 +++++++++ 5 files changed, 69 insertions(+) create mode 100644 src/ChatGPT/Model/Json/Chat/ChatFunction.cs create mode 100644 src/ChatGPT/Model/Json/Chat/ChatFunctionCall.cs create mode 100644 src/ChatGPT/Model/Json/Chat/ChatMessageFunctionCall.cs diff --git a/src/ChatGPT/Model/Json/Chat/ChatFunction.cs b/src/ChatGPT/Model/Json/Chat/ChatFunction.cs new file mode 100644 index 00000000..e98e3116 --- /dev/null +++ b/src/ChatGPT/Model/Json/Chat/ChatFunction.cs @@ -0,0 +1,22 @@ +using System.Runtime.Serialization; +using System.Text.Json.Serialization; + +namespace AI.Model.Json.Chat; + +[DataContract] +public class ChatFunction +{ + [DataMember(Name = "name")] + [JsonPropertyName("name")] + public string? Name { get; set; } + + [DataMember(Name = "description")] + [JsonPropertyName("description")] + public string? Description { get; set; } + + // JSON Schema object + // https://json-schema.org/understanding-json-schema/ + [DataMember(Name = "parameters")] + [JsonPropertyName("parameters")] + public object? Parameters { get; set; } +} diff --git a/src/ChatGPT/Model/Json/Chat/ChatFunctionCall.cs b/src/ChatGPT/Model/Json/Chat/ChatFunctionCall.cs new file mode 100644 index 00000000..cf31c5e2 --- /dev/null +++ b/src/ChatGPT/Model/Json/Chat/ChatFunctionCall.cs @@ -0,0 +1,12 @@ +using System.Runtime.Serialization; +using System.Text.Json.Serialization; + +namespace AI.Model.Json.Chat; + +[DataContract] +public class ChatFunctionCall +{ + [DataMember(Name = "name")] + [JsonPropertyName("name")] + public string? Name { get; set; } +} diff --git a/src/ChatGPT/Model/Json/Chat/ChatMessage.cs b/src/ChatGPT/Model/Json/Chat/ChatMessage.cs index b988a5e5..ee4c8176 100644 --- a/src/ChatGPT/Model/Json/Chat/ChatMessage.cs +++ b/src/ChatGPT/Model/Json/Chat/ChatMessage.cs @@ -13,4 +13,12 @@ public class ChatMessage [DataMember(Name = "content")] [JsonPropertyName("content")] public string? Content { get; set; } + + [DataMember(Name = "name")] + [JsonPropertyName("name")] + public string? Name { get; set; } + + [DataMember(Name = "function_call")] + [JsonPropertyName("function_call")] + public ChatMessageFunctionCall? FunctionCall { get; set; } } diff --git a/src/ChatGPT/Model/Json/Chat/ChatMessageFunctionCall.cs b/src/ChatGPT/Model/Json/Chat/ChatMessageFunctionCall.cs new file mode 100644 index 00000000..b7d2a8a6 --- /dev/null +++ b/src/ChatGPT/Model/Json/Chat/ChatMessageFunctionCall.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Text.Json.Serialization; + +namespace AI.Model.Json.Chat; + +[DataContract] +public class ChatMessageFunctionCall +{ + [DataMember(Name = "name")] + [JsonPropertyName("name")] + public string? Name { get; set; } + + [DataMember(Name = "arguments")] + [JsonPropertyName("arguments")] + public Dictionary? Arguments { get; set; } +} diff --git a/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs b/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs index f14f391d..2b02a943 100644 --- a/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs +++ b/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs @@ -15,6 +15,16 @@ public class ChatRequestBody [JsonPropertyName("messages")] public ChatMessage[]? Messages { get; set; } + [DataMember(Name = "functions")] + [JsonPropertyName("functions")] + public ChatFunction[]? Functions { get; set; } + + // string: "none", "auto" + // ChatFunctionCall: {"name":\ "my_function"} + [DataMember(Name = "function_call")] + [JsonPropertyName("function_call")] + public object? FunctionCall { get; set; } + [DataMember(Name = "temperature")] [JsonPropertyName("temperature")] public decimal Temperature { get; set; } = 1; From 5ecfba0e06534318b65615c1fca6d807c23ab457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 10:59:40 +0200 Subject: [PATCH 03/28] Add xml docs --- src/ChatGPT/Model/Json/Chat/ChatMessage.cs | 15 +++++ .../Model/Json/Chat/ChatRequestBody.cs | 57 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/ChatGPT/Model/Json/Chat/ChatMessage.cs b/src/ChatGPT/Model/Json/Chat/ChatMessage.cs index ee4c8176..634f38f4 100644 --- a/src/ChatGPT/Model/Json/Chat/ChatMessage.cs +++ b/src/ChatGPT/Model/Json/Chat/ChatMessage.cs @@ -3,21 +3,36 @@ namespace AI.Model.Json.Chat; +/// +/// Chat completion request message model. +/// [DataContract] public class ChatMessage { + /// + /// The role of the messages author. One of system, user, assistant, or function. + /// [DataMember(Name = "role")] [JsonPropertyName("role")] public string? Role { get; set; } + /// + /// The contents of the message. content is required for all messages, and may be null for assistant messages with function calls. + /// [DataMember(Name = "content")] [JsonPropertyName("content")] public string? Content { get; set; } + /// + /// The name of the author of this message. name is required if role is function, and it should be the name of the function whose response is in the content. May contain a-z, A-Z, 0-9, and underscores, with a maximum length of 64 characters. + /// [DataMember(Name = "name")] [JsonPropertyName("name")] public string? Name { get; set; } + /// + /// The name and arguments of a function that should be called, as generated by the model. + /// [DataMember(Name = "function_call")] [JsonPropertyName("function_call")] public ChatMessageFunctionCall? FunctionCall { get; set; } diff --git a/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs b/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs index 2b02a943..bbee62ea 100644 --- a/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs +++ b/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs @@ -4,17 +4,32 @@ namespace AI.Model.Json.Chat; +/// +/// Chat completion request body model. +/// [DataContract] public class ChatRequestBody { + /// + /// ID of the model to use. See the model endpoint compatibility table for details on which models work with the Chat API. + /// + /// + /// https://platform.openai.com/docs/models/model-endpoint-compatibility + /// [DataMember(Name = "model")] [JsonPropertyName("model")] public string? Model { get; set; } + /// + /// A list of messages comprising the conversation so far. + /// [DataMember(Name = "messages")] [JsonPropertyName("messages")] public ChatMessage[]? Messages { get; set; } + /// + /// A list of functions the model may generate JSON inputs for. + /// [DataMember(Name = "functions")] [JsonPropertyName("functions")] public ChatFunction[]? Functions { get; set; } @@ -25,42 +40,84 @@ public class ChatRequestBody [JsonPropertyName("function_call")] public object? FunctionCall { get; set; } + /// + /// What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. + /// + /// + /// We generally recommend altering this or top_p but not both. + /// [DataMember(Name = "temperature")] [JsonPropertyName("temperature")] public decimal Temperature { get; set; } = 1; + /// + /// An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. + /// + /// + /// We generally recommend altering this or temperature but not both. + /// [DataMember(Name = "top_p")] [JsonPropertyName("top_p")] public decimal TopP { get; set; } = 1; + /// + /// How many chat completion choices to generate for each input message. + /// [DataMember(Name = "n")] [JsonPropertyName("n")] public int N { get; set; } = 1; + /// + /// If set, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only server-sent events as they become available, with the stream terminated by a data: [DONE] message. + /// [DataMember(Name = "stream")] [JsonPropertyName("stream")] public bool Stream { get; set; } + /// + /// Up to 4 sequences where the API will stop generating further tokens. + /// [DataMember(Name = "stop")] [JsonPropertyName("stop")] public string? Stop { get; set; } + /// + /// The maximum number of tokens to generate in the chat completion. + /// + /// + /// The total length of input tokens and generated tokens is limited by the model's context length. + /// [DataMember(Name = "max_tokens")] [JsonPropertyName("max_tokens")] public int MaxTokens { get; set; } = 16; + /// + /// Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. + /// [DataMember(Name = "presence_penalty")] [JsonPropertyName("presence_penalty")] public decimal PresencePenalty { get; set; } + /// + /// Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. + /// [DataMember(Name = "frequency_penalty")] [JsonPropertyName("frequency_penalty")] public decimal FrequencyPenalty { get; set; } + /// + /// Modify the likelihood of specified tokens appearing in the completion. + /// + /// + /// Accepts a json object that maps tokens (specified by their token ID in the tokenizer) to an associated bias value from -100 to 100. Mathematically, the bias is added to the logits generated by the model prior to sampling. The exact effect will vary per model, but values between -1 and 1 should decrease or increase likelihood of selection; values like -100 or 100 should result in a ban or exclusive selection of the relevant token. + /// [DataMember(Name = "logit_bias")] [JsonPropertyName("logit_bias")] public Dictionary? LogitBias { get; set; } + /// + /// A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. + /// [DataMember(Name = "user")] [JsonPropertyName("user")] public string? User { get; set; } From f61ee19235da996ff3a53f496544831f7e4c90e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 11:00:23 +0200 Subject: [PATCH 04/28] Add Name property --- .../ViewModels/Chat/ChatMessageViewModel.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatMessageViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatMessageViewModel.cs index 77240b07..c13608f0 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatMessageViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatMessageViewModel.cs @@ -13,6 +13,7 @@ public class ChatMessageViewModel : ObservableObject { private string? _role; private string? _message; + private string? _name; private string? _format; private bool _isSent; private bool _isAwaiting; @@ -52,6 +53,17 @@ public ChatMessageViewModel(string role, string message) _message = message; } + public ChatMessageViewModel(string role, string message, string name) + : this() + { + _role = role; + _message = message; + _name = name; + } + + /// + /// The role of the messages author. One of system, user, assistant, or function. + /// [JsonPropertyName("role")] public string? Role { @@ -59,6 +71,9 @@ public string? Role set => SetProperty(ref _role, value); } + /// + /// The contents of the message. content is required for all messages, and may be null for assistant messages with function calls. + /// [JsonPropertyName("message")] public string? Message { @@ -66,6 +81,16 @@ public string? Message set => SetProperty(ref _message, value); } + /// + /// The name of the author of this message. name is required if role is function, and it should be the name of the function whose response is in the content. May contain a-z, A-Z, 0-9, and underscores, with a maximum length of 64 characters. + /// + [JsonPropertyName("name")] + public string? Name + { + get => _name; + set => SetProperty(ref _name, value); + } + [JsonPropertyName("format")] public string? Format { @@ -299,6 +324,7 @@ public ChatMessageViewModel Copy() { Role = _role, Message = _message, + Name = _name, Format = _format, IsSent = _isSent, IsAwaiting = _isAwaiting, From 9eb918250d685d75c79eb8b9e2d2e6d0f460082d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 11:00:37 +0200 Subject: [PATCH 05/28] Handle name property --- src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs index b71cb3c0..69af90c7 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs @@ -282,7 +282,9 @@ public ChatMessage[] CreateChatMessages() chatMessages.Add(new ChatMessage { Role = message.Role, - Content = content + Content = content, + Name = message.Name + // TODO: FunctionCall }); continue; @@ -293,7 +295,9 @@ public ChatMessage[] CreateChatMessages() chatMessages.Add(new ChatMessage { Role = message.Role, - Content = message.Message + Content = message.Message, + Name = message.Name, + // TODO: FunctionCall }); } } From 8258d479aa43f84b0ac6519c5d9856b89b09ff76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 11:00:46 +0200 Subject: [PATCH 06/28] Add helper method AddFunctionMessage --- src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs index 69af90c7..1896c6cf 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs @@ -466,6 +466,17 @@ public ChatViewModel AddAssistantMessage(string? message) return this; } + public ChatViewModel AddFunctionMessage(string? message, string? name) + { + Messages.Add(new ChatMessageViewModel + { + Role = "function", + Message = message, + Name = name + }); + return this; + } + private ObservableCollection CopyMessages(out ChatMessageViewModel? currentMessage) { var messages = new ObservableCollection(); From 13826e865395f23d9df6e26499deaa3f4f6c5858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 11:16:11 +0200 Subject: [PATCH 07/28] Update ChatSettingsViewModel.cs --- .../ViewModels/Chat/ChatSettingsViewModel.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs index 31b9e36f..f2e0edf6 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs @@ -30,6 +30,12 @@ public ChatSettingsViewModel() _apiUrl = null; } + /// + /// What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. + /// + /// + /// We generally recommend altering this or top_p but not both. + /// [JsonPropertyName("temperature")] public decimal Temperature { @@ -37,6 +43,12 @@ public decimal Temperature set => SetProperty(ref _temperature, value); } + /// + /// An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass. So 0.1 means only the tokens comprising the top 10% probability mass are considered. + /// + /// + /// We generally recommend altering this or temperature but not both. + /// [JsonPropertyName("top_p")] public decimal TopP { @@ -44,6 +56,9 @@ public decimal TopP set => SetProperty(ref _topP, value); } + /// + /// Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far, increasing the model's likelihood to talk about new topics. + /// [JsonPropertyName("presence_penalty")] public decimal PresencePenalty { @@ -51,6 +66,9 @@ public decimal PresencePenalty set => SetProperty(ref _presencePenalty, value); } + /// + /// Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far, decreasing the model's likelihood to repeat the same line verbatim. + /// [JsonPropertyName("frequency_penalty")] public decimal FrequencyPenalty { From e57e383ef71d64f7133d1dcbb47f78268f4f25ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 11:41:03 +0200 Subject: [PATCH 08/28] Add FunctionCall property to chat message --- .../Chat/ChatMessageFunctionCallViewModel.cs | 52 +++++++++++++++++++ .../ViewModels/Chat/ChatMessageViewModel.cs | 21 ++++++++ 2 files changed, 73 insertions(+) create mode 100644 src/ChatGPT.Core/ViewModels/Chat/ChatMessageFunctionCallViewModel.cs diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatMessageFunctionCallViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatMessageFunctionCallViewModel.cs new file mode 100644 index 00000000..52270c0d --- /dev/null +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatMessageFunctionCallViewModel.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace ChatGPT.ViewModels.Chat; + +public class ChatMessageFunctionCallViewModel : ObservableObject +{ + private string? _name; + private Dictionary? _arguments; + + [JsonConstructor] + public ChatMessageFunctionCallViewModel() + { + } + + public ChatMessageFunctionCallViewModel(string role, Dictionary arguments) + : this() + { + _name = role; + _arguments = arguments; + } + + [JsonPropertyName("name")] + public string? Name + { + get => _name; + set => SetProperty(ref _name, value); + } + + [JsonPropertyName("arguments")] + public Dictionary? Arguments + { + get => _arguments; + set => SetProperty(ref _arguments, value); + } + + public ChatMessageFunctionCallViewModel Copy() + { + var functionCall = new ChatMessageFunctionCallViewModel + { + Name = _name, + // TODO: Copy entry Value if it's reference value. + Arguments = _arguments?.ToDictionary( + e => e.Key, + e => e.Value) + }; + + return functionCall; + } +} diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatMessageViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatMessageViewModel.cs index c13608f0..20d47698 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatMessageViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatMessageViewModel.cs @@ -14,6 +14,7 @@ public class ChatMessageViewModel : ObservableObject private string? _role; private string? _message; private string? _name; + private ChatMessageFunctionCallViewModel? _functionCall; private string? _format; private bool _isSent; private bool _isAwaiting; @@ -61,6 +62,15 @@ public ChatMessageViewModel(string role, string message, string name) _name = name; } + public ChatMessageViewModel(string role, string? message, string name, ChatMessageFunctionCallViewModel functionCall) + : this() + { + _role = role; + _message = message; + _name = name; + _functionCall = functionCall; + } + /// /// The role of the messages author. One of system, user, assistant, or function. /// @@ -91,6 +101,16 @@ public string? Name set => SetProperty(ref _name, value); } + /// + /// The name and arguments of a function that should be called, as generated by the model. + /// + [JsonPropertyName("function_call")] + public ChatMessageFunctionCallViewModel? FunctionCall + { + get => _functionCall; + set => SetProperty(ref _functionCall, value); + } + [JsonPropertyName("format")] public string? Format { @@ -325,6 +345,7 @@ public ChatMessageViewModel Copy() Role = _role, Message = _message, Name = _name, + FunctionCall = _functionCall?.Copy(), Format = _format, IsSent = _isSent, IsAwaiting = _isAwaiting, From ec3092917bb09f0f0a89f70ba2b6a0ed34288187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 12:42:43 +0200 Subject: [PATCH 09/28] Create ChatFunctionCallViewModel.cs --- .../Chat/ChatFunctionCallViewModel.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/ChatGPT.Core/ViewModels/Chat/ChatFunctionCallViewModel.cs diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatFunctionCallViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatFunctionCallViewModel.cs new file mode 100644 index 00000000..ad84d1a2 --- /dev/null +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatFunctionCallViewModel.cs @@ -0,0 +1,27 @@ +using System.Text.Json.Serialization; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace ChatGPT.ViewModels.Chat; + +public class ChatFunctionCallViewModel : ObservableObject +{ + private string? _name; + + [JsonConstructor] + public ChatFunctionCallViewModel() + { + } + + public ChatFunctionCallViewModel(string name) + : this() + { + _name = name; + } + + [JsonPropertyName("name")] + public string? Name + { + get => _name; + set => SetProperty(ref _name, value); + } +} From 6d3c43bf657365185c1a97fed4207476b055c374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 12:42:57 +0200 Subject: [PATCH 10/28] Create ChatFunctionViewModel.cs --- .../ViewModels/Chat/ChatFunctionViewModel.cs | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/ChatGPT.Core/ViewModels/Chat/ChatFunctionViewModel.cs diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatFunctionViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatFunctionViewModel.cs new file mode 100644 index 00000000..7066046a --- /dev/null +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatFunctionViewModel.cs @@ -0,0 +1,63 @@ +using System.Text.Json.Serialization; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace ChatGPT.ViewModels.Chat; + +public class ChatFunctionViewModel : ObservableObject +{ + private string? _name; + private string? _description; + private object? _parameters; + + [JsonConstructor] + public ChatFunctionViewModel() + { + } + + public ChatFunctionViewModel(string name, string description) + : this() + { + _name = name; + _description = description; + } + + public ChatFunctionViewModel(string name, string description, object parameters) + : this() + { + _name = name; + _description = description; + _parameters = parameters; + } + + [JsonPropertyName("name")] + public string? Name + { + get => _name; + set => SetProperty(ref _name, value); + } + + [JsonPropertyName("description")] + public string? Description + { + get => _description; + set => SetProperty(ref _description, value); + } + + [JsonPropertyName("parameters")] + public object? Parameters + { + get => _parameters; + set => SetProperty(ref _parameters, value); + } + + public ChatFunctionViewModel Copy() + { + return new ChatFunctionViewModel + { + Name = _name, + Description = _description, + // TODO: Copy Parameters if type is reference. + Parameters = _parameters + }; + } +} From e1d183780b23d6f63101ededf1855e613b5e8c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 12:43:02 +0200 Subject: [PATCH 11/28] Update ChatSettingsViewModel.cs --- src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs index f2e0edf6..beda386e 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs @@ -16,6 +16,10 @@ public partial class ChatSettingsViewModel : ObservableObject private string? _format; private string? _apiUrl; + // TODO: Add Functions property (or in Settings?). + + // TODO: Add FunctionCall property (or in Settings?). + [JsonConstructor] public ChatSettingsViewModel() { From 362cb7f629cd45290f1a99f04a6fcdf8118ab52f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 12:43:06 +0200 Subject: [PATCH 12/28] Update ChatJsonContext.cs --- src/ChatGPT/Model/Json/Chat/ChatJsonContext.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ChatGPT/Model/Json/Chat/ChatJsonContext.cs b/src/ChatGPT/Model/Json/Chat/ChatJsonContext.cs index 6084b609..568a0f32 100644 --- a/src/ChatGPT/Model/Json/Chat/ChatJsonContext.cs +++ b/src/ChatGPT/Model/Json/Chat/ChatJsonContext.cs @@ -6,6 +6,9 @@ namespace AI.Model.Json.Chat; [JsonSerializable(typeof(ChatResponseSuccess))] [JsonSerializable(typeof(ChatChoice))] [JsonSerializable(typeof(ChatMessage))] +[JsonSerializable(typeof(ChatFunction))] +[JsonSerializable(typeof(ChatFunctionCall))] +[JsonSerializable(typeof(ChatMessageFunctionCall))] [JsonSerializable(typeof(ChatUsage))] [JsonSerializable(typeof(ChatResponseError))] [JsonSerializable(typeof(ChatError))] From 503f814c26512b784f35d0490e1e1a08d449fe26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 12:43:08 +0200 Subject: [PATCH 13/28] Update MainViewModelJsonContext.cs --- src/ChatGPT.Core/ViewModels/MainViewModelJsonContext.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ChatGPT.Core/ViewModels/MainViewModelJsonContext.cs b/src/ChatGPT.Core/ViewModels/MainViewModelJsonContext.cs index 273d75f0..e963ee65 100644 --- a/src/ChatGPT.Core/ViewModels/MainViewModelJsonContext.cs +++ b/src/ChatGPT.Core/ViewModels/MainViewModelJsonContext.cs @@ -9,6 +9,9 @@ namespace ChatGPT.ViewModels; [JsonSerializable(typeof(ChatMessageViewModel))] [JsonSerializable(typeof(ChatViewModel))] +[JsonSerializable(typeof(ChatFunctionCallViewModel))] +[JsonSerializable(typeof(ChatFunctionViewModel))] +[JsonSerializable(typeof(ChatMessageFunctionCallViewModel))] [JsonSerializable(typeof(ObservableCollection))] [JsonSerializable(typeof(ChatSettingsViewModel))] [JsonSerializable(typeof(ObservableCollection))] From 9c48972185bcac45128ba3c5c80045104208c2ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 12:58:41 +0200 Subject: [PATCH 14/28] Update ChatFunctionCallViewModel.cs --- .../ViewModels/Chat/ChatFunctionCallViewModel.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatFunctionCallViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatFunctionCallViewModel.cs index ad84d1a2..69438586 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatFunctionCallViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatFunctionCallViewModel.cs @@ -24,4 +24,12 @@ public string? Name get => _name; set => SetProperty(ref _name, value); } + + public ChatFunctionCallViewModel Copy() + { + return new ChatFunctionCallViewModel + { + Name = _name, + }; + } } From 7bf3b97b3eef62cbd7b58d95029cfbd6a7398813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 12:58:48 +0200 Subject: [PATCH 15/28] Update ChatRequestBody.cs --- src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs b/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs index bbee62ea..2f71dae2 100644 --- a/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs +++ b/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs @@ -34,8 +34,9 @@ public class ChatRequestBody [JsonPropertyName("functions")] public ChatFunction[]? Functions { get; set; } - // string: "none", "auto" - // ChatFunctionCall: {"name":\ "my_function"} + /// + /// Controls how the model responds to function calls. "none" means the model does not call a function, and responds to the end-user. "auto" means the model can pick between an end-user or calling a function. Specifying a particular function via {"name":\ "my_function"} forces the model to call that function. "none" is the default when no functions are present. "auto" is the default if functions are present. + /// [DataMember(Name = "function_call")] [JsonPropertyName("function_call")] public object? FunctionCall { get; set; } From 113ef50d0b244edab697f13887c1718268c683ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 12:58:51 +0200 Subject: [PATCH 16/28] Update ChatServiceSettings.cs --- src/ChatGPT/Model/Services/ChatServiceSettings.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ChatGPT/Model/Services/ChatServiceSettings.cs b/src/ChatGPT/Model/Services/ChatServiceSettings.cs index cb767ce3..8f943792 100644 --- a/src/ChatGPT/Model/Services/ChatServiceSettings.cs +++ b/src/ChatGPT/Model/Services/ChatServiceSettings.cs @@ -7,6 +7,8 @@ public class ChatServiceSettings public string? ApiUrl { get; set; } public string? Model { get; set; } public ChatMessage[]? Messages { get; set; } + public ChatFunction[]? Functions { get; set; } + public object? FunctionCall { get; set; } public string? Suffix { get; set; } public decimal Temperature { get; set; } public int MaxTokens { get; set; } From bf2b760954fb585dade571997581e7a385be121f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 12:58:53 +0200 Subject: [PATCH 17/28] Update ChatViewModel.cs --- src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs index 1896c6cf..09a5e340 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs @@ -398,6 +398,10 @@ public ChatMessage[] CreateChatMessages() var chatServiceSettings = new ChatServiceSettings { + // TODO: Functions + Functions = null, + // TODO: FunctionCall + FunctionCall = null, Model = Settings.Model, Messages = messages, Suffix = null, From bf67560ece74bc997de602c8cd1b190a19ff88b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Fri, 14 Jul 2023 12:58:55 +0200 Subject: [PATCH 18/28] Update ChatSettingsViewModel.cs --- .../ViewModels/Chat/ChatSettingsViewModel.cs | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs index beda386e..5e32f057 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs @@ -1,3 +1,4 @@ +using System.Linq; using System.Text.Json.Serialization; using CommunityToolkit.Mvvm.ComponentModel; @@ -5,6 +6,8 @@ namespace ChatGPT.ViewModels.Chat; public partial class ChatSettingsViewModel : ObservableObject { + private ChatFunctionViewModel[]? _functions; + private ChatFunctionCallViewModel? _functionCall; private decimal _temperature; private decimal _topP; private decimal _presencePenalty; @@ -16,13 +19,11 @@ public partial class ChatSettingsViewModel : ObservableObject private string? _format; private string? _apiUrl; - // TODO: Add Functions property (or in Settings?). - - // TODO: Add FunctionCall property (or in Settings?). - [JsonConstructor] public ChatSettingsViewModel() { + _functions = null; + _functionCall = null; _temperature = 0.7m; _topP = 1m; _presencePenalty = 0m; @@ -34,6 +35,26 @@ public ChatSettingsViewModel() _apiUrl = null; } + /// + /// A list of functions the model may generate JSON inputs for. + /// + [JsonPropertyName("functions")] + public ChatFunctionViewModel[]? Functions + { + get => _functions; + set => SetProperty(ref _functions, value); + } + + /// + /// Controls how the model responds to function calls. "none" means the model does not call a function, and responds to the end-user. "auto" means the model can pick between an end-user or calling a function. Specifying a particular function via {"name":\ "my_function"} forces the model to call that function. "none" is the default when no functions are present. "auto" is the default if functions are present. + /// + [JsonPropertyName("function_call")] + public ChatFunctionCallViewModel? FunctionCall + { + get => _functionCall; + set => SetProperty(ref _functionCall, value); + } + /// /// What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. /// @@ -126,6 +147,8 @@ public ChatSettingsViewModel Copy() { return new ChatSettingsViewModel { + Functions = _functions?.Select(x => x.Copy()).ToArray(), + FunctionCall = _functionCall?.Copy(), Temperature = _temperature, TopP = _topP, PresencePenalty = _presencePenalty, From 36f12731f140fca7f277c114c3503fd796861d1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 23 Jul 2023 14:54:12 +0200 Subject: [PATCH 19/28] Implement function calling --- .../Chat/ChatMessageFunctionCallViewModel.cs | 6 ++--- .../ViewModels/Chat/ChatResultViewModel.cs | 8 ++++++ .../ViewModels/Chat/ChatSettingsViewModel.cs | 17 +++++++----- .../ViewModels/Chat/ChatViewModel.cs | 23 ++++++++++++---- src/ChatGPT/Model/Json/Chat/ChatFunction.cs | 22 ---------------- .../Json/Chat/ChatFunctionsJsonConverter.cs | 26 +++++++++++++++++++ .../Model/Json/Chat/ChatJsonContext.cs | 3 ++- .../Json/Chat/ChatMessageFunctionCall.cs | 5 ++-- .../Model/Json/Chat/ChatRequestBody.cs | 3 ++- .../Model/Services/ChatServiceSettings.cs | 2 +- src/ChatGPT/Services/ChatService.cs | 2 ++ 11 files changed, 74 insertions(+), 43 deletions(-) delete mode 100644 src/ChatGPT/Model/Json/Chat/ChatFunction.cs create mode 100644 src/ChatGPT/Model/Json/Chat/ChatFunctionsJsonConverter.cs diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatMessageFunctionCallViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatMessageFunctionCallViewModel.cs index 52270c0d..6ef78675 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatMessageFunctionCallViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatMessageFunctionCallViewModel.cs @@ -8,14 +8,14 @@ namespace ChatGPT.ViewModels.Chat; public class ChatMessageFunctionCallViewModel : ObservableObject { private string? _name; - private Dictionary? _arguments; + private Dictionary? _arguments; [JsonConstructor] public ChatMessageFunctionCallViewModel() { } - public ChatMessageFunctionCallViewModel(string role, Dictionary arguments) + public ChatMessageFunctionCallViewModel(string role, Dictionary arguments) : this() { _name = role; @@ -30,7 +30,7 @@ public string? Name } [JsonPropertyName("arguments")] - public Dictionary? Arguments + public Dictionary? Arguments { get => _arguments; set => SetProperty(ref _arguments, value); diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatResultViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatResultViewModel.cs index be701e72..829e71c4 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatResultViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatResultViewModel.cs @@ -7,6 +7,7 @@ public class ChatResultViewModel : ObservableObject { private string? _message; private bool _isError; + private ChatMessageFunctionCallViewModel? _functionCall; [JsonPropertyName("name")] public string? Message @@ -21,4 +22,11 @@ public bool IsError get => _isError; set => SetProperty(ref _isError, value); } + + [JsonPropertyName("function_call")] + public ChatMessageFunctionCallViewModel? FunctionCall + { + get => _functionCall; + set => SetProperty(ref _functionCall, value); + } } diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs index 5e32f057..c3bfb28a 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatSettingsViewModel.cs @@ -1,4 +1,3 @@ -using System.Linq; using System.Text.Json.Serialization; using CommunityToolkit.Mvvm.ComponentModel; @@ -6,8 +5,8 @@ namespace ChatGPT.ViewModels.Chat; public partial class ChatSettingsViewModel : ObservableObject { - private ChatFunctionViewModel[]? _functions; - private ChatFunctionCallViewModel? _functionCall; + private object? _functions; + private object? _functionCall; private decimal _temperature; private decimal _topP; private decimal _presencePenalty; @@ -39,7 +38,7 @@ public ChatSettingsViewModel() /// A list of functions the model may generate JSON inputs for. /// [JsonPropertyName("functions")] - public ChatFunctionViewModel[]? Functions + public object? Functions { get => _functions; set => SetProperty(ref _functions, value); @@ -49,7 +48,7 @@ public ChatFunctionViewModel[]? Functions /// Controls how the model responds to function calls. "none" means the model does not call a function, and responds to the end-user. "auto" means the model can pick between an end-user or calling a function. Specifying a particular function via {"name":\ "my_function"} forces the model to call that function. "none" is the default when no functions are present. "auto" is the default if functions are present. /// [JsonPropertyName("function_call")] - public ChatFunctionCallViewModel? FunctionCall + public object? FunctionCall { get => _functionCall; set => SetProperty(ref _functionCall, value); @@ -147,8 +146,12 @@ public ChatSettingsViewModel Copy() { return new ChatSettingsViewModel { - Functions = _functions?.Select(x => x.Copy()).ToArray(), - FunctionCall = _functionCall?.Copy(), + // TODO: Copy Functions object. + Functions = _functions, + // TODO: Copy FunctionCall object. + FunctionCall = _functionCall is ChatFunctionCallViewModel functionCall + ? functionCall.Copy() + : _functionCall, Temperature = _temperature, TopP = _topP, PresencePenalty = _presencePenalty, diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs index 09a5e340..865bf406 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs @@ -398,12 +398,10 @@ public ChatMessage[] CreateChatMessages() var chatServiceSettings = new ChatServiceSettings { - // TODO: Functions - Functions = null, - // TODO: FunctionCall - FunctionCall = null, Model = Settings.Model, Messages = messages, + Functions = Settings.Functions, + FunctionCall = Settings.FunctionCall, Suffix = null, Temperature = Settings.Temperature, MaxTokens = Settings.MaxTokens, @@ -432,9 +430,24 @@ public ChatMessage[] CreateChatMessages() } else if (responseData is ChatResponseSuccess success) { - var message = success.Choices?.FirstOrDefault()?.Message?.Content?.Trim(); + var choice = success.Choices?.FirstOrDefault(); + var message = choice?.Message?.Content?.Trim(); result.Message = message ?? ""; result.IsError = false; + + if (choice is { } && choice.Message?.FunctionCall is { } functionCall) + { + var serializer = Defaults.Locator.GetService(); + var arguments = functionCall.Arguments is { } + ? serializer?.Deserialize>(functionCall.Arguments) + : null; + + result.FunctionCall = new () + { + Name = functionCall.Name, + Arguments = arguments + }; + } } return result; diff --git a/src/ChatGPT/Model/Json/Chat/ChatFunction.cs b/src/ChatGPT/Model/Json/Chat/ChatFunction.cs deleted file mode 100644 index e98e3116..00000000 --- a/src/ChatGPT/Model/Json/Chat/ChatFunction.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Runtime.Serialization; -using System.Text.Json.Serialization; - -namespace AI.Model.Json.Chat; - -[DataContract] -public class ChatFunction -{ - [DataMember(Name = "name")] - [JsonPropertyName("name")] - public string? Name { get; set; } - - [DataMember(Name = "description")] - [JsonPropertyName("description")] - public string? Description { get; set; } - - // JSON Schema object - // https://json-schema.org/understanding-json-schema/ - [DataMember(Name = "parameters")] - [JsonPropertyName("parameters")] - public object? Parameters { get; set; } -} diff --git a/src/ChatGPT/Model/Json/Chat/ChatFunctionsJsonConverter.cs b/src/ChatGPT/Model/Json/Chat/ChatFunctionsJsonConverter.cs new file mode 100644 index 00000000..1bc06bc8 --- /dev/null +++ b/src/ChatGPT/Model/Json/Chat/ChatFunctionsJsonConverter.cs @@ -0,0 +1,26 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace AI.Model.Json.Chat; + +internal class ChatFunctionsJsonConverter : JsonConverter +{ + public override object Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + + public override void Write(Utf8JsonWriter writer, object? value, JsonSerializerOptions options) + { + if (value is null) + { + writer.WriteNullValue(); + } + else + { + var json = JsonSerializer.Serialize(value); + writer.WriteRawValue(json); + } + } +} diff --git a/src/ChatGPT/Model/Json/Chat/ChatJsonContext.cs b/src/ChatGPT/Model/Json/Chat/ChatJsonContext.cs index 568a0f32..79f1218c 100644 --- a/src/ChatGPT/Model/Json/Chat/ChatJsonContext.cs +++ b/src/ChatGPT/Model/Json/Chat/ChatJsonContext.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.Text.Json.Serialization; namespace AI.Model.Json.Chat; @@ -6,9 +7,9 @@ namespace AI.Model.Json.Chat; [JsonSerializable(typeof(ChatResponseSuccess))] [JsonSerializable(typeof(ChatChoice))] [JsonSerializable(typeof(ChatMessage))] -[JsonSerializable(typeof(ChatFunction))] [JsonSerializable(typeof(ChatFunctionCall))] [JsonSerializable(typeof(ChatMessageFunctionCall))] +[JsonSerializable(typeof(Dictionary))] [JsonSerializable(typeof(ChatUsage))] [JsonSerializable(typeof(ChatResponseError))] [JsonSerializable(typeof(ChatError))] diff --git a/src/ChatGPT/Model/Json/Chat/ChatMessageFunctionCall.cs b/src/ChatGPT/Model/Json/Chat/ChatMessageFunctionCall.cs index b7d2a8a6..a90317ca 100644 --- a/src/ChatGPT/Model/Json/Chat/ChatMessageFunctionCall.cs +++ b/src/ChatGPT/Model/Json/Chat/ChatMessageFunctionCall.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Runtime.Serialization; +using System.Runtime.Serialization; using System.Text.Json.Serialization; namespace AI.Model.Json.Chat; @@ -13,5 +12,5 @@ public class ChatMessageFunctionCall [DataMember(Name = "arguments")] [JsonPropertyName("arguments")] - public Dictionary? Arguments { get; set; } + public string? Arguments { get; set; } } diff --git a/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs b/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs index 2f71dae2..d837dce0 100644 --- a/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs +++ b/src/ChatGPT/Model/Json/Chat/ChatRequestBody.cs @@ -32,7 +32,8 @@ public class ChatRequestBody /// [DataMember(Name = "functions")] [JsonPropertyName("functions")] - public ChatFunction[]? Functions { get; set; } + [JsonConverter(typeof(ChatFunctionsJsonConverter))] + public object? Functions { get; set; } /// /// Controls how the model responds to function calls. "none" means the model does not call a function, and responds to the end-user. "auto" means the model can pick between an end-user or calling a function. Specifying a particular function via {"name":\ "my_function"} forces the model to call that function. "none" is the default when no functions are present. "auto" is the default if functions are present. diff --git a/src/ChatGPT/Model/Services/ChatServiceSettings.cs b/src/ChatGPT/Model/Services/ChatServiceSettings.cs index 8f943792..aa296ac2 100644 --- a/src/ChatGPT/Model/Services/ChatServiceSettings.cs +++ b/src/ChatGPT/Model/Services/ChatServiceSettings.cs @@ -7,7 +7,7 @@ public class ChatServiceSettings public string? ApiUrl { get; set; } public string? Model { get; set; } public ChatMessage[]? Messages { get; set; } - public ChatFunction[]? Functions { get; set; } + public object? Functions { get; set; } public object? FunctionCall { get; set; } public string? Suffix { get; set; } public decimal Temperature { get; set; } diff --git a/src/ChatGPT/Services/ChatService.cs b/src/ChatGPT/Services/ChatService.cs index 83759f6e..d9f7ffb5 100644 --- a/src/ChatGPT/Services/ChatService.cs +++ b/src/ChatGPT/Services/ChatService.cs @@ -38,6 +38,8 @@ private string GetRequestBodyJson(ChatServiceSettings settings) { Model = model, Messages = settings.Messages, + Functions = settings.Functions, + FunctionCall = settings.FunctionCall, MaxTokens = settings.MaxTokens, Temperature = settings.Temperature, TopP = settings.TopP, From 7ed4fce5594447f0323e9140021deffab996188b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 23 Jul 2023 14:54:34 +0200 Subject: [PATCH 20/28] Add ChatGPT.CLI.FunctionCalling sample --- ChatGPT.sln | 7 ++ .../ChatGPT.CLI.FunctionCalling.csproj | 19 ++++ .../ChatGPT.CLI.FunctionCalling/Program.cs | 103 ++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 samples/ChatGPT.CLI.FunctionCalling/ChatGPT.CLI.FunctionCalling.csproj create mode 100644 samples/ChatGPT.CLI.FunctionCalling/Program.cs diff --git a/ChatGPT.sln b/ChatGPT.sln index 07a90d9c..5082498c 100644 --- a/ChatGPT.sln +++ b/ChatGPT.sln @@ -56,6 +56,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatGPT.UI.Game", "samples\ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{5EDF3913-3E89-44F6-A11F-52DA003AD315}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatGPT.CLI.FunctionCalling", "samples\ChatGPT.CLI.FunctionCalling\ChatGPT.CLI.FunctionCalling.csproj", "{0590592D-CDF7-4705-9F34-D8E779B66644}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -122,6 +124,10 @@ Global {B0A8A296-575A-443A-BD55-12713EAFE506}.Debug|Any CPU.Build.0 = Debug|Any CPU {B0A8A296-575A-443A-BD55-12713EAFE506}.Release|Any CPU.ActiveCfg = Release|Any CPU {B0A8A296-575A-443A-BD55-12713EAFE506}.Release|Any CPU.Build.0 = Release|Any CPU + {0590592D-CDF7-4705-9F34-D8E779B66644}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0590592D-CDF7-4705-9F34-D8E779B66644}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0590592D-CDF7-4705-9F34-D8E779B66644}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0590592D-CDF7-4705-9F34-D8E779B66644}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -142,5 +148,6 @@ Global {A9793A98-235E-4877-A3FC-C7C3DB4852FA} = {62EB4E5F-59EB-4D59-83A0-2A8B5B2397ED} {F9D8D17B-228B-4D5E-8126-39E8F41B87A2} = {D3B27217-AB31-4AB0-8FF9-C7528DA03FDE} {B0A8A296-575A-443A-BD55-12713EAFE506} = {5EDF3913-3E89-44F6-A11F-52DA003AD315} + {0590592D-CDF7-4705-9F34-D8E779B66644} = {5EDF3913-3E89-44F6-A11F-52DA003AD315} EndGlobalSection EndGlobal diff --git a/samples/ChatGPT.CLI.FunctionCalling/ChatGPT.CLI.FunctionCalling.csproj b/samples/ChatGPT.CLI.FunctionCalling/ChatGPT.CLI.FunctionCalling.csproj new file mode 100644 index 00000000..039e6a94 --- /dev/null +++ b/samples/ChatGPT.CLI.FunctionCalling/ChatGPT.CLI.FunctionCalling.csproj @@ -0,0 +1,19 @@ + + + Exe + net7.0 + win-x64;linux-x64;linux-arm64;osx-x64;osx-arm64 + enable + enable + full + False + ChatGPT.CLI + + + True + false + + + + + diff --git a/samples/ChatGPT.CLI.FunctionCalling/Program.cs b/samples/ChatGPT.CLI.FunctionCalling/Program.cs new file mode 100644 index 00000000..95890f55 --- /dev/null +++ b/samples/ChatGPT.CLI.FunctionCalling/Program.cs @@ -0,0 +1,103 @@ +using ChatGPT; +using ChatGPT.ViewModels.Chat; + +Defaults.ConfigureDefaultServices(); + +var directions = +""" +You are a helpful assistant. +Write answers in plain text. +Do not use markdown. +"""; + +if (args.Length == 1) +{ + directions = args[0]; +} + +using var cts = new CancellationTokenSource(); + +var functions = new[] +{ + new + { + name = "get_current_weather", + description = "Get the current weather in a given location", + parameters = new + { + type = "object", + properties = new + { + location = new + { + type = "string", + description = "The city and state, e.g. San Francisco, CA" + }, + unit = new + { + type = "string", + @enum = new[] { "celsius", "fahrenheit" } + }, + }, + required = new[] { "location" } + }, + } +}; + +var chat = new ChatViewModel(new ChatSettingsViewModel +{ + MaxTokens = 2000, + Model = "gpt-3.5-turbo-0613", + Functions = functions, + FunctionCall = "auto" + // Force function call by setting FunctionCall property. + // FunctionCall = new { name = "get_current_weather" } +}); + +chat.AddSystemMessage(directions); + +while (true) +{ + Console.Write("> "); + + var input = Console.ReadLine(); + if (string.IsNullOrWhiteSpace(input) || input == Environment.NewLine) + { + continue; + } + + try + { + chat.AddUserMessage(input); + var result = await chat.SendAsync(chat.CreateChatMessages(), cts.Token); + + chat.AddAssistantMessage(result?.Message); + + if (result?.Message is { }) + { + Console.WriteLine(result.Message); + } + + if (result?.FunctionCall is { } functionCall) + { + if (functionCall.Name == "get_current_weather" && functionCall.Arguments is { }) + { + functionCall.Arguments.TryGetValue("location", out var location); + functionCall.Arguments.TryGetValue("location", out var unit); + var functionCallResult = get_current_weather(location, unit ?? "celsius"); + chat.AddFunctionMessage(functionCallResult, functionCall.Name); + + Console.WriteLine(functionCallResult); + } + } + } + catch (Exception ex) + { + Console.WriteLine("Error: " + ex.Message); + } +} + +string get_current_weather(string? location, string? unit) +{ + return "Cloudy."; +} From 8217998c03064456d110a3436bc806e2cd5e6aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 23 Jul 2023 15:03:54 +0200 Subject: [PATCH 21/28] Update ChatFunctionsJsonConverter.cs --- src/ChatGPT/Model/Json/Chat/ChatFunctionsJsonConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ChatGPT/Model/Json/Chat/ChatFunctionsJsonConverter.cs b/src/ChatGPT/Model/Json/Chat/ChatFunctionsJsonConverter.cs index 1bc06bc8..a3fa79d2 100644 --- a/src/ChatGPT/Model/Json/Chat/ChatFunctionsJsonConverter.cs +++ b/src/ChatGPT/Model/Json/Chat/ChatFunctionsJsonConverter.cs @@ -19,7 +19,7 @@ public override void Write(Utf8JsonWriter writer, object? value, JsonSerializerO } else { - var json = JsonSerializer.Serialize(value); + var json = JsonSerializer.Serialize(value, new JsonSerializerOptions { WriteIndented = true }); writer.WriteRawValue(json); } } From b09db195ac7d4a4946b0527dbb9ae9d6029371ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 23 Jul 2023 15:17:09 +0200 Subject: [PATCH 22/28] Update ChatViewModel.cs --- src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs index 865bf406..548c3c5a 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs @@ -432,7 +432,7 @@ public ChatMessage[] CreateChatMessages() { var choice = success.Choices?.FirstOrDefault(); var message = choice?.Message?.Content?.Trim(); - result.Message = message ?? ""; + result.Message = message; result.IsError = false; if (choice is { } && choice.Message?.FunctionCall is { } functionCall) From d49c67c7274a07d30c860fe254644dab8b75e293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 23 Jul 2023 15:17:18 +0200 Subject: [PATCH 23/28] Update SystemTextJsonChatSerializer.cs --- src/ChatGPT/Services/SystemTextJsonChatSerializer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ChatGPT/Services/SystemTextJsonChatSerializer.cs b/src/ChatGPT/Services/SystemTextJsonChatSerializer.cs index 0fc50379..7533790f 100644 --- a/src/ChatGPT/Services/SystemTextJsonChatSerializer.cs +++ b/src/ChatGPT/Services/SystemTextJsonChatSerializer.cs @@ -16,7 +16,8 @@ static SystemTextJsonChatSerializer() new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - IgnoreReadOnlyProperties = true + IgnoreReadOnlyProperties = true, + WriteIndented = true }); } From 8c3ad075518059127c236b306969f6a1873cf50a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 23 Jul 2023 15:17:37 +0200 Subject: [PATCH 24/28] Add json debug support --- samples/ChatGPT.CLI.FunctionCalling/Program.cs | 3 +++ .../ViewModels/Chat/ChatViewModel.cs | 9 +++++++++ .../Model/Services/ChatServiceSettings.cs | 1 + src/ChatGPT/Services/ChatService.cs | 18 ++++++++++++++---- 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/samples/ChatGPT.CLI.FunctionCalling/Program.cs b/samples/ChatGPT.CLI.FunctionCalling/Program.cs index 95890f55..4e039de3 100644 --- a/samples/ChatGPT.CLI.FunctionCalling/Program.cs +++ b/samples/ChatGPT.CLI.FunctionCalling/Program.cs @@ -54,6 +54,9 @@ Do not use markdown. // FunctionCall = new { name = "get_current_weather" } }); +// Enable to debug json requests and responses. +// chat.Debug = true; + chat.AddSystemMessage(directions); while (true) diff --git a/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs b/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs index 548c3c5a..f5befcf8 100644 --- a/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs +++ b/src/ChatGPT.Core/ViewModels/Chat/ChatViewModel.cs @@ -20,6 +20,7 @@ public class ChatViewModel : ObservableObject private ObservableCollection _messages; private ChatMessageViewModel? _currentMessage; private bool _isEnabled; + private bool _debug; private CancellationTokenSource? _cts; [JsonConstructor] @@ -92,6 +93,13 @@ public bool IsEnabled set => SetProperty(ref _isEnabled, value); } + [JsonIgnore] + public bool Debug + { + get => _debug; + set => SetProperty(ref _debug, value); + } + public void SetMessageActions(ChatMessageViewModel message) { message.SetSendAction(SendAsync); @@ -408,6 +416,7 @@ public ChatMessage[] CreateChatMessages() TopP = 1.0m, Stop = null, ApiUrl = Settings.ApiUrl, + Debug = Debug }; var result = new ChatResultViewModel diff --git a/src/ChatGPT/Model/Services/ChatServiceSettings.cs b/src/ChatGPT/Model/Services/ChatServiceSettings.cs index aa296ac2..b4c6d620 100644 --- a/src/ChatGPT/Model/Services/ChatServiceSettings.cs +++ b/src/ChatGPT/Model/Services/ChatServiceSettings.cs @@ -16,4 +16,5 @@ public class ChatServiceSettings public decimal PresencePenalty { get; set; } public decimal FrequencyPenalty { get; set; } public string? Stop { get; set; } + public bool Debug { get; set; } } diff --git a/src/ChatGPT/Services/ChatService.cs b/src/ChatGPT/Services/ChatService.cs index d9f7ffb5..5146f3ee 100644 --- a/src/ChatGPT/Services/ChatService.cs +++ b/src/ChatGPT/Services/ChatService.cs @@ -55,7 +55,7 @@ private string GetRequestBodyJson(ChatServiceSettings settings) return _serializer.Serialize(requestBody); } - private async Task SendApiRequestAsync(string apiUrl, string apiKey, string requestBodyJson, CancellationToken token) + private async Task SendApiRequestAsync(string apiUrl, string apiKey, string requestBodyJson, bool debug, CancellationToken token) { // Create a new HttpClient for making the API request @@ -68,6 +68,10 @@ private string GetRequestBodyJson(ChatServiceSettings settings) // Create a new StringContent object with the JSON payload and the correct content type var content = new StringContent(requestBodyJson, Encoding.UTF8, "application/json"); + if (debug) + { + Console.WriteLine($"RequestBody:{Environment.NewLine}{requestBodyJson}"); + } // Send the API request and get the response var response = await s_client.PostAsync(apiUrl, content, token); @@ -78,8 +82,12 @@ private string GetRequestBodyJson(ChatServiceSettings settings) #else var responseBody = await response.Content.ReadAsStringAsync(token); #endif - // Console.WriteLine($"Status code: {response.StatusCode}"); - // Console.WriteLine($"Response body:{Environment.NewLine}{responseBody}"); + if (debug) + { + Console.WriteLine($"Status code: {response.StatusCode}"); + Console.WriteLine($"Response body:{Environment.NewLine}{responseBody}"); + } + switch (response.StatusCode) { case HttpStatusCode.Unauthorized: @@ -132,7 +140,9 @@ private string GetRequestBodyJson(ChatServiceSettings settings) return null; } + var debug = settings.Debug; + // Send the API request and get the response data - return await SendApiRequestAsync(apiUrl, apiKey, requestBodyJson, token); + return await SendApiRequestAsync(apiUrl, apiKey, requestBodyJson, debug, token); } } From 5dff2e6e2c3966277b0c3c9961420fcb4a6c6deb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 23 Jul 2023 15:22:26 +0200 Subject: [PATCH 25/28] Update Program.cs --- samples/ChatGPT.CLI.FunctionCalling/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/ChatGPT.CLI.FunctionCalling/Program.cs b/samples/ChatGPT.CLI.FunctionCalling/Program.cs index 4e039de3..2dcf938c 100644 --- a/samples/ChatGPT.CLI.FunctionCalling/Program.cs +++ b/samples/ChatGPT.CLI.FunctionCalling/Program.cs @@ -86,7 +86,7 @@ Do not use markdown. if (functionCall.Name == "get_current_weather" && functionCall.Arguments is { }) { functionCall.Arguments.TryGetValue("location", out var location); - functionCall.Arguments.TryGetValue("location", out var unit); + functionCall.Arguments.TryGetValue("unit", out var unit); var functionCallResult = get_current_weather(location, unit ?? "celsius"); chat.AddFunctionMessage(functionCallResult, functionCall.Name); From 12b91cd8c4eaa9e944899d0b8d0aa21e9d720372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 23 Jul 2023 15:25:16 +0200 Subject: [PATCH 26/28] Update Program.cs --- samples/ChatGPT.CLI.FunctionCalling/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/ChatGPT.CLI.FunctionCalling/Program.cs b/samples/ChatGPT.CLI.FunctionCalling/Program.cs index 2dcf938c..ac72ecd5 100644 --- a/samples/ChatGPT.CLI.FunctionCalling/Program.cs +++ b/samples/ChatGPT.CLI.FunctionCalling/Program.cs @@ -102,5 +102,6 @@ Do not use markdown. string get_current_weather(string? location, string? unit) { + Console.WriteLine($"Weather for {location} [{unit}]."); return "Cloudy."; } From 65994536e9babf8817acfbc96700c90e086c7da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 23 Jul 2023 15:31:11 +0200 Subject: [PATCH 27/28] Update Program.cs --- .../ChatGPT.CLI.FunctionCalling/Program.cs | 65 ++++++++++--------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/samples/ChatGPT.CLI.FunctionCalling/Program.cs b/samples/ChatGPT.CLI.FunctionCalling/Program.cs index ac72ecd5..f48cca26 100644 --- a/samples/ChatGPT.CLI.FunctionCalling/Program.cs +++ b/samples/ChatGPT.CLI.FunctionCalling/Program.cs @@ -17,32 +17,7 @@ Do not use markdown. using var cts = new CancellationTokenSource(); -var functions = new[] -{ - new - { - name = "get_current_weather", - description = "Get the current weather in a given location", - parameters = new - { - type = "object", - properties = new - { - location = new - { - type = "string", - description = "The city and state, e.g. San Francisco, CA" - }, - unit = new - { - type = "string", - @enum = new[] { "celsius", "fahrenheit" } - }, - }, - required = new[] { "location" } - }, - } -}; +var functions = GetFunctions(); var chat = new ChatViewModel(new ChatSettingsViewModel { @@ -51,7 +26,7 @@ Do not use markdown. Functions = functions, FunctionCall = "auto" // Force function call by setting FunctionCall property. - // FunctionCall = new { name = "get_current_weather" } + // FunctionCall = new { name = "GetCurrentWeather" } }); // Enable to debug json requests and responses. @@ -83,11 +58,11 @@ Do not use markdown. if (result?.FunctionCall is { } functionCall) { - if (functionCall.Name == "get_current_weather" && functionCall.Arguments is { }) + if (functionCall.Name == "GetCurrentWeather" && functionCall.Arguments is { }) { functionCall.Arguments.TryGetValue("location", out var location); functionCall.Arguments.TryGetValue("unit", out var unit); - var functionCallResult = get_current_weather(location, unit ?? "celsius"); + var functionCallResult = GetCurrentWeather(location, unit ?? "celsius"); chat.AddFunctionMessage(functionCallResult, functionCall.Name); Console.WriteLine(functionCallResult); @@ -100,8 +75,38 @@ Do not use markdown. } } -string get_current_weather(string? location, string? unit) +string GetCurrentWeather(string? location, string? unit) { Console.WriteLine($"Weather for {location} [{unit}]."); return "Cloudy."; } + +object GetFunctions() +{ + return new[] + { + new + { + name = "GetCurrentWeather", + description = "Get the current weather in a given location", + parameters = new + { + type = "object", + properties = new + { + location = new + { + type = "string", + description = "The city and state, e.g. San Francisco, CA" + }, + unit = new + { + type = "string", + @enum = new[] {"celsius", "fahrenheit"} + }, + }, + required = new[] {"location"} + }, + } + }; +} From d9e7d357ae5d4693d3b869590d94aae9d9992eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wies=C5=82aw=20S=CC=8Colte=CC=81s?= Date: Sun, 23 Jul 2023 15:31:15 +0200 Subject: [PATCH 28/28] Update Program.cs --- samples/ChatGPT.CLI.FunctionCalling/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/ChatGPT.CLI.FunctionCalling/Program.cs b/samples/ChatGPT.CLI.FunctionCalling/Program.cs index f48cca26..6d219f3f 100644 --- a/samples/ChatGPT.CLI.FunctionCalling/Program.cs +++ b/samples/ChatGPT.CLI.FunctionCalling/Program.cs @@ -8,6 +8,7 @@ You are a helpful assistant. Write answers in plain text. Do not use markdown. +Only use the functions you have been provided with. """; if (args.Length == 1)