From 9597c6a43484f6f6990a5abb37bb1fecfd9e81f3 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Lalicata Date: Mon, 26 Aug 2024 12:54:43 +0200 Subject: [PATCH] some demo-for changes --- .../src/backend/Agents/Auditor/Auditor.cs | 5 - .../backend/Agents/Auditor/AuditorPrompts.cs | 1 - .../CommunityManager/CommunityManager.cs | 22 ++- .../CommunityManagerPrompts.cs | 13 ++ .../Agents/GraphicDesigner/GraphicDesigner.cs | 20 +- .../ManufacturingManager.cs | 56 ++++++ .../ManufacturingManagerPrompt.cs | 16 ++ .../ManufacturingManagerState.cs | 8 + .../src/backend/Agents/Notary/INotary.cs | 9 + .../src/backend/Agents/Notary/Notary.cs | 43 ++++ .../src/backend/Agents/Notary/NotaryState.cs | 9 + .../Agents/SalesAnalyst/SalesAnalyst.cs | 11 +- .../Agents/SalesAnalyst/SalesAnalystPrompt.cs | 2 +- .../src/backend/Agents/SignalR/SignalR.cs | 8 +- .../src/backend/Agents/Writer/Writer.cs | 16 +- .../backend/Controller/EventsController.cs | 28 +++ .../src/backend/Events/EventTypes.cs | 2 +- .../src/backend/SignalRHub/AgentTypes.cs | 3 +- .../frontend/src/app/marketing/costs/cost.tsx | 8 +- .../frontend/src/app/marketing/docs/docs.tsx | 4 +- .../manufacturing-manager/manufacturing.tsx | 187 ++++++++++++++++++ .../src/frontend/src/app/marketing/page.tsx | 32 ++- .../marketing/stakeholders/stakeholders.tsx | 59 ------ 23 files changed, 453 insertions(+), 109 deletions(-) create mode 100644 samples/marketing/src/backend/Agents/ManufacturingManager/ManufacturingManager.cs create mode 100644 samples/marketing/src/backend/Agents/ManufacturingManager/ManufacturingManagerPrompt.cs create mode 100644 samples/marketing/src/backend/Agents/ManufacturingManager/ManufacturingManagerState.cs create mode 100644 samples/marketing/src/backend/Agents/Notary/INotary.cs create mode 100644 samples/marketing/src/backend/Agents/Notary/Notary.cs create mode 100644 samples/marketing/src/backend/Agents/Notary/NotaryState.cs create mode 100644 samples/marketing/src/backend/Controller/EventsController.cs create mode 100644 samples/marketing/src/frontend/src/app/marketing/manufacturing-manager/manufacturing.tsx diff --git a/samples/marketing/src/backend/Agents/Auditor/Auditor.cs b/samples/marketing/src/backend/Agents/Auditor/Auditor.cs index b3f12247..c003892d 100644 --- a/samples/marketing/src/backend/Agents/Auditor/Auditor.cs +++ b/samples/marketing/src/backend/Agents/Auditor/Auditor.cs @@ -32,14 +32,9 @@ public async override Task HandleEvent(Event item) var context = new KernelArguments { ["input"] = AppendChatHistory(article) }; string auditorAnswer = await CallFunction(AuditorPrompts.AuditText, context); - if (auditorAnswer.Contains("NOTFORME")) - { - return; - } if (auditorAnswer.Contains("AUDITOK")) { await SendAuditorOkEvent(auditorAnswer, article, item.Data["SessionId"]); - } else { diff --git a/samples/marketing/src/backend/Agents/Auditor/AuditorPrompts.cs b/samples/marketing/src/backend/Agents/Auditor/AuditorPrompts.cs index e4fb7f1c..b84f6349 100644 --- a/samples/marketing/src/backend/Agents/Auditor/AuditorPrompts.cs +++ b/samples/marketing/src/backend/Agents/Auditor/AuditorPrompts.cs @@ -7,7 +7,6 @@ You are an Auditor in a Marketing team Audit the text bello and make sure we do not give discounts larger than 10% If the text talks about a larger than 50% discount, reply with a message to the user saying that the discount is too large, and by company policy we are not allowed. If the message says who wrote it, add that information in the response as well - In any other case, reply with NOTFORME If this is about a marketing campaign. and the discount is lower than 50%, reply with AUDITOK --- Input: {{$input}} diff --git a/samples/marketing/src/backend/Agents/CommunityManager/CommunityManager.cs b/samples/marketing/src/backend/Agents/CommunityManager/CommunityManager.cs index b60b0e7c..c2c15627 100644 --- a/samples/marketing/src/backend/Agents/CommunityManager/CommunityManager.cs +++ b/samples/marketing/src/backend/Agents/CommunityManager/CommunityManager.cs @@ -3,9 +3,11 @@ using Marketing.Options; using Microsoft.AI.Agents.Abstractions; using Microsoft.AI.Agents.Orleans; +using Microsoft.Identity.Client; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Memory; using Orleans.Runtime; +using Polly.CircuitBreaker; namespace Marketing.Agents; @@ -38,9 +40,23 @@ public async override Task HandleEvent(Event item) // break; case nameof(EventTypes.UserChatInput): - - break; + if(_state.State?.Data?.WrittenSocialMediaPost != null) + { + KernelArguments ka = new KernelArguments(); + string prompt = CommunityManagerPrompts.UpdatePost + .Replace("{{$userrequest}}", item.Data["userMessage"]) + .Replace("{{$inprogresstweet}}", _state.State.Data.WrittenSocialMediaPost); + + string socialMediaPost = await CallFunction(prompt, ka); + if (socialMediaPost.Contains("NOTFORME")) + { + return; + } + _state.State.Data.WrittenSocialMediaPost = socialMediaPost; + await SendDesignedCreatedEvent(socialMediaPost, item.Data["SessionId"]); + } + break; case nameof(EventTypes.AuditorOk): { string article; @@ -63,7 +79,7 @@ public async override Task HandleEvent(Event item) { article += "| USER REQUEST: " + item.Data["userMessage"]; } - _logger.LogInformation($"[{nameof(GraphicDesigner)}] Event {nameof(EventTypes.CampaignCreated)}. Article: {article}"); + _logger.LogInformation($"[{nameof(CommunityManager)}] Event {nameof(EventTypes.CampaignCreated)}. Article: {article}"); var context = new KernelArguments { ["input"] = AppendChatHistory(article) }; string socialMediaPost = await CallFunction(CommunityManagerPrompts.WritePost, context); diff --git a/samples/marketing/src/backend/Agents/CommunityManager/CommunityManagerPrompts.cs b/samples/marketing/src/backend/Agents/CommunityManager/CommunityManagerPrompts.cs index ada868d6..d574ae8b 100644 --- a/samples/marketing/src/backend/Agents/CommunityManager/CommunityManagerPrompts.cs +++ b/samples/marketing/src/backend/Agents/CommunityManager/CommunityManagerPrompts.cs @@ -13,4 +13,17 @@ then you should write a post based on the user request Input: {{$input}} --- """; + public static string UpdatePost = """ + You are a Marketing community manager writer. This is a chat with many agents, you are just one of them + If the request from the user is addressing you specifically (for example, @communitymanager) + then you should write a post based on the user request + Your writings are going to be posted on Tweeter. So be informal, friendly and add some hashtags and emojis. + Remember, the tweet cannot be longer than 280 characters. + If the request was not intedend for you. Or you are not sure who is intended for, reply with " + --- + UserRequest: {{$userrequest}} + --- + InProgressTweet: {{$inprogresstweet}} + --- + """; } \ No newline at end of file diff --git a/samples/marketing/src/backend/Agents/GraphicDesigner/GraphicDesigner.cs b/samples/marketing/src/backend/Agents/GraphicDesigner/GraphicDesigner.cs index 79366be8..e097ff2d 100644 --- a/samples/marketing/src/backend/Agents/GraphicDesigner/GraphicDesigner.cs +++ b/samples/marketing/src/backend/Agents/GraphicDesigner/GraphicDesigner.cs @@ -49,15 +49,21 @@ public async override Task HandleEvent(Event item) return; } - _logger.LogInformation($"[{nameof(GraphicDesigner)}] Event {nameof(EventTypes.AuditorOk)}."); - var article = item.Data["article"]; - var dallEService = _kernel.GetRequiredService(); - var imageUri = await dallEService.GenerateImageAsync(article, 1024, 1024); - - _state.State.Data.imageUrl = imageUri; + try + { + _logger.LogInformation($"[{nameof(GraphicDesigner)}] Event {nameof(EventTypes.AuditorOk)}."); + var article = item.Data["article"]; + var dallEService = _kernel.GetRequiredService(); + var imageUri = await dallEService.GenerateImageAsync(article, 1024, 1024); - await SendDesignedCreatedEvent(imageUri, item.Data["SessionId"]); + _state.State.Data.imageUrl = imageUri; + await SendDesignedCreatedEvent(imageUri, item.Data["SessionId"]); + } + catch (Exception ex) + { + _logger.LogError(ex.Message); + } break; default: diff --git a/samples/marketing/src/backend/Agents/ManufacturingManager/ManufacturingManager.cs b/samples/marketing/src/backend/Agents/ManufacturingManager/ManufacturingManager.cs new file mode 100644 index 00000000..9e79bd1b --- /dev/null +++ b/samples/marketing/src/backend/Agents/ManufacturingManager/ManufacturingManager.cs @@ -0,0 +1,56 @@ +using Marketing.Controller; +using Marketing.Events; +using Marketing.Options; +using Microsoft.AI.Agents.Abstractions; +using Microsoft.AI.Agents.Orleans; +using Microsoft.Identity.Client; +using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.Memory; +using Orleans.Runtime; +using static System.Net.Mime.MediaTypeNames; + +namespace Marketing.Agents; + +[ImplicitStreamSubscription(Consts.OrleansNamespace)] +public class ManufacturingManager : AiAgent +{ + protected override string Namespace => Consts.OrleansNamespace; + + private readonly ILogger _logger; + + public ManufacturingManager([PersistentState("state", "messages")] IPersistentState> state, Kernel kernel, ISemanticTextMemory memory, ILogger logger) + : base(state, memory, kernel) + { + _logger = logger; + } + + public async override Task HandleEvent(Event item) + { + switch (item.Type) + { + case nameof(EventTypes.SalesForecast): + string salesExpectations = item.Data["salesForecastMessage"]; + _logger.LogInformation($"[{nameof(ManufacturingManager)}] Event {nameof(EventTypes.SalesForecast)}. Text: {salesExpectations}"); + + var context = new KernelArguments { ["input"] = AppendChatHistory(salesExpectations) }; + string manufactureManagerAnswer = await CallFunction(ManufacturingManagerPrompt.ManufacturingCreateProductionForecast, context); + + SendManufactureForecastEvent(manufactureManagerAnswer, item.Data["SessionId"]); + break; + default: + break; + } + } + private async Task SendManufactureForecastEvent(string manufactureForecastMessage, string sessionId) + { + await PublishEvent(Consts.OrleansNamespace, this.GetPrimaryKeyString(), new Event + { + Type = nameof(EventTypes.ManufacturingForecast), + Data = new Dictionary { + { "SessionId", sessionId }, + { nameof(manufactureForecastMessage), manufactureForecastMessage}, + } + }); + } + +} \ No newline at end of file diff --git a/samples/marketing/src/backend/Agents/ManufacturingManager/ManufacturingManagerPrompt.cs b/samples/marketing/src/backend/Agents/ManufacturingManager/ManufacturingManagerPrompt.cs new file mode 100644 index 00000000..b23be34d --- /dev/null +++ b/samples/marketing/src/backend/Agents/ManufacturingManager/ManufacturingManagerPrompt.cs @@ -0,0 +1,16 @@ +namespace Marketing.Agents; + +public static class ManufacturingManagerPrompt +{ + public static string ManufacturingCreateProductionForecast = """ + You manage a factory. A person from marketing is trying to build a marketing campain. + The sales analyst have made a prediction on how many items are going to be sold due to a new marketing campaign + You need to answer to the user if it is possible or not to produce what the analyst have estimated. + Currently, we can increase production by 5000 only, so if the prediction is higher, please answer that it is not possible + that they should contact the manufacturing lead for an exceptional plan. + THE ANSWER IS TO THE END USER DIRECTLY + --- + SAles Forecast: {{$input}} + --- + """; +} \ No newline at end of file diff --git a/samples/marketing/src/backend/Agents/ManufacturingManager/ManufacturingManagerState.cs b/samples/marketing/src/backend/Agents/ManufacturingManager/ManufacturingManagerState.cs new file mode 100644 index 00000000..f7aa207e --- /dev/null +++ b/samples/marketing/src/backend/Agents/ManufacturingManager/ManufacturingManagerState.cs @@ -0,0 +1,8 @@ +namespace Marketing.Agents; + +[GenerateSerializer] +public class ManufacturingManagerState +{ + [Id(0)] + public string Article { get; set; } +} \ No newline at end of file diff --git a/samples/marketing/src/backend/Agents/Notary/INotary.cs b/samples/marketing/src/backend/Agents/Notary/INotary.cs new file mode 100644 index 00000000..260a8371 --- /dev/null +++ b/samples/marketing/src/backend/Agents/Notary/INotary.cs @@ -0,0 +1,9 @@ +using Microsoft.AI.Agents.Abstractions; + +namespace Marketing.Agents +{ + public interface INotary : IGrainWithStringKey + { + public Task> GetAllEvents(); + } +} diff --git a/samples/marketing/src/backend/Agents/Notary/Notary.cs b/samples/marketing/src/backend/Agents/Notary/Notary.cs new file mode 100644 index 00000000..82decb88 --- /dev/null +++ b/samples/marketing/src/backend/Agents/Notary/Notary.cs @@ -0,0 +1,43 @@ +using Marketing.Agents; +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 Notary : AiAgent, INotary +{ + protected override string Namespace => Consts.OrleansNamespace; + + private readonly ILogger _logger; + private readonly IConfiguration _configuration; + + public Notary([PersistentState("state", "messages")] IPersistentState> state, Kernel kernel, ISemanticTextMemory memory, ILogger logger, IConfiguration configuration) + : base(state, memory, kernel) + { + _logger = logger; + _configuration = configuration; + } + + public async override Task HandleEvent(Event item) + { + string lastMessage; + + if(_state.State.Data.AllEvents == null) + { + _state.State.Data.AllEvents = new List(); + } + _state.State.Data.AllEvents.Add(item); + } + + public Task> GetAllEvents() + { + return Task.FromResult(_state.State.Data.AllEvents); + } +} \ No newline at end of file diff --git a/samples/marketing/src/backend/Agents/Notary/NotaryState.cs b/samples/marketing/src/backend/Agents/Notary/NotaryState.cs new file mode 100644 index 00000000..936be907 --- /dev/null +++ b/samples/marketing/src/backend/Agents/Notary/NotaryState.cs @@ -0,0 +1,9 @@ +using Microsoft.AI.Agents.Abstractions; + +namespace Marketing.Agents +{ + public class NotaryState + { + public List AllEvents { get; set; } + } +} diff --git a/samples/marketing/src/backend/Agents/SalesAnalyst/SalesAnalyst.cs b/samples/marketing/src/backend/Agents/SalesAnalyst/SalesAnalyst.cs index 33e5e57c..67ca6676 100644 --- a/samples/marketing/src/backend/Agents/SalesAnalyst/SalesAnalyst.cs +++ b/samples/marketing/src/backend/Agents/SalesAnalyst/SalesAnalyst.cs @@ -35,18 +35,16 @@ public async Task AnalizeCampaign(string campaingText, string sessionId) } - int sales = CalculateSalesBasedOnDiscount(discountPercentage); + int salesExpectations = CalculateSalesBasedOnDiscount(discountPercentage); if (discountPercentage > 10) { - await SendSalesForecastEvent($"With a discount of {discountPercentage} we expect to sell {sales}", sessionId); + await SendSalesForecastEvent($"With a discount of {discountPercentage}% we expect a sales increase of {salesExpectations} in the next 4 months", salesExpectations, sessionId); } } - - public async override Task HandleEvent(Event item) { switch (item.Type) @@ -72,14 +70,15 @@ private async Task CallLlm (string prompt) return answer; } - private async Task SendSalesForecastEvent(string salesForecast, string sessionId) + private async Task SendSalesForecastEvent(string salesForecastMessage, int salesExpectations, string sessionId) { await PublishEvent(Consts.OrleansNamespace, this.GetPrimaryKeyString(), new Event { Type = nameof(EventTypes.SalesForecast), Data = new Dictionary { { "SessionId", sessionId }, - { nameof(salesForecast), salesForecast} + { nameof(salesForecastMessage), salesForecastMessage}, + { nameof(salesExpectations) , salesExpectations.ToString() } } }); } diff --git a/samples/marketing/src/backend/Agents/SalesAnalyst/SalesAnalystPrompt.cs b/samples/marketing/src/backend/Agents/SalesAnalyst/SalesAnalystPrompt.cs index 6770a90d..98a91ae3 100644 --- a/samples/marketing/src/backend/Agents/SalesAnalyst/SalesAnalystPrompt.cs +++ b/samples/marketing/src/backend/Agents/SalesAnalyst/SalesAnalystPrompt.cs @@ -6,8 +6,8 @@ public static class SalesAnalystPrompt You are an SalesAnalyst in a Marketing team The bellow is a marketing campaing that the team is planning to launch. If the campaing involves a discount, extract the discount percentage. + If the campaing involves giveaways, calculate the proportion of boxes for free REPLY ONLY WITH THE PERCENTAGE NUMBER - In any other case, reply with NOTFORME --- Input: {{$input}} --- diff --git a/samples/marketing/src/backend/Agents/SignalR/SignalR.cs b/samples/marketing/src/backend/Agents/SignalR/SignalR.cs index ffc8290d..915568a5 100644 --- a/samples/marketing/src/backend/Agents/SignalR/SignalR.cs +++ b/samples/marketing/src/backend/Agents/SignalR/SignalR.cs @@ -24,7 +24,7 @@ public SignalR(ILogger logger, ISignalRService signalRClient) public async override Task HandleEvent(Event item) { - int attempt = 20; + int attempt = 2; while (attempt > 0) { try @@ -50,9 +50,13 @@ public async override Task HandleEvent(Event item) await _signalRClient.SendMessageToSpecificClient(item.Data["SessionId"], auditorAlertMessage, AgentTypes.Auditor); break; case nameof(EventTypes.SalesForecast): - var salesForecast = item.Data["salesForecast"]; + var salesForecast = item.Data["salesForecastMessage"]; await _signalRClient.SendMessageToSpecificClient(item.Data["SessionId"], salesForecast, AgentTypes.SalesAnalyst); break; + case nameof(EventTypes.ManufacturingForecast): + var manufactureForecastMessage = item.Data["manufactureForecastMessage"]; + await _signalRClient.SendMessageToSpecificClient(item.Data["SessionId"], manufactureForecastMessage, AgentTypes.ManufacturingManager); + break; default: break; } diff --git a/samples/marketing/src/backend/Agents/Writer/Writer.cs b/samples/marketing/src/backend/Agents/Writer/Writer.cs index 3531bc89..317d5742 100644 --- a/samples/marketing/src/backend/Agents/Writer/Writer.cs +++ b/samples/marketing/src/backend/Agents/Writer/Writer.cs @@ -29,16 +29,16 @@ 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; - } + //// The user reconnected, let's send the last message if we have one + //string lastMessage = _state.State.History.LastOrDefault()?.Message; + //if (lastMessage == null) + //{ + // return; + //} - await SendCampaignCreatedEvent(lastMessage, item.Data["SessionId"]); + //await SendCampaignCreatedEvent(lastMessage, item.Data["SessionId"]); - break; + //break; case nameof(EventTypes.UserChatInput): var userMessage = item.Data["userMessage"]; diff --git a/samples/marketing/src/backend/Controller/EventsController.cs b/samples/marketing/src/backend/Controller/EventsController.cs new file mode 100644 index 00000000..e3de3249 --- /dev/null +++ b/samples/marketing/src/backend/Controller/EventsController.cs @@ -0,0 +1,28 @@ +using Marketing.Agents; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using System.Text.Json; + +namespace Marketing.Controller +{ + [Route("api/[controller]")] + [ApiController] + public class EventsController : ControllerBase + { + private readonly IClusterClient _client; + + public EventsController(IClusterClient client) + { + _client = client; + } + + [HttpGet("{id}")] + // GET: EventsController + public async Task Get(string id) + { + var grain = _client.GetGrain(id); + var allEvents = await grain.GetAllEvents(); + return JsonSerializer.Serialize(allEvents); + } + } +} diff --git a/samples/marketing/src/backend/Events/EventTypes.cs b/samples/marketing/src/backend/Events/EventTypes.cs index c5b9c06e..f5180deb 100644 --- a/samples/marketing/src/backend/Events/EventTypes.cs +++ b/samples/marketing/src/backend/Events/EventTypes.cs @@ -10,5 +10,5 @@ public enum EventTypes AuditorOk, AuditorAlert, SalesForecast, - ProductionForecast + ManufacturingForecast } \ No newline at end of file diff --git a/samples/marketing/src/backend/SignalRHub/AgentTypes.cs b/samples/marketing/src/backend/SignalRHub/AgentTypes.cs index e4348220..cb5ceae3 100644 --- a/samples/marketing/src/backend/SignalRHub/AgentTypes.cs +++ b/samples/marketing/src/backend/SignalRHub/AgentTypes.cs @@ -7,5 +7,6 @@ public enum AgentTypes GraphicDesigner, Auditor, Accountant, - SalesAnalyst + SalesAnalyst, + ManufacturingManager } diff --git a/samples/marketing/src/frontend/src/app/marketing/costs/cost.tsx b/samples/marketing/src/frontend/src/app/marketing/costs/cost.tsx index 4d1dec52..85a05ef8 100644 --- a/samples/marketing/src/frontend/src/app/marketing/costs/cost.tsx +++ b/samples/marketing/src/frontend/src/app/marketing/costs/cost.tsx @@ -16,9 +16,9 @@ import { green, pink } from '@mui/material/colors'; import AttachMoneyIcon from '@mui/icons-material/AttachMoney'; const data = [ - { icon: , label: 'IPA discount form 9-9 - eur 15k' }, - { icon: , label: '2x1 brewery birthday - eur 250k' }, - { icon: , label: 'Summer day 1 - CHF 180k' }, + { icon: , label: 'Vitamin discount 10% DK only - eur 15k' }, + { icon: , label: 'Combo Vitamin+Hidratate - eur 250k' }, + { icon: , label: 'Free Vitamins Summer - CHF 180k' }, { icon: , label: 'Worldcup promo 1.5M' }, ]; @@ -63,7 +63,7 @@ export default function CostList() { - + @@ -155,7 +155,7 @@ export default function RelevantDocumentList() { - + diff --git a/samples/marketing/src/frontend/src/app/marketing/manufacturing-manager/manufacturing.tsx b/samples/marketing/src/frontend/src/app/marketing/manufacturing-manager/manufacturing.tsx new file mode 100644 index 00000000..f1670c11 --- /dev/null +++ b/samples/marketing/src/frontend/src/app/marketing/manufacturing-manager/manufacturing.tsx @@ -0,0 +1,187 @@ +"use client"; + +import React, { useRef, useState } from 'react'; + +import '@fontsource/roboto/300.css'; +import '@fontsource/roboto/400.css'; +import '@fontsource/roboto/500.css'; +import '@fontsource/roboto/700.css'; + +import { styled } from '@mui/material/styles'; +import { Avatar, Box, Container } from '@mui/material'; +import Badge, { BadgeProps } from '@mui/material/Badge'; +import { Typography } from '@mui/material'; +import List from '@mui/material/List'; +import ListItemAvatar from '@mui/material/ListItemAvatar'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemText from '@mui/material/ListItemText'; +import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown'; +import PersonIcon from '@mui/icons-material/Person'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import { Title } from '@refinedev/mui'; + +const GreenStyledBadge = styled(Badge)(({ theme }) => ({ + '& .MuiBadge-badge': { + backgroundColor: '#44b700', + color: '#44b700', + boxShadow: `0 0 0 2px ${theme.palette.background.paper}`, + '&::after': { + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%', + borderRadius: '50%', + animation: 'ripple 1.2s infinite ease-in-out', + border: '1px solid currentColor', + content: '""', + }, + }, + '@keyframes ripple': { + '0%': { + transform: 'scale(.8)', + opacity: 1, + }, + '100%': { + transform: 'scale(2.4)', + opacity: 0, + }, + }, +})); + +const RedStyledBadge = styled(Badge)(({ theme }) => ({ + '& .MuiBadge-badge': { + backgroundColor: 'red', + color: '#44b700', + boxShadow: `0 0 0 2px ${theme.palette.background.paper}`, + '&::after': { + position: 'absolute', + top: 0, + left: 0, + width: '100%', + height: '100%', + borderRadius: '50%', + animation: 'ripple 1.2s infinite ease-in-out', + border: '1px solid currentColor', + content: '""', + }, + }, + '@keyframes ripple': { + '0%': { + transform: 'scale(.8)', + opacity: 1, + }, + '100%': { + transform: 'scale(2.4)', + opacity: 0, + }, + }, +})); + +export default function ManufacturingManager() { + const [open, setOpen] = React.useState(false); + + console.log(`[Marketing] Rendering ManufactureManager.`); + return ( + + + setOpen(!open)} + sx={{ + px: 3, + pt: 2.5, + pb: open ? 0 : 2.5, + '&:hover, &:focus': { '& #arrowdownicon': { opacity: open ? 1 : 0 } }, + }} + > + + + + + + + {open && ( + + + + + + + + + + Manufacturing Director + + + } + /> + + + + + + + + + + Production Manager + + + } + /> + + + )} + + + ); +} \ No newline at end of file diff --git a/samples/marketing/src/frontend/src/app/marketing/page.tsx b/samples/marketing/src/frontend/src/app/marketing/page.tsx index 4206fd23..87586724 100644 --- a/samples/marketing/src/frontend/src/app/marketing/page.tsx +++ b/samples/marketing/src/frontend/src/app/marketing/page.tsx @@ -16,6 +16,7 @@ import CostList from './costs/cost'; import RelevantDocumentList from './docs/docs'; import Chat from './chat/chat'; import CommunityManager from './community-manager/community-manager'; +import ManufacturingManager from './manufacturing-manager/manufacturing'; import { Container, Grid, TextField } from '@mui/material'; import { HubConnectionBuilder, HubConnection, LogLevel } from '@microsoft/signalr'; @@ -66,7 +67,7 @@ export default function Marketing() { // initi the connection const connection = new HubConnectionBuilder() .withUrl(uri, {withCredentials: false}) - .withAutomaticReconnect(Array(3).fill(2000)) + .withAutomaticReconnect(Array(3).fill(1000)) .configureLogging(LogLevel.Information) .build(); @@ -77,23 +78,30 @@ export default function Marketing() { const newMessage = { sender: 'Writer', text: message.message }; setMessages(prevMessages => [...prevMessages, newMessage]); } - if (message.agent === 'Auditor') { + else if (message.agent === 'Auditor') { const newMessage = { sender: 'Auditor', text: message.message }; setMessages(prevMessages => [...prevMessages, newMessage]); } - if (message.agent === 'CommunityManager') { + else if (message.agent === 'CommunityManager') { setArticle(message.message); - const newMessage = { sender: message.agent, text: 'Community Manager: ' + message.message }; + const newMessage = { sender: 'Community Manager', text: message.message }; setMessages(prevMessages => [...prevMessages, newMessage]); } - if (message.agent === 'GraphicDesigner') { + else if (message.agent === 'GraphicDesigner') { setImgUrl(message.message); - const newMessage = { sender: message.agent, text: 'Graphic Designer: Check the image I created!'}; + const newMessage = { sender: 'Graphic Designer', text: 'Check the image I created!'}; setMessages(prevMessages => [...prevMessages, newMessage]); } - if (message.agent === 'SalesAnalyst') { - setImgUrl(message.message); - const newMessage = { sender: message.agent, text: 'Sales Analyst: ' + message.message }; + else if (message.agent === 'SalesAnalyst') { + const newMessage = { sender: 'Sales Analyst', text: message.message }; + setMessages(prevMessages => [...prevMessages, newMessage]); + } + else if(message.agent=='ManufacturingManager') { + const newMessage = { sender: 'Manufacturing Manager', text: message.message }; + setMessages(prevMessages => [...prevMessages, newMessage]); + } + else { + const newMessage = { sender: 'UNKNOWN', text: message.message }; setMessages(prevMessages => [...prevMessages, newMessage]); } }); @@ -195,6 +203,12 @@ export default function Marketing() { + + + + + + diff --git a/samples/marketing/src/frontend/src/app/marketing/stakeholders/stakeholders.tsx b/samples/marketing/src/frontend/src/app/marketing/stakeholders/stakeholders.tsx index db2e75b8..8283b26e 100644 --- a/samples/marketing/src/frontend/src/app/marketing/stakeholders/stakeholders.tsx +++ b/samples/marketing/src/frontend/src/app/marketing/stakeholders/stakeholders.tsx @@ -153,65 +153,6 @@ export default function StakeholderList() { )} - {open && ( -

Questions? These are relevant stakeholders for you:

- )} - {open && ( - - - - - - - - - - General Attorney - - - } - /> - - - - - - - - - - Marketing Manager - - - } - /> - - - )} );