Skip to content

Commit cbf4252

Browse files
authored
[Ongoing] Adding Marketing sample (autogenhub#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
1 parent 615db4f commit cbf4252

File tree

84 files changed

+14389
-19
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+14389
-19
lines changed

samples/marketing/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# [In progress] Marketing Saple application
2+
3+
This is a demo application that showcase the different features of the AI Agent framework.
4+
There are five agents in this application that control the different areas of the UI autonomously.
5+
6+
The agents are designed to be able to interact with each other and the user to achieve their goals.
7+
To do that each agent has
8+
9+
![Agents](readme-media/agents.png)
10+
11+
12+
## Requirements to run locally
13+
### Frontend
14+
The latest version of Node.js and npm
15+
16+
### Backend
17+
Visual Studio or Visual Studio code and the latest version of dotnet
18+
19+
## How to run the application locally
20+
21+
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.
22+
```
23+
.\run.ps1
24+
```
25+
26+
## How to debug the application locally
27+
To debug the backend, you can simply open the solution in Visual Studio, and press F5 to start debugging.
28+
Remember to copy `appsettings.local.template.json` to `appsettings.json` and fill out the values.</p>
29+
The frontend is a NodeJS React application. You can debug it using Visual Studio code.

samples/marketing/azure.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
2+
3+
name: ai-dev-team
4+
services:
5+
gh-flow:
6+
project: "src/Microsoft.AI.DevTeam/Microsoft.AI.DevTeam.csproj"
7+
language: csharp
8+
host: containerapp
9+
docker:
10+
context: ../../../
905 KB
Loading

samples/marketing/run.ps1

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
function New-MarketingBackendSettings {
2+
param(
3+
4+
)
5+
if(Test-Path src/backend/appsettings.json) {
6+
Write-Host "appsettings.json already exists"
7+
return
8+
}
9+
10+
Copy-Item src/backend/appsettings.local.template.json src/backend/appsettings.json
11+
Write-Host "appsettings.json created"
12+
13+
if((Get-Content .\src\backend\appsettings.local.template.json -Raw | Select-String "<mandatory>") -ne $null) {
14+
Write-Error "Please update the appsettings.json file with the correct values" -ErrorAction Stop
15+
}
16+
}
17+
18+
$backendProc = Start-Process powershell -ArgumentList '-NoExit', '-Command cd src/backend/; dotnet run'
19+
$frontendProc = Start-Process powershell -ArgumentList '-NoExit', '-Command cd src/frontend/; npm run dev'
20+
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using Marketing.Events;
2+
using Marketing.Options;
3+
using Microsoft.AI.Agents.Abstractions;
4+
using Microsoft.AI.Agents.Orleans;
5+
using Microsoft.SemanticKernel;
6+
using Microsoft.SemanticKernel.Memory;
7+
using Orleans.Runtime;
8+
9+
namespace Marketing.Agents;
10+
11+
[ImplicitStreamSubscription(Consts.OrleansNamespace)]
12+
public class CommunityManager : AiAgent<CommunityManagerState>
13+
{
14+
protected override string Namespace => Consts.OrleansNamespace;
15+
16+
private readonly ILogger<GraphicDesigner> _logger;
17+
18+
public CommunityManager([PersistentState("state", "messages")] IPersistentState<AgentState<CommunityManagerState>> state, Kernel kernel, ISemanticTextMemory memory, ILogger<GraphicDesigner> logger)
19+
: base(state, memory, kernel)
20+
{
21+
_logger = logger;
22+
}
23+
24+
public async override Task HandleEvent(Event item)
25+
{
26+
switch (item.Type)
27+
{
28+
case nameof(EventTypes.UserConnected):
29+
// The user reconnected, let's send the last message if we have one
30+
string lastMessage = _state.State.History.LastOrDefault()?.Message;
31+
if (lastMessage == null)
32+
{
33+
return;
34+
}
35+
36+
SendDesignedCreatedEvent(lastMessage, item.Data["UserId"]);
37+
break;
38+
39+
case nameof(EventTypes.ArticleCreated):
40+
//var lastCode = _state.State.History.Last().Message;
41+
42+
_logger.LogInformation($"[{nameof(GraphicDesigner)}] Event {nameof(EventTypes.ArticleCreated)}. UserMessage: {item.Message}");
43+
44+
var context = new KernelArguments { ["input"] = AppendChatHistory(item.Message) };
45+
string socialMediaPost = await CallFunction(CommunityManagerPrompts.WritePost, context);
46+
_state.State.Data.WrittenSocialMediaPost = socialMediaPost;
47+
SendDesignedCreatedEvent(socialMediaPost, item.Data["UserId"]);
48+
break;
49+
50+
default:
51+
break;
52+
}
53+
}
54+
55+
private async Task SendDesignedCreatedEvent(string socialMediaPost, string userId)
56+
{
57+
await PublishEvent(Consts.OrleansNamespace, this.GetPrimaryKeyString(), new Event
58+
{
59+
Type = nameof(EventTypes.SocialMediaPostCreated),
60+
Data = new Dictionary<string, string> {
61+
{ "UserId", userId },
62+
},
63+
Message = socialMediaPost
64+
});
65+
}
66+
67+
public Task<String> GetArticle()
68+
{
69+
return Task.FromResult(_state.State.Data.WrittenSocialMediaPost);
70+
}
71+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Marketing.Agents;
2+
3+
public static class CommunityManagerPrompts
4+
{
5+
public static string WritePost = """
6+
You are a Marketing community manager writer.
7+
Write a tweet to promote what it is described bellow.
8+
The tweet cannot be longer than 280 characters
9+
Input: {{$input}}
10+
""";
11+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Marketing.Agents;
2+
3+
[GenerateSerializer]
4+
public class CommunityManagerState
5+
{
6+
[Id(0)]
7+
public string WrittenSocialMediaPost { get; set; }
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Marketing.Agents;
2+
3+
[GenerateSerializer]
4+
public class GraphicDesignerState
5+
{
6+
[Id(0)]
7+
public string imageUrl { get; set; }
8+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using Marketing.Events;
2+
using Marketing.Options;
3+
using Microsoft.AI.Agents.Abstractions;
4+
using Microsoft.AI.Agents.Orleans;
5+
using Microsoft.SemanticKernel;
6+
using Microsoft.SemanticKernel.Memory;
7+
using Microsoft.SemanticKernel.TextToImage;
8+
using Orleans.Runtime;
9+
10+
namespace Marketing.Agents;
11+
12+
[ImplicitStreamSubscription(Consts.OrleansNamespace)]
13+
public class GraphicDesigner : AiAgent<GraphicDesignerState>
14+
{
15+
protected override string Namespace => Consts.OrleansNamespace;
16+
17+
private readonly ILogger<GraphicDesigner> _logger;
18+
private readonly IConfiguration _configuration;
19+
20+
public GraphicDesigner([PersistentState("state", "messages")] IPersistentState<AgentState<GraphicDesignerState>> state, Kernel kernel, ISemanticTextMemory memory, ILogger<GraphicDesigner> logger, IConfiguration configuration)
21+
: base(state, memory, kernel)
22+
{
23+
_logger = logger;
24+
_configuration = configuration;
25+
}
26+
27+
public async override Task HandleEvent(Event item)
28+
{
29+
switch (item.Type)
30+
{
31+
case nameof(EventTypes.UserConnected):
32+
// The user reconnected, let's send the last message if we have one
33+
string lastMessage = _state.State.History.LastOrDefault()?.Message;
34+
if (lastMessage == null)
35+
{
36+
return;
37+
}
38+
39+
SendDesignedCreatedEvent(lastMessage, item.Data["UserId"]);
40+
41+
break;
42+
case nameof(EventTypes.ArticleCreated):
43+
_logger.LogInformation($"[{nameof(GraphicDesigner)}] Event {nameof(EventTypes.ArticleCreated)}. UserMessage: {item.Message}");
44+
45+
var dallEService = _kernel.GetRequiredService<ITextToImageService>();
46+
var imageUri = await dallEService.GenerateImageAsync(item.Message, 1024, 1024);
47+
48+
_state.State.Data.imageUrl = imageUri;
49+
50+
SendDesignedCreatedEvent(imageUri, item.Data["UserId"]);
51+
52+
break;
53+
54+
default:
55+
break;
56+
}
57+
}
58+
59+
private async Task SendDesignedCreatedEvent(string AbsoluteImageUri, string userId)
60+
{
61+
await PublishEvent(Consts.OrleansNamespace, this.GetPrimaryKeyString(), new Event
62+
{
63+
Type = nameof(EventTypes.GraphicDesignCreated),
64+
Data = new Dictionary<string, string> {
65+
{ "UserId", userId },
66+
},
67+
Message = AbsoluteImageUri
68+
});
69+
}
70+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
namespace Marketing.Agents;
3+
public static class GraphicDesignerPrompts
4+
{
5+
public static string GenerateImage = """
6+
You are a Marketing community manager graphic designer.
7+
Bellow is a campaing that you need to create a image for.
8+
Create an image of maximum 500x500 pixels that could be use in social medias as a marketing iamge.
9+
Input: {{$input}}
10+
""";
11+
}

0 commit comments

Comments
 (0)