Skip to content

Commit

Permalink
1️⃣2️⃣ piratize todoitems with ai
Browse files Browse the repository at this point in the history
  • Loading branch information
Ami Hollander committed Jan 12, 2024
1 parent b1172f4 commit cae89c6
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 1 deletion.
108 changes: 108 additions & 0 deletions src/backend/CosmosTodoItemAITrigger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
using System.Collections.Generic;
using Microsoft.Azure.WebJobs;
using backend.Models;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Azure.AI.OpenAI;
using Azure;
using System;
using System.Linq;

namespace backend
{
public class CosmosTodoItemAITrigger
{
private readonly OpenAIClient _openAIClient;

public CosmosTodoItemAITrigger(OpenAIClient openAIClient)
{
_openAIClient = openAIClient;
}

[FunctionName("CosmosTodoItemAITrigger")]
public async Task Run(
[CosmosDBTrigger(
databaseName: "%CosmosDatabaseName%",
containerName: "TodoItem",
Connection = "CosmosConnectionOptions",
LeaseContainerName = "Leases",
StartFromBeginning = true,
LeaseContainerPrefix = "ai",
CreateLeaseContainerIfNotExists = false)] IReadOnlyList<TodoItem> input,
[CosmosDB(
databaseName: "%CosmosDatabaseName%",
containerName: "TodoItem",
Connection = "CosmosConnectionOptions")]
IAsyncCollector<TodoItem> output,
[DurableClient] IDurableEntityClient durableEntityClient)
{
var exceptions = new List<Exception>();

if (input != null && input.Count > 0)
{
foreach (var item in input)
{
try
{
var piratized = await Piratize(output, item);

if (piratized)
{
await UpdateDbDescription(output, item);
}
}
catch (Exception e)
{
// We need to keep processing the rest of the batch - capture this exception and continue.
// Also, consider capturing details of the message that failed processing so it can be processed again later.
exceptions.Add(e);
}
}
}

// Once processing of the batch is complete, if any messages in the batch failed processing throw an exception so that there is a record of the failure.

if (exceptions.Count > 1)
throw new AggregateException(exceptions);

if (exceptions.Count == 1)
throw exceptions.Single();
}

private async Task<bool> Piratize(IAsyncCollector<TodoItem> output, TodoItem item)
{
if (!string.IsNullOrWhiteSpace(item.Description) && item.Description.StartsWith("[ASSISTANT]"))
{
return false;
}

var input = string.IsNullOrWhiteSpace(item.Description) ? item.Name : item.Description;

var chatCompletionsOptions = new ChatCompletionsOptions()
{
DeploymentName = "gpt-35-turbo-16k",
Messages =
{
new ChatRequestSystemMessage("You are a helpful assistant. You will talk like a pirate. Rephrase, fix grammer, and create a todo task."),

new ChatRequestUserMessage(input),
}
};

Response<ChatCompletions> response = await _openAIClient.GetChatCompletionsAsync(chatCompletionsOptions);
ChatResponseMessage responseMessage = response.Value.Choices[0].Message;

item.Description = $"[ASSISTANT]: {responseMessage.Content}";

return true;
}

private async Task<bool> UpdateDbDescription(IAsyncCollector<TodoItem> output, TodoItem item)
{
item.UpdatedDate = DateTimeOffset.UtcNow.DateTime;
await output.AddAsync(item);

return true;
}
}
}
20 changes: 20 additions & 0 deletions src/backend/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Azure;
using Azure.AI.OpenAI;
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.Azure.Cosmos;
Expand Down Expand Up @@ -44,6 +46,24 @@ public override void Configure(IFunctionsHostBuilder builder)
return new CosmosClientBuilder(accountEndpoint, defaultAzureCredentials).Build();
})
.AddSingleton<OpenAIClient>(serviceProvider =>
{
var azureOpenAIEndpoint = Environment.GetEnvironmentVariable("AzureOpenAIEndpoint");
Uri azureOpenAIResourceUri = new(azureOpenAIEndpoint);
var keyVaultUri = new Uri(Environment.GetEnvironmentVariable("KeyVaultEndpoint"));
var httpClient = serviceProvider.GetService<HttpClient>();
var defaultAzureCredentials = serviceProvider.GetService<DefaultAzureCredential>();
// Retrieve apiKey from KeyVault
var secretClient = new SecretClient(keyVaultUri, defaultAzureCredentials);
var azureResponseKeyVaultSecret = new Lazy<Task<Azure.Response<KeyVaultSecret>>>(async () => await secretClient.GetSecretAsync("AZURE-OPEN-AI-KEY"));
var openAIApiKey = azureResponseKeyVaultSecret.Value.Result.Value.Value;
AzureKeyCredential azureOpenAIApiKey = new(openAIApiKey);
return new OpenAIClient(azureOpenAIResourceUri, azureOpenAIApiKey);
})
.AddHealthChecks();
}
}
Expand Down
1 change: 1 addition & 0 deletions src/backend/Todo.Backend.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" Version="1.0.0-beta.12" />
<PackageReference Include="Azure.Identity" Version="1.10.4" />
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.5.0" />
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.35.3" />
Expand Down
3 changes: 2 additions & 1 deletion src/backend/local.settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"EventHubRequestsName": "<eventhub-name>",
"EventHubRequestsConnectionOptions__fullyQualifiedNamespace": "<eventhub-namespace-endpoint>",
"EventHubRequestsConsumerGroup": "<consumer-group>",
"KeyVaultEndpoint": "<keyvault-endpoint>"
"KeyVaultEndpoint": "<keyvault-endpoint>",
"AzureOpenAIEndpoint": "<openai-endpoint>"
}
}

0 comments on commit cae89c6

Please sign in to comment.