Skip to content

Commit

Permalink
Manually add chat interaction (#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcominerva authored Aug 11, 2023
2 parents 8db82f4 + 2299cc6 commit 83f3ebb
Show file tree
Hide file tree
Showing 19 changed files with 145 additions and 48 deletions.
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,15 @@ If necessary, it is possibile to provide a custom Cache by implementing the [ICh
```csharp
public class LocalMessageCache : IChatGptCache
{
private readonly Dictionary<Guid, List<ChatGptMessage>> localCache = new();
private readonly Dictionary<Guid, IEnumerable<ChatGptMessage>> localCache = new();

public Task SetAsync(Guid conversationId, IEnumerable<ChatGptMessage> messages, TimeSpan expiration, CancellationToken cancellationToken = default)
{
localCache[conversationId] = messages.ToList();
return Task.CompletedTask;
}

public Task<List<ChatGptMessage>?> GetAsync(Guid conversationId, CancellationToken cancellationToken = default)
public Task<IEnumerable<ChatGptMessage>?> GetAsync(Guid conversationId, CancellationToken cancellationToken = default)
{
localCache.TryGetValue(conversationId, out var messages);
return Task.FromResult(messages);
Expand Down Expand Up @@ -211,14 +211,23 @@ var message = response.GetMessage();
The **AskAsync** and **AskStreamAsync** (see below) methods provides overloads that require a *conversationId* parameter. If we pass an empty value, a random one is generated and returned.
We can pass this value in subsequent invocations of **AskAsync** or **AskStreamAsync**, so that the library automatically retrieves previous messages of the current conversation (according to *MessageLimit* and *MessageExpiration* settings) and send them to chat completion API.

This is the default behavior for all the chat interactions. If you want to exlude a particular interaction from the conversation history, you can set the *addToChatHistory* argument to *false*:
This is the default behavior for all the chat interactions. If you want to exlude a particular interaction from the conversation history, you can set the *addToConversationHistory* argument to *false*:

```csharp
var response = await chatGptClient.AskAsync(conversationId, message, addToChatHistory: false);
var response = await chatGptClient.AskAsync(conversationId, message, addToConversationHistory: false);
```

In this way, the message will be sent to the chat completion API, but it and the corresponding answer from ChatGPT will not be added to the conversation history.

On the other hand, in some scenarios, it could be useful to manually add a chat interaction (i.e., a question followed by an answer) to the conversation history. For example, we may want to add a message that was generated by a bot. In this case, we can use the **AddInteractionAsync** method:

```csharp
await chatGptClient.AskInteractionAsync(conversationId, question: "What is the weather like in Taggia?",
answer: "It's Always Sunny in Taggia");
```

The question will be added as *user* message and the answer will be added as *assistant* message in the conversation history. As always, these new messages (respecting the *MessageLimit* option) will be used in subsequent invocations of **AskAsync** or **AskStreamAsync**.

### Response streaming

Chat completion API supports response streaming. When using this feature, partial message deltas will be sent, like in ChatGPT. Tokens will be sent as data-only server-sent events as they become available. **ChatGptNet** provides response streaming using the **AskStreamAsync** method:
Expand Down
4 changes: 4 additions & 0 deletions docs/ChatGptNet.Models/ChatGptResponse/Usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Gets or sets information about token usage.
public ChatGptUsage? Usage { get; set; }
```

## Remarks

The `Usage` property is always `null` when requesting response streaming with CancellationToken).

## See Also

* class [ChatGptUsage](../ChatGptUsage.md)
Expand Down
2 changes: 1 addition & 1 deletion docs/ChatGptNet/IChatGptCache/GetAsync.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Gets the list of messages for the given *conversationId*.

```csharp
public Task<List<ChatGptMessage>?> GetAsync(Guid conversationId,
public Task<IEnumerable<ChatGptMessage>?> GetAsync(Guid conversationId,
CancellationToken cancellationToken = default)
```

Expand Down
1 change: 1 addition & 0 deletions docs/ChatGptNet/IChatGptClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public interface IChatGptClient
| name | description |
| --- | --- |
| [AddFunctionResponseAsync](IChatGptClient/AddFunctionResponseAsync.md)(…) | Adds a function response to the conversation history. |
| [AddInteractionAsync](IChatGptClient/AddInteractionAsync.md)(…) | Explicitly adds a new interaction (a question and the corresponding answer) to the conversation history. |
| [AskAsync](IChatGptClient/AskAsync.md)(…) | Requests a new chat interaction using the default completion model specified in the [`DefaultModel`](./ChatGptOptions/DefaultModel.md) property. (4 methods) |
| [AskStreamAsync](IChatGptClient/AskStreamAsync.md)(…) | Requests a new chat interaction (using the default completion model specified in the [`DefaultModel`](./ChatGptOptions/DefaultModel.md) property) with streaming response, like in ChatGPT. (2 methods) |
| [ConversationExistsAsync](IChatGptClient/ConversationExistsAsync.md)(…) | Determines if a chat conversation exists. |
Expand Down
1 change: 1 addition & 0 deletions docs/ChatGptNet/IChatGptClient/AddFunctionResponseAsync.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ The Task corresponding to the asynchronous operation.
## See Also

* method [AskAsync](./AskAsync.md)
* method [AskStreamAsync](./AskStreamAsync.md)
* class [ChatGptFunctionCall](../../ChatGptNet.Models/ChatGptFunctionCall.md)
* interface [IChatGptClient](../IChatGptClient.md)
* namespace [ChatGptNet](../../ChatGptNet.md)
Expand Down
32 changes: 32 additions & 0 deletions docs/ChatGptNet/IChatGptClient/AddInteractionAsync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# IChatGptClient.AddInteractionAsync method

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

```csharp
public Task AddInteractionAsync(Guid conversationId, string question, string answer,
CancellationToken cancellationToken = default)
```

| parameter | description |
| --- | --- |
| conversationId | The unique identifier of the conversation. |
| question | The question. |
| answer | The answer. |
| cancellationToken | The token to monitor for cancellation requests. |

## Return Value

The Task corresponding to the asynchronous operation.

## Exceptions

| exception | condition |
| --- | --- |
| ArgumentNullException | *question* or *answer* are `null`. |

## See Also

* interface [IChatGptClient](../IChatGptClient.md)
* namespace [ChatGptNet](../../ChatGptNet.md)

<!-- DO NOT EDIT: generated by xmldocmd for ChatGptNet.dll -->
13 changes: 9 additions & 4 deletions docs/ChatGptNet/IChatGptClient/AskAsync.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ Requests a new chat interaction using the default completion model specified in

```csharp
public Task<ChatGptResponse> AskAsync(string message, ChatGptParameters? parameters = null,
CancellationToken cancellationToken = default)
bool addToConversationHistory = true, CancellationToken cancellationToken = default)
```

| parameter | description |
| --- | --- |
| message | The message. |
| parameters | A [`ChatGptParameters`](../../ChatGptNet.Models/ChatGptParameters.md) object used to override the default completion parameters in the [`DefaultParameters`](../ChatGptOptions/DefaultParameters.md) property. |
| addToConversationHistory | Set to `true` to add the current chat interaction to the conversation history. |
| cancellationToken | The token to monitor for cancellation requests. |

## Return Value
Expand Down Expand Up @@ -45,14 +46,15 @@ Requests a new chat interaction using the default completion model specified in
```csharp
public Task<ChatGptResponse> AskAsync(string message,
ChatGptFunctionParameters? functionParameters, ChatGptParameters? parameters = null,
CancellationToken cancellationToken = default)
bool addToConversationHistory = true, CancellationToken cancellationToken = default)
```

| parameter | description |
| --- | --- |
| message | The message. |
| functionParameters | A [`ChatGptFunctionParameters`](../../ChatGptNet.Models/ChatGptFunctionParameters.md) object that contains the list of available functions for calling. |
| parameters | A [`ChatGptParameters`](../../ChatGptNet.Models/ChatGptParameters.md) object used to override the default completion parameters in the [`DefaultParameters`](../ChatGptOptions/DefaultParameters.md) property. |
| addToConversationHistory | Set to `true` to add the current chat interaction to the conversation history. |
| cancellationToken | The token to monitor for cancellation requests. |

## Return Value
Expand Down Expand Up @@ -90,7 +92,7 @@ Requests a chat interaction.
```csharp
public Task<ChatGptResponse> AskAsync(Guid conversationId, string message,
ChatGptParameters? parameters = null, string? model = null,
CancellationToken cancellationToken = default)
bool addToConversationHistory = true, CancellationToken cancellationToken = default)
```

| parameter | description |
Expand All @@ -99,6 +101,7 @@ public Task<ChatGptResponse> AskAsync(Guid conversationId, string message,
| message | The message. |
| parameters | A object used to override the default completion parameters in the [`DefaultParameters`](../ChatGptOptions/DefaultParameters.md) property. |
| model | The chat completion model to use. If model is `null`, then the one specified in the [`DefaultModel`](../ChatGptOptions/DefaultModel.md) property will be used. |
| addToConversationHistory | Set to `true` to add the current chat interaction to the conversation history. |
| cancellationToken | The token to monitor for cancellation requests. |

## Return Value
Expand Down Expand Up @@ -128,7 +131,8 @@ Requests a chat interaction.
```csharp
public Task<ChatGptResponse> AskAsync(Guid conversationId, string message,
ChatGptFunctionParameters? functionParameters, ChatGptParameters? parameters = null,
string? model = null, CancellationToken cancellationToken = default)
string? model = null, bool addToConversationHistory = true,
CancellationToken cancellationToken = default)
```

| parameter | description |
Expand All @@ -138,6 +142,7 @@ public Task<ChatGptResponse> AskAsync(Guid conversationId, string message,
| functionParameters | A [`ChatGptFunctionParameters`](../../ChatGptNet.Models/ChatGptFunctionParameters.md) object that contains the list of available functions for calling. |
| parameters | A object used to override the default completion parameters in the [`DefaultParameters`](../ChatGptOptions/DefaultParameters.md) property. |
| model | The chat completion model to use. If model is `null`, then the one specified in the [`DefaultModel`](../ChatGptOptions/DefaultModel.md) property will be used. |
| addToConversationHistory | Set to `true` to add the current chat interaction to the conversation history. |
| cancellationToken | The token to monitor for cancellation requests. |

## Return Value
Expand Down
7 changes: 5 additions & 2 deletions docs/ChatGptNet/IChatGptClient/AskStreamAsync.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ Requests a new chat interaction (using the default completion model specified in

```csharp
public IAsyncEnumerable<ChatGptResponse> AskStreamAsync(string message,
ChatGptParameters? parameters = null, CancellationToken cancellationToken = default)
ChatGptParameters? parameters = null, bool addToConversationHistory = true,
CancellationToken cancellationToken = default)
```

| parameter | description |
| --- | --- |
| message | The message. |
| parameters | A [`ChatGptParameters`](../../ChatGptNet.Models/ChatGptParameters.md) object used to override the default completion parameters in the [`DefaultParameters`](../ChatGptOptions/DefaultParameters.md) property. |
| addToConversationHistory | Set to `true` to add the current chat interaction to the conversation history. |
| cancellationToken | The token to monitor for cancellation requests. |

## Return Value
Expand Down Expand Up @@ -44,7 +46,7 @@ Requests a chat interaction with streaming response, like in ChatGPT.
```csharp
public IAsyncEnumerable<ChatGptResponse> AskStreamAsync(Guid conversationId, string message,
ChatGptParameters? parameters = null, string? model = null,
CancellationToken cancellationToken = default)
bool addToConversationHistory = true, CancellationToken cancellationToken = default)
```

| parameter | description |
Expand All @@ -53,6 +55,7 @@ public IAsyncEnumerable<ChatGptResponse> AskStreamAsync(Guid conversationId, str
| message | The message. |
| parameters | A [`ChatGptParameters`](../../ChatGptNet.Models/ChatGptParameters.md) object used to override the default completion parameters in the [`DefaultParameters`](../ChatGptOptions/DefaultParameters.md) property. |
| model | The chat completion model to use. If model is `null`, then the one specified in the [`DefaultModel`](../ChatGptOptions/DefaultModel.md) property will be used. |
| addToConversationHistory | Set to `true` to add the current chat interaction to the conversation history. |
| cancellationToken | The token to monitor for cancellation requests. |

## Return Value
Expand Down
3 changes: 2 additions & 1 deletion docs/ChatGptNet/IChatGptClient/LoadConversationAsync.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@ The unique identifier of the new conversation.

## Remarks

This method creates a new conversation with a random Conversation Id. Then, call [`AskAsync`](./AskAsync.md) with this Id to start the actual conversation.
This method creates a new conversation with a random Conversation Id. Then, call [`AskAsync`](./AskAsync.md) or [`AskStreamAsync`](./AskStreamAsync.md) with this Id to start the actual conversation.

The total number of messages never exceeds the message limit defined in [`MessageLimit`](../ChatGptOptions/MessageLimit.md). If *messages* contains more, only the latest ones are loaded.

## See Also

* property [MessageLimit](../ChatGptOptions/MessageLimit.md)
* method [AskAsync](./AskAsync.md)
* method [AskStreamAsync](./AskStreamAsync.md)
* class [ChatGptMessage](../../ChatGptNet.Models/ChatGptMessage.md)
* interface [IChatGptClient](../IChatGptClient.md)
Expand Down
2 changes: 1 addition & 1 deletion samples/ChatGptApi/ChatGptApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.9" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.10" />
<PackageReference Include="MinimalHelpers.OpenApi" Version="1.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions samples/ChatGptApi/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ async IAsyncEnumerable<string> Stream()
})
.WithOpenApi();

app.MapDelete("/api/chat/{conversationId:guid}", async (Guid conversationId, IChatGptClient chatGptClient) =>
app.MapDelete("/api/chat/{conversationId:guid}", async (Guid conversationId, bool? preserveSetup, IChatGptClient chatGptClient) =>
{
await chatGptClient.DeleteConversationAsync(conversationId);
await chatGptClient.DeleteConversationAsync(conversationId, preserveSetup.GetValueOrDefault());
return TypedResults.NoContent();
})
.WithOpenApi();
Expand Down
6 changes: 3 additions & 3 deletions samples/ChatGptBlazor.Wasm/ChatGptBlazor.Wasm.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Markdig" Version="0.31.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.9" PrivateAssets="all" />
<PackageReference Include="Markdig" Version="0.32.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="7.0.10" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="7.0.10" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions samples/ChatGptConsole/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ static void ConfigureServices(HostBuilderContext context, IServiceCollection ser

public class LocalMessageCache : IChatGptCache
{
private readonly Dictionary<Guid, List<ChatGptMessage>> localCache = new();
private readonly Dictionary<Guid, IEnumerable<ChatGptMessage>> localCache = new();

public Task SetAsync(Guid conversationId, IEnumerable<ChatGptMessage> messages, TimeSpan expiration, CancellationToken cancellationToken = default)
{
localCache[conversationId] = messages.ToList();
return Task.CompletedTask;
}
public Task<List<ChatGptMessage>?> GetAsync(Guid conversationId, CancellationToken cancellationToken = default)
public Task<IEnumerable<ChatGptMessage>?> GetAsync(Guid conversationId, CancellationToken cancellationToken = default)
{
localCache.TryGetValue(conversationId, out var messages);
return Task.FromResult(messages);
Expand Down
4 changes: 2 additions & 2 deletions samples/ChatGptFunctionCallingConsole/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,14 @@ static void ConfigureServices(HostBuilderContext context, IServiceCollection ser

public class LocalMessageCache : IChatGptCache
{
private readonly Dictionary<Guid, List<ChatGptMessage>> localCache = new();
private readonly Dictionary<Guid, IEnumerable<ChatGptMessage>> localCache = new();

public Task SetAsync(Guid conversationId, IEnumerable<ChatGptMessage> messages, TimeSpan expiration, CancellationToken cancellationToken = default)
{
localCache[conversationId] = messages.ToList();
return Task.CompletedTask;
}
public Task<List<ChatGptMessage>?> GetAsync(Guid conversationId, CancellationToken cancellationToken = default)
public Task<IEnumerable<ChatGptMessage>?> GetAsync(Guid conversationId, CancellationToken cancellationToken = default)
{
localCache.TryGetValue(conversationId, out var messages);
return Task.FromResult(messages);
Expand Down
Loading

0 comments on commit 83f3ebb

Please sign in to comment.