-
Notifications
You must be signed in to change notification settings - Fork 5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Ongoing] Adding Marketing sample (#52)
* boilerplate init * agents work * agents * adding frontend * Now we can call the actor directly, and indireclty * Orleans packages need to be there in order serialization works. no clue why * horrible code, making the signlar hub static * more horrible code, now the frontend can send messages to the backend and receibe the answer * marketing works. a lot to fix still * adding a legal assistant * breaking agents * adding a signalr client * adding AlreadyExistentUser * cleaning up * renaming solution * cleaning to prep for push to upstream * cleaning in prep for upstream * cleaning and forcing agents to always have a state * removing legal-assistant for now * sln should not bethere * creating the class using new T * replacing Activator by where T : new * removing infra from marketing sample * Add state initialization in AiAgent * changing namespace name, and creating an agent to interact with signalr * signalr agent works fine. It just loops forever when connecting. I need to diferentiate if it already happened * init Readme.md * Using Semantic Kernel to run Dall-E * Graphic designer does not ened its own openai client anylonger
- Loading branch information
1 parent
615db4f
commit cbf4252
Showing
84 changed files
with
14,389 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# [In progress] Marketing Saple application | ||
|
||
This is a demo application that showcase the different features of the AI Agent framework. | ||
There are five agents in this application that control the different areas of the UI autonomously. | ||
|
||
The agents are designed to be able to interact with each other and the user to achieve their goals. | ||
To do that each agent has | ||
|
||
![Agents](readme-media/agents.png) | ||
|
||
|
||
## Requirements to run locally | ||
### Frontend | ||
The latest version of Node.js and npm | ||
|
||
### Backend | ||
Visual Studio or Visual Studio code and the latest version of dotnet | ||
|
||
## How to run the application locally | ||
|
||
Execute Run.ps1. IF you are missing the config file the script will create an empty one for you and ask you to fill it out. | ||
``` | ||
.\run.ps1 | ||
``` | ||
|
||
## How to debug the application locally | ||
To debug the backend, you can simply open the solution in Visual Studio, and press F5 to start debugging. | ||
Remember to copy `appsettings.local.template.json` to `appsettings.json` and fill out the values.</p> | ||
The frontend is a NodeJS React application. You can debug it using Visual Studio code. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json | ||
|
||
name: ai-dev-team | ||
services: | ||
gh-flow: | ||
project: "src/Microsoft.AI.DevTeam/Microsoft.AI.DevTeam.csproj" | ||
language: csharp | ||
host: containerapp | ||
docker: | ||
context: ../../../ |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
function New-MarketingBackendSettings { | ||
param( | ||
|
||
) | ||
if(Test-Path src/backend/appsettings.json) { | ||
Write-Host "appsettings.json already exists" | ||
return | ||
} | ||
|
||
Copy-Item src/backend/appsettings.local.template.json src/backend/appsettings.json | ||
Write-Host "appsettings.json created" | ||
|
||
if((Get-Content .\src\backend\appsettings.local.template.json -Raw | Select-String "<mandatory>") -ne $null) { | ||
Write-Error "Please update the appsettings.json file with the correct values" -ErrorAction Stop | ||
} | ||
} | ||
|
||
$backendProc = Start-Process powershell -ArgumentList '-NoExit', '-Command cd src/backend/; dotnet run' | ||
$frontendProc = Start-Process powershell -ArgumentList '-NoExit', '-Command cd src/frontend/; npm run dev' | ||
|
71 changes: 71 additions & 0 deletions
71
samples/marketing/src/backend/Agents/CommunityManager/CommunityManager.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
using Marketing.Events; | ||
using Marketing.Options; | ||
using Microsoft.AI.Agents.Abstractions; | ||
using Microsoft.AI.Agents.Orleans; | ||
using Microsoft.SemanticKernel; | ||
using Microsoft.SemanticKernel.Memory; | ||
using Orleans.Runtime; | ||
|
||
namespace Marketing.Agents; | ||
|
||
[ImplicitStreamSubscription(Consts.OrleansNamespace)] | ||
public class CommunityManager : AiAgent<CommunityManagerState> | ||
{ | ||
protected override string Namespace => Consts.OrleansNamespace; | ||
|
||
private readonly ILogger<GraphicDesigner> _logger; | ||
|
||
public CommunityManager([PersistentState("state", "messages")] IPersistentState<AgentState<CommunityManagerState>> state, Kernel kernel, ISemanticTextMemory memory, ILogger<GraphicDesigner> logger) | ||
: base(state, memory, kernel) | ||
{ | ||
_logger = logger; | ||
} | ||
|
||
public async override Task HandleEvent(Event item) | ||
{ | ||
switch (item.Type) | ||
{ | ||
case nameof(EventTypes.UserConnected): | ||
// The user reconnected, let's send the last message if we have one | ||
string lastMessage = _state.State.History.LastOrDefault()?.Message; | ||
if (lastMessage == null) | ||
{ | ||
return; | ||
} | ||
|
||
SendDesignedCreatedEvent(lastMessage, item.Data["UserId"]); | ||
break; | ||
|
||
case nameof(EventTypes.ArticleCreated): | ||
//var lastCode = _state.State.History.Last().Message; | ||
|
||
_logger.LogInformation($"[{nameof(GraphicDesigner)}] Event {nameof(EventTypes.ArticleCreated)}. UserMessage: {item.Message}"); | ||
|
||
var context = new KernelArguments { ["input"] = AppendChatHistory(item.Message) }; | ||
string socialMediaPost = await CallFunction(CommunityManagerPrompts.WritePost, context); | ||
_state.State.Data.WrittenSocialMediaPost = socialMediaPost; | ||
SendDesignedCreatedEvent(socialMediaPost, item.Data["UserId"]); | ||
break; | ||
|
||
default: | ||
break; | ||
} | ||
} | ||
|
||
private async Task SendDesignedCreatedEvent(string socialMediaPost, string userId) | ||
{ | ||
await PublishEvent(Consts.OrleansNamespace, this.GetPrimaryKeyString(), new Event | ||
{ | ||
Type = nameof(EventTypes.SocialMediaPostCreated), | ||
Data = new Dictionary<string, string> { | ||
{ "UserId", userId }, | ||
}, | ||
Message = socialMediaPost | ||
}); | ||
} | ||
|
||
public Task<String> GetArticle() | ||
{ | ||
return Task.FromResult(_state.State.Data.WrittenSocialMediaPost); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
samples/marketing/src/backend/Agents/CommunityManager/CommunityManagerPrompts.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
namespace Marketing.Agents; | ||
|
||
public static class CommunityManagerPrompts | ||
{ | ||
public static string WritePost = """ | ||
You are a Marketing community manager writer. | ||
Write a tweet to promote what it is described bellow. | ||
The tweet cannot be longer than 280 characters | ||
Input: {{$input}} | ||
"""; | ||
} |
8 changes: 8 additions & 0 deletions
8
samples/marketing/src/backend/Agents/CommunityManager/CommunityManagerState.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace Marketing.Agents; | ||
|
||
[GenerateSerializer] | ||
public class CommunityManagerState | ||
{ | ||
[Id(0)] | ||
public string WrittenSocialMediaPost { get; set; } | ||
} |
8 changes: 8 additions & 0 deletions
8
samples/marketing/src/backend/Agents/GraphicDesigner/GraphicDesignedState.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
namespace Marketing.Agents; | ||
|
||
[GenerateSerializer] | ||
public class GraphicDesignerState | ||
{ | ||
[Id(0)] | ||
public string imageUrl { get; set; } | ||
} |
70 changes: 70 additions & 0 deletions
70
samples/marketing/src/backend/Agents/GraphicDesigner/GraphicDesigner.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using Marketing.Events; | ||
using Marketing.Options; | ||
using Microsoft.AI.Agents.Abstractions; | ||
using Microsoft.AI.Agents.Orleans; | ||
using Microsoft.SemanticKernel; | ||
using Microsoft.SemanticKernel.Memory; | ||
using Microsoft.SemanticKernel.TextToImage; | ||
using Orleans.Runtime; | ||
|
||
namespace Marketing.Agents; | ||
|
||
[ImplicitStreamSubscription(Consts.OrleansNamespace)] | ||
public class GraphicDesigner : AiAgent<GraphicDesignerState> | ||
{ | ||
protected override string Namespace => Consts.OrleansNamespace; | ||
|
||
private readonly ILogger<GraphicDesigner> _logger; | ||
private readonly IConfiguration _configuration; | ||
|
||
public GraphicDesigner([PersistentState("state", "messages")] IPersistentState<AgentState<GraphicDesignerState>> state, Kernel kernel, ISemanticTextMemory memory, ILogger<GraphicDesigner> logger, IConfiguration configuration) | ||
: base(state, memory, kernel) | ||
{ | ||
_logger = logger; | ||
_configuration = configuration; | ||
} | ||
|
||
public async override Task HandleEvent(Event item) | ||
{ | ||
switch (item.Type) | ||
{ | ||
case nameof(EventTypes.UserConnected): | ||
// The user reconnected, let's send the last message if we have one | ||
string lastMessage = _state.State.History.LastOrDefault()?.Message; | ||
if (lastMessage == null) | ||
{ | ||
return; | ||
} | ||
|
||
SendDesignedCreatedEvent(lastMessage, item.Data["UserId"]); | ||
|
||
break; | ||
case nameof(EventTypes.ArticleCreated): | ||
_logger.LogInformation($"[{nameof(GraphicDesigner)}] Event {nameof(EventTypes.ArticleCreated)}. UserMessage: {item.Message}"); | ||
|
||
var dallEService = _kernel.GetRequiredService<ITextToImageService>(); | ||
var imageUri = await dallEService.GenerateImageAsync(item.Message, 1024, 1024); | ||
|
||
_state.State.Data.imageUrl = imageUri; | ||
|
||
SendDesignedCreatedEvent(imageUri, item.Data["UserId"]); | ||
|
||
break; | ||
|
||
default: | ||
break; | ||
} | ||
} | ||
|
||
private async Task SendDesignedCreatedEvent(string AbsoluteImageUri, string userId) | ||
{ | ||
await PublishEvent(Consts.OrleansNamespace, this.GetPrimaryKeyString(), new Event | ||
{ | ||
Type = nameof(EventTypes.GraphicDesignCreated), | ||
Data = new Dictionary<string, string> { | ||
{ "UserId", userId }, | ||
}, | ||
Message = AbsoluteImageUri | ||
}); | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
samples/marketing/src/backend/Agents/GraphicDesigner/GraphicDesignerPrompts.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
|
||
namespace Marketing.Agents; | ||
public static class GraphicDesignerPrompts | ||
{ | ||
public static string GenerateImage = """ | ||
You are a Marketing community manager graphic designer. | ||
Bellow is a campaing that you need to create a image for. | ||
Create an image of maximum 500x500 pixels that could be use in social medias as a marketing iamge. | ||
Input: {{$input}} | ||
"""; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
using Marketing.Events; | ||
using Marketing.Options; | ||
using Marketing.SignalRHub; | ||
using Microsoft.AI.Agents.Abstractions; | ||
using Microsoft.AI.Agents.Orleans; | ||
using System; | ||
using System.Security.Policy; | ||
|
||
namespace Marketing.Agents; | ||
|
||
[ImplicitStreamSubscription(Consts.OrleansNamespace)] | ||
public class SignalR : Agent | ||
{ | ||
protected override string Namespace => Consts.OrleansNamespace; | ||
|
||
private readonly ILogger<SignalR> _logger; | ||
private readonly ISignalRService _signalRClient; | ||
|
||
public SignalR(ILogger<SignalR> logger, ISignalRService signalRClient) | ||
{ | ||
_logger = logger; | ||
_signalRClient = signalRClient; | ||
} | ||
|
||
public async override Task HandleEvent(Event item) | ||
{ | ||
switch (item.Type) | ||
{ | ||
case nameof(EventTypes.ArticleCreated): | ||
var writenArticle = item.Message; | ||
await _signalRClient.SendMessageToSpecificClient(item.Data["UserId"], writenArticle, AgentTypes.Chat); | ||
break; | ||
|
||
case nameof(EventTypes.GraphicDesignCreated): | ||
var imageUrl = item.Message; | ||
await _signalRClient.SendMessageToSpecificClient(item.Data["UserId"], imageUrl, AgentTypes.GraphicDesigner); | ||
break; | ||
|
||
case nameof(EventTypes.SocialMediaPostCreated): | ||
var post = item.Message; | ||
await _signalRClient.SendMessageToSpecificClient(item.Data["UserId"], post, AgentTypes.CommunityManager); | ||
break; | ||
|
||
default: | ||
break; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
namespace Marketing.Agents; | ||
public interface IWriter : IGrainWithStringKey | ||
{ | ||
Task<String> GetArticle(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
using Marketing.Events; | ||
using Marketing.Options; | ||
using Microsoft.AI.Agents.Abstractions; | ||
using Microsoft.AI.Agents.Orleans; | ||
using Microsoft.SemanticKernel; | ||
using Microsoft.SemanticKernel.Memory; | ||
using Orleans.Runtime; | ||
|
||
namespace Marketing.Agents; | ||
|
||
[ImplicitStreamSubscription(Consts.OrleansNamespace)] | ||
public class Writer : AiAgent<WriterState>, IWriter | ||
{ | ||
protected override string Namespace => Consts.OrleansNamespace; | ||
|
||
private readonly ILogger<GraphicDesigner> _logger; | ||
|
||
public Writer([PersistentState("state", "messages")] IPersistentState<AgentState<WriterState>> state, Kernel kernel, ISemanticTextMemory memory, ILogger<GraphicDesigner> logger) | ||
: base(state, memory, kernel) | ||
{ | ||
_logger = logger; | ||
} | ||
|
||
public async override Task HandleEvent(Event item) | ||
{ | ||
switch (item.Type) | ||
{ | ||
case nameof(EventTypes.UserConnected): | ||
// The user reconnected, let's send the last message if we have one | ||
string lastMessage = _state.State.History.LastOrDefault()?.Message; | ||
if (lastMessage == null) | ||
{ | ||
return; | ||
} | ||
|
||
SendDesignedCreatedEvent(lastMessage, item.Data["UserId"]); | ||
|
||
break; | ||
|
||
case nameof(EventTypes.UserChatInput): | ||
|
||
_logger.LogInformation($"[{nameof(GraphicDesigner)}] Event {nameof(EventTypes.UserChatInput)}. UserMessage: {item.Message}"); | ||
|
||
var context = new KernelArguments { ["input"] = AppendChatHistory(item.Message) }; | ||
string newArticle = await CallFunction(WriterPrompts.Write, context); | ||
|
||
SendDesignedCreatedEvent(newArticle, item.Data["UserId"]); | ||
|
||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
|
||
private async Task SendDesignedCreatedEvent(string writtenArticle, string userId) | ||
{ | ||
await PublishEvent(Consts.OrleansNamespace, this.GetPrimaryKeyString(), new Event | ||
{ | ||
Type = nameof(EventTypes.ArticleCreated), | ||
Data = new Dictionary<string, string> { | ||
{ "UserId", userId }, | ||
{ "UserMessage", writtenArticle }, | ||
}, | ||
Message = writtenArticle | ||
}); | ||
} | ||
|
||
|
||
public Task<String> GetArticle() | ||
{ | ||
return Task.FromResult(_state.State.Data.WrittenArticle); | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
samples/marketing/src/backend/Agents/Writer/WriterPrompts.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
|
||
namespace Marketing.Agents; | ||
public static class WriterPrompts | ||
{ | ||
public static string Write = """ | ||
You are a Marketing writer. | ||
Write up to three paragraphs for a campain to promote what it is described bellow. | ||
Bellow are a series of inputs from the user that you can use to create the campain. | ||
If the input talks about twitter or images, dismiss it and return the same as before. | ||
Input: {{$input}} | ||
"""; | ||
} |
Oops, something went wrong.