Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AI Chatbot using AWS Bedrock #84

Merged
merged 11 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Prerequisites:
* [ActivitySimple](src/ActivitySimple) - Simple workflow that runs simple activities.
* [ActivityWorker](src/ActivityWorker) - Use .NET activities from a workflow in another language.
* [AspNet](src/AspNet) - Demonstration of a generic host worker and an ASP.NET workflow starter.
* [Bedrock](src/Bedrock) - Orchestrate a chatbot with Amazon Bedrock.
* [ClientMtls](src/ClientMtls) - How to use client certificate authentication, e.g. for Temporal Cloud.
* [ContextPropagation](src/ContextPropagation) - Context propagation via interceptors.
* [CounterInterceptor](src/CounterInterceptor/) - Simple Workflow and Client Interceptors example.
Expand Down
31 changes: 31 additions & 0 deletions TemporalioSamples.sln
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemporalioSamples.CounterIn
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemporalioSamples.Patching", "src\Patching\TemporalioSamples.Patching.csproj", "{751E0AF8-62EE-4220-A571-D1C53DD0D45A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemporalioSamples.SignalsQueries", "src\SignalsQueries\TemporalioSamples.SignalsQueries.csproj", "{4EA37A92-E4D5-4348-AF2F-0CAE37A1E079}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Bedrock", "Bedrock", "{5339989C-3791-4D75-A9F1-42620C443D4A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemporalioSamples.Bedrock.Basic", "src\Bedrock\Basic\TemporalioSamples.Bedrock.Basic.csproj", "{CC3487CB-F795-4CA9-A4F6-28C145AE383B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemporalioSamples.Bedrock.SignalsAndQueries", "src\Bedrock\SignalsAndQueries\TemporalioSamples.Bedrock.SignalsAndQueries.csproj", "{4E69DE72-E972-4155-B4D1-ABFE0B054ECF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemporalioSamples.Bedrock.Entity", "src\Bedrock\Entity\TemporalioSamples.Bedrock.Entity.csproj", "{AE18875F-B7D2-4A3C-8784-15B76277D508}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -167,6 +177,22 @@ Global
{751E0AF8-62EE-4220-A571-D1C53DD0D45A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{751E0AF8-62EE-4220-A571-D1C53DD0D45A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{751E0AF8-62EE-4220-A571-D1C53DD0D45A}.Release|Any CPU.Build.0 = Release|Any CPU
{4EA37A92-E4D5-4348-AF2F-0CAE37A1E079}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EA37A92-E4D5-4348-AF2F-0CAE37A1E079}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EA37A92-E4D5-4348-AF2F-0CAE37A1E079}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EA37A92-E4D5-4348-AF2F-0CAE37A1E079}.Release|Any CPU.Build.0 = Release|Any CPU
{CC3487CB-F795-4CA9-A4F6-28C145AE383B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CC3487CB-F795-4CA9-A4F6-28C145AE383B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC3487CB-F795-4CA9-A4F6-28C145AE383B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC3487CB-F795-4CA9-A4F6-28C145AE383B}.Release|Any CPU.Build.0 = Release|Any CPU
{4E69DE72-E972-4155-B4D1-ABFE0B054ECF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E69DE72-E972-4155-B4D1-ABFE0B054ECF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E69DE72-E972-4155-B4D1-ABFE0B054ECF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E69DE72-E972-4155-B4D1-ABFE0B054ECF}.Release|Any CPU.Build.0 = Release|Any CPU
{AE18875F-B7D2-4A3C-8784-15B76277D508}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AE18875F-B7D2-4A3C-8784-15B76277D508}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE18875F-B7D2-4A3C-8784-15B76277D508}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE18875F-B7D2-4A3C-8784-15B76277D508}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -199,5 +225,10 @@ Global
{FAF5984A-5B1C-4686-B056-A4F2AC0E8EB7} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC}
{F9C44936-8BF9-4919-BB66-8F1888E22AEB} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC}
{751E0AF8-62EE-4220-A571-D1C53DD0D45A} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC}
{4EA37A92-E4D5-4348-AF2F-0CAE37A1E079} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC}
{5339989C-3791-4D75-A9F1-42620C443D4A} = {1A647B41-53D0-4638-AE5A-6630BAAE45FC}
{CC3487CB-F795-4CA9-A4F6-28C145AE383B} = {5339989C-3791-4D75-A9F1-42620C443D4A}
{4E69DE72-E972-4155-B4D1-ABFE0B054ECF} = {5339989C-3791-4D75-A9F1-42620C443D4A}
{AE18875F-B7D2-4A3C-8784-15B76277D508} = {5339989C-3791-4D75-A9F1-42620C443D4A}
EndGlobalSection
EndGlobal
39 changes: 39 additions & 0 deletions src/Bedrock/Basic/BedrockActivities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Amazon.BedrockRuntime;
using Amazon.BedrockRuntime.Model;
using Temporalio.Activities;

namespace TemporalioSamples.Bedrock.Basic;

public class BedrockActivities(IAmazonBedrockRuntime bedrock)
{
public record PromptArgs(string Prompt);

public record PromptResult(string Response);

[Activity]
public async Task<PromptResult> PromptBedrockAsync(PromptArgs args)
{
var body = JsonSerializer.Serialize(new
{
prompt = args.Prompt,
max_gen_len = 512,
temperature = 0.1,
top_p = 0.2,
});

var request = new InvokeModelRequest
{
ModelId = "meta.llama3-1-70b-instruct-v1:0",
Accept = "application/json",
ContentType = "application/json",
Body = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(body)),
};

var response = await bedrock.InvokeModelAsync(request);
var modelResponse = await JsonNode.ParseAsync(response.Body);
var responseText = modelResponse?["generation"]?.ToString() ?? string.Empty;
return new(responseText);
}
}
29 changes: 29 additions & 0 deletions src/Bedrock/Basic/BedrockWorkflow.workflow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Microsoft.Extensions.Logging;
using Temporalio.Workflows;

namespace TemporalioSamples.Bedrock.Basic;

[Workflow]
public class BedrockWorkflow
{
public record WorkflowArgs(string Prompt);

public record WorkflowResult(string Response);

[WorkflowRun]
public async Task<WorkflowResult> RunAsync(WorkflowArgs args)
{
Workflow.Logger.LogInformation("Prompt: {Prompt}", args.Prompt);

var promptResult = await Workflow.ExecuteActivityAsync(
(BedrockActivities activities) => activities.PromptBedrockAsync(new(args.Prompt)),
new()
{
StartToCloseTimeout = TimeSpan.FromSeconds(20),
});

Workflow.Logger.LogInformation("Response:\n{Response}", promptResult.Response);

return new(promptResult.Response);
}
}
69 changes: 69 additions & 0 deletions src/Bedrock/Basic/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Amazon.BedrockRuntime;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Temporalio.Client;
using Temporalio.Extensions.Hosting;
using TemporalioSamples.Bedrock.Basic;

async Task RunWorkerAsync()
{
var builder = Host.CreateApplicationBuilder(args);

builder.Logging.
SetMinimumLevel(LogLevel.Information).
AddSimpleConsole(options => options.SingleLine = true);

builder.Services.AddSingleton<IAmazonBedrockRuntime>(_ => new AmazonBedrockRuntimeClient());

builder.Services.
AddHostedTemporalWorker(clientTargetHost: "localhost:7233", clientNamespace: "default", taskQueue: "basic-bedrock-task-queue").
AddSingletonActivities<BedrockActivities>().
AddWorkflow<BedrockWorkflow>();

var app = builder.Build();
await app.RunAsync();
}

async Task SendMessageAsync()
{
var prompt = args.ElementAtOrDefault(1);
if (prompt is null)
{
Console.WriteLine("Usage: dotnet run send-message '<prompt>'");
Console.WriteLine("Example: dotnet run send-message 'What animals are marsupials?'");
return;
}

var client = await CreateClientAsync();
var workflowId = "basic-bedrock-workflow";

// Start the workflow
var result = await client.ExecuteWorkflowAsync(
(BedrockWorkflow workflow) =>
workflow.RunAsync(new(prompt)),
new WorkflowOptions(workflowId, "basic-bedrock-task-queue"));

Console.WriteLine($"Result: {result.Response}");
}

async Task<ITemporalClient> CreateClientAsync() =>
await TemporalClient.ConnectAsync(new("localhost:7233")
{
LoggerFactory = LoggerFactory.Create(builder =>
builder.
AddSimpleConsole(options => options.TimestampFormat = "[HH:mm:ss] ").
SetMinimumLevel(LogLevel.Information)),
});

switch (args.ElementAtOrDefault(0))
{
case "worker":
await RunWorkerAsync();
break;
case "send-message":
await SendMessageAsync();
break;
default:
throw new ArgumentException("Must pass 'worker' or 'send-message' as the single argument");
}
10 changes: 10 additions & 0 deletions src/Bedrock/Basic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Basic Amazon Bedrock workflow

A basic Bedrock workflow. Starts a workflow with a prompt, generates a response and ends the workflow.

To run, first see `Bedrock` [README.md](../README.md) for prerequisites specific to this sample. Once set up, run the following from this directory:

1. Run the worker: `dotnet run worker`
2. In another terminal run the client with a prompt:

e.g. `dotnet run send-message 'What animals are marsupials?'`
11 changes: 11 additions & 0 deletions src/Bedrock/Basic/TemporalioSamples.Bedrock.Basic.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AWSSDK.BedrockRuntime" Version="3.7.401.11" />
</ItemGroup>

</Project>
39 changes: 39 additions & 0 deletions src/Bedrock/Entity/BedrockActivities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Text.Json;
using System.Text.Json.Nodes;
using Amazon.BedrockRuntime;
using Amazon.BedrockRuntime.Model;
using Temporalio.Activities;

namespace TemporalioSamples.Bedrock.Entity;

public class BedrockActivities(IAmazonBedrockRuntime bedrock)
{
public record PromptArgs(string Prompt);

public record PromptResult(string Response);

[Activity]
public async Task<PromptResult> PromptBedrockAsync(PromptArgs args)
{
var body = JsonSerializer.Serialize(new
{
prompt = args.Prompt,
max_gen_len = 512,
temperature = 0.1,
top_p = 0.2,
});

var request = new InvokeModelRequest
{
ModelId = "meta.llama3-1-70b-instruct-v1:0",
Accept = "application/json",
ContentType = "application/json",
Body = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(body)),
};

var response = await bedrock.InvokeModelAsync(request);
var modelResponse = await JsonNode.ParseAsync(response.Body);
var responseText = modelResponse?["generation"]?.ToString() ?? string.Empty;
return new(responseText);
}
}
Loading