Skip to content

Commit

Permalink
Documentantion update #137
Browse files Browse the repository at this point in the history
  • Loading branch information
marcominerva committed Jan 8, 2024
1 parent cc47527 commit e0901e5
Show file tree
Hide file tree
Showing 11 changed files with 61 additions and 30 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ var functionResponse = await GetWeatherAsync(functionCall.Arguments);
await chatGptClient.AddToolResponseAsync(conversationId, tool, functionResponse);
```

Check out the [Function calling sample](https://github.com/marcominerva/ChatGptNet/blob/master/samples/ChatGptFunctionCallingConsole/Application.cs#L18) for a complete implementation of this workflow.
Finally, you need to resend the original message to the chat completion API, so that the model can continue the conversation taking into account the function call response. Check out the [Function calling sample](https://github.com/marcominerva/ChatGptNet/blob/master/samples/ChatGptFunctionCallingConsole/Application.cs#L18) for a complete implementation of this workflow.

## Content filtering

Expand Down
2 changes: 1 addition & 1 deletion docs/ChatGptNet.Models/ChatGptToolParameters.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ChatGptToolParameters class

Contains parameters about the tools that are available for ChatGPT.
Contains parameters about the tool calls that are available for ChatGPT.

```csharp
public class ChatGptToolParameters
Expand Down
2 changes: 1 addition & 1 deletion docs/ChatGptNet/IChatGptClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public interface IChatGptClient

| name | description |
| --- | --- |
| [AddInteractionAsync](IChatGptClient/AddInteractionAsync.md)(…) | Explicitly adds a new interaction (a question and the corresponding answer) to the conversation history. |
| [AddInteractionAsync](IChatGptClient/AddInteractionAsync.md)(…) | Explicitly adds a new interaction (a question and the corresponding answer) to an existing conversation history. |
| [AddToolResponseAsync](IChatGptClient/AddToolResponseAsync.md)(…) | Adds a function response to the conversation history. (4 methods) |
| [AskAsync](IChatGptClient/AskAsync.md)(…) | Requests a new chat interaction. (4 methods) |
| [AskStreamAsync](IChatGptClient/AskStreamAsync.md)(…) | Requests a new chat interaction with streaming response, like in ChatGPT. (2 methods) |
Expand Down
3 changes: 2 additions & 1 deletion docs/ChatGptNet/IChatGptClient/AddInteractionAsync.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# IChatGptClient.AddInteractionAsync method

Explicitly adds a new interaction (a question and the corresponding answer) to the conversation history.
Explicitly adds a new interaction (a question and the corresponding answer) to an existing conversation history.

```csharp
public Task AddInteractionAsync(Guid conversationId, string question, string answer,
Expand All @@ -22,6 +22,7 @@ The Task corresponding to the asynchronous operation.

| exception | condition |
| --- | --- |
| ArgumentException | *conversationId* is Empty. |
| ArgumentNullException | *question* or *answer* are `null`. |

## See Also
Expand Down
1 change: 1 addition & 0 deletions docs/ChatGptNet/IChatGptClient/AddToolResponseAsync.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The Task corresponding to the asynchronous operation.

| exception | condition |
| --- | --- |
| ArgumentException | *conversationId* is Empty. |
| ArgumentNullException | [`Name`](../../ChatGptNet.Models/ChatGptFunction/Name.md) or *content* are `null`. |
| InvalidOperationException | The conversation history is empty. |

Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
| class [ChatGptTool](./ChatGptNet.Models/ChatGptTool.md) | Represents a tool that the model may call. |
| class [ChatGptToolCall](./ChatGptNet.Models/ChatGptToolCall.md) | A tool call generated by the model, such as a function call. |
| static class [ChatGptToolChoices](./ChatGptNet.Models/ChatGptToolChoices.md) | Contains constants for ChatGPT function call types. |
| class [ChatGptToolParameters](./ChatGptNet.Models/ChatGptToolParameters.md) | Contains parameters about the function calls that are available for ChatGPT. |
| class [ChatGptToolParameters](./ChatGptNet.Models/ChatGptToolParameters.md) | Contains parameters about the tools calls that are available for ChatGPT. |
| static class [ChatGptToolTypes](./ChatGptNet.Models/ChatGptToolTypes.md) | Contains constants for ChatGPT tool types. |
| class [ChatGptUsage](./ChatGptNet.Models/ChatGptUsage.md) | Contains information about the API usage. |
| static class [OpenAIChatGptModels](./ChatGptNet.Models/OpenAIChatGptModels.md) | Contains all the chat completion models that are currently supported by OpenAI. |
Expand Down
2 changes: 1 addition & 1 deletion samples/ChatGptBlazor.Wasm/ChatGptBlazor.Wasm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Markdig" Version="0.33.0" />
<PackageReference Include="Markdig" Version="0.34.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0" PrivateAssets="all" />
</ItemGroup>
Expand Down
51 changes: 34 additions & 17 deletions samples/ChatGptFunctionCallingConsole/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,8 @@

namespace ChatGptConsole;

internal class Application
internal class Application(IChatGptClient chatGptClient)
{
private readonly IChatGptClient chatGptClient;

public Application(IChatGptClient chatGptClient)
{
this.chatGptClient = chatGptClient;
}

public async Task ExecuteAsync()
{
Console.WriteLine("Welcome! You can ask me whatever you want, but if you ask me something about the weather, I will probably suggest you to call a function.");
Expand Down Expand Up @@ -107,15 +100,12 @@ public async Task ExecuteAsync()
var functionCall = response.GetFunctionCall()!;

Console.ForegroundColor = ConsoleColor.Green;

Console.WriteLine(functionCall.Name);
Console.WriteLine(functionCall.Arguments);

Console.ResetColor();

// Simulate the calling to the function.
// Simulates the call to the function.
var functionResponse = await GetWeatherAsync(functionCall.GetArgumentsAsJson());
Console.WriteLine(functionResponse);

// After the function has been called, it is necessary to add the response to the conversation.

Expand All @@ -127,6 +117,17 @@ public async Task ExecuteAsync()
// for example the gpt-4 1106-preview model, you need the following code:
//var tool = response.GetToolCalls()!.First();
//await chatGptClient.AddToolResponseAsync(conversationId, tool, functionResponse);

Console.WriteLine("The function gives the following response:");

Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(functionResponse);
Console.ResetColor();

// Finally, it sends the original message back to the model, to obtain a response that takes into account the function call.
response = await chatGptClient.AskAsync(conversationId, message, toolParameters);

Console.WriteLine(response.GetContent());
}
else
{
Expand All @@ -150,14 +151,30 @@ public async Task ExecuteAsync()

private static Task<string> GetWeatherAsync(JsonDocument? arguments)
{
var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
string[] summaries =
[
"Freezing",
"Bracing",
"Chilly",
"Cool",
"Mild",
"Warm",
"Balmy",
"Hot",
"Sweltering",
"Scorching"
];

var location = arguments?.RootElement.GetProperty("location").GetString();

var response = $"It is {summaries[Random.Shared.Next(summaries.Length)]} in {location}, with {Random.Shared.Next(-20, 35)}° degrees";
var response = $$"""
{
"location": "{{location}}",
"temperature": {{Random.Shared.Next(-5, 35)}},
"description": "{{summaries[Random.Shared.Next(summaries.Length)]}}"
}
""";

return Task.FromResult(response);
}
}
20 changes: 15 additions & 5 deletions src/ChatGptNet/ChatGptClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,12 @@ public async Task<Guid> LoadConversationAsync(Guid conversationId, IEnumerable<C

public async Task AddInteractionAsync(Guid conversationId, string question, string answer, CancellationToken cancellationToken = default)
{
ThrowIfEmptyConversationId(conversationId, nameof(conversationId));
ArgumentNullException.ThrowIfNull(question);
ArgumentNullException.ThrowIfNull(answer);

var messages = await cache.GetAsync(conversationId, cancellationToken) ?? Enumerable.Empty<ChatGptMessage>();
messages = messages.Union(new ChatGptMessage[]
{
messages = messages.Union([
new()
{
Role = ChatGptRoles.User,
Expand All @@ -262,20 +262,21 @@ public async Task AddInteractionAsync(Guid conversationId, string question, stri
Role = ChatGptRoles.Assistant,
Content = answer
}
});
]);

await UpdateCacheAsync(conversationId, messages, cancellationToken);
}

public async Task AddToolResponseAsync(Guid conversationId, string? toolId, string name, string content, CancellationToken cancellationToken = default)
{
ThrowIfEmptyConversationId(conversationId, nameof(conversationId));
ArgumentNullException.ThrowIfNull(name);
ArgumentNullException.ThrowIfNull(content);

var messages = await cache.GetAsync(conversationId, cancellationToken);
if (!messages?.Any() ?? true)
{
throw new InvalidOperationException("Cannot add a function response message if the conversation history is empty");
throw new InvalidOperationException("Cannot add a tool/function response message if the conversation history is empty");
}

messages = messages!.Append(new()
Expand Down Expand Up @@ -338,7 +339,8 @@ private ChatGptRequest CreateChatGptRequest(IEnumerable<ChatGptMessage> messages
{ } => JsonDocument.Parse($$"""{ "type": "{{ChatGptToolTypes.Function}}", "{{ChatGptToolTypes.Function}}": { "name": "{{toolParameters.ToolChoice}}" } }"""),
_ => null
},
// If the tool paramters uses the legacy function properties.

// If the tool parameters uses the legacy function properties.
Functions = toolParameters?.Functions,
FunctionCall = toolParameters?.FunctionCall switch
{
Expand Down Expand Up @@ -426,4 +428,12 @@ private static void NormalizeResponse(HttpResponseMessage httpResponse, Response
response.Error.StatusCode = (int)httpResponse.StatusCode;
}
}

private static void ThrowIfEmptyConversationId(Guid guid, string parameterName)
{
if (guid == Guid.Empty)
{
throw new ArgumentException($"The value {guid} is invalid", parameterName);
}
}
}
4 changes: 3 additions & 1 deletion src/ChatGptNet/IChatGptClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,14 @@ Task<ChatGptResponse> AskAsync(Guid conversationId, string message, ChatGptParam
IAsyncEnumerable<ChatGptResponse> AskStreamAsync(Guid conversationId, string message, ChatGptParameters? parameters = null, string? model = null, bool addToConversationHistory = true, CancellationToken cancellationToken = default);

/// <summary>
/// Explicitly adds a new interaction (a question and the corresponding answer) to the conversation history.
/// Explicitly adds a new interaction (a question and the corresponding answer) to an existing conversation history.
/// </summary>
/// <param name="conversationId">The unique identifier of the conversation.</param>
/// <param name="question">The question.</param>
/// <param name="answer">The answer.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="Task"/> corresponding to the asynchronous operation.</returns>
/// <exception cref="ArgumentException"><paramref name="conversationId"/> is <see cref="Guid.Empty"/>.</exception>
/// <exception cref="ArgumentNullException"><paramref name="question"/> or <paramref name="answer"/> are <see langword="null"/>.</exception>
Task AddInteractionAsync(Guid conversationId, string question, string answer, CancellationToken cancellationToken = default);

Expand Down Expand Up @@ -230,6 +231,7 @@ Task<Guid> LoadConversationAsync(IEnumerable<ChatGptMessage> messages, Cancellat
/// <param name="content">The content of the function response.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
/// <returns>The <see cref="Task"/> corresponding to the asynchronous operation.</returns>
/// <exception cref="ArgumentException"><paramref name="conversationId"/> is <see cref="Guid.Empty"/>.</exception>
/// <exception cref="ArgumentNullException"><see cref="ChatGptFunction.Name"/> or <paramref name="content"/> are <see langword="null"/>.</exception>
/// <exception cref="InvalidOperationException">The conversation history is empty.</exception>
/// <seealso cref="AskAsync(Guid, string, ChatGptParameters?, string?, bool, CancellationToken)"/>
Expand Down
2 changes: 1 addition & 1 deletion src/ChatGptNet/Models/ChatGptToolParameters.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace ChatGptNet.Models;

/// <summary>
/// Contains parameters about the tools calls that are available for ChatGPT.
/// Contains parameters about the tool calls that are available for ChatGPT.
/// </summary>
public class ChatGptToolParameters
{
Expand Down

0 comments on commit e0901e5

Please sign in to comment.