Skip to content

Commit 70e008a

Browse files
csharpfritzlannonbr
andcommitted
Added SentimentWidget
Co-Authored-By: Benjamin Lannon <[email protected]>
1 parent 5950b88 commit 70e008a

File tree

14 files changed

+192
-5
lines changed

14 files changed

+192
-5
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Fritz.Chatbot.Commands
6+
{
7+
8+
public class SentimentSink
9+
{
10+
11+
public static Queue<string> RecentChatMessages { get; } = new Queue<string>();
12+
13+
}
14+
15+
}

Fritz.Chatbot/FritzBot.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ public FritzBot(IConfiguration config, IServiceProvider serviceProvider, ILogger
3636
_chatServices = serviceProvider.GetServices<IChatService>().ToArray();
3737
_serviceProvider = serviceProvider;
3838

39-
4039
_basicCommands = _serviceProvider.GetServices<IBasicCommand>().ToArray();
4140
_extendedCommands = _serviceProvider.GetServices<IExtendedCommand>().OrderBy(k => k.Order).ToArray();
4241
}
@@ -108,6 +107,7 @@ private async void OnChat_ChatMessage(object sender, ChatMessageEventArgs e)
108107
// async void as Event callback
109108
try
110109
{
110+
111111
await ProcessChatMessage(sender, e);
112112
}
113113
catch (Exception ex)
@@ -126,6 +126,7 @@ private async Task ProcessChatMessage(object sender, ChatMessageEventArgs e)
126126
var user = _activeUsers.AddOrUpdate(userKey, new ChatUserInfo(), (_, u) => u);
127127

128128
var chatService = sender as IChatService;
129+
if (chatService.BotUserName.Equals(e.UserName, StringComparison.InvariantCultureIgnoreCase)) return; // Don't process my own messages
129130

130131
var final = await HandleExtendedCommands();
131132
if (final)
@@ -137,6 +138,8 @@ private async Task ProcessChatMessage(object sender, ChatMessageEventArgs e)
137138
{
138139
await chatService.SendWhisperAsync(e.UserName, "Unknown command. Try !help for a list of available commands");
139140
}
141+
} else {
142+
SentimentSink.RecentChatMessages.Enqueue(e.Message);
140143
}
141144

142145
return; // Only local functions below

Fritz.StreamLib.Core/IChatService.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ public interface IChatService
99
string Name { get; }
1010
bool IsAuthenticated { get; }
1111

12+
string BotUserName { get; }
13+
1214
event EventHandler<ChatMessageEventArgs> ChatMessage;
1315
event EventHandler<ChatUserInfoEventArgs> UserJoined;
1416
event EventHandler<ChatUserInfoEventArgs> UserLeft;

Fritz.StreamTools.sln

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
3-
# Visual Studio 15
4-
VisualStudioVersion = 15.0.27130.2020
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.28527.54
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{520B1405-AC30-493A-8F04-6AA9B8FE2CDD}"
77
EndProject
@@ -29,7 +29,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fritz.Chatbot", "Fritz.Chat
2929
EndProject
3030
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fritz.Twitch", "Fritz.Twitch\Fritz.Twitch.csproj", "{28D6D34A-3F6E-40B3-B62A-20F90D281C7D}"
3131
EndProject
32-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleChatbot", "ConsoleChatbot\ConsoleChatbot.csproj", "{A9F1860F-163B-44AC-A935-C1B584D3CB8A}"
32+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleChatbot", "ConsoleChatbot\ConsoleChatbot.csproj", "{A9F1860F-163B-44AC-A935-C1B584D3CB8A}"
3333
EndProject
3434
Global
3535
GlobalSection(SolutionConfigurationPlatforms) = preSolution

Fritz.StreamTools/Fritz.StreamTools.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.5.1" />
2525
<PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.6" />
2626
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="1.0.4" />
27+
<PackageReference Include="Microsoft.Azure.CognitiveServices.Language.TextAnalytics" Version="2.8.0-preview" />
2728
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.6" />
2829
<PackageReference Include="Octokit" Version="0.32.0" />
2930
<PackageReference Include="System.IO.Abstractions" Version="2.1.0.256" />
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
@page
2+
@model Fritz.StreamTools.Pages.SentimentModel
3+
@{
4+
}
5+
<!DOCTYPE html>
6+
7+
<html>
8+
<head>
9+
<meta name="viewport" content="width=device-width" />
10+
<title>Sentiment</title>
11+
</head>
12+
<body>
13+
<div id="currentSentiment"></div>
14+
15+
<script src="~/lib/signalr/signalr-client.js"></script>
16+
<script src="~/js/streamhub.js"></script>
17+
<script>
18+
(function () {
19+
20+
var hub = new StreamHub();
21+
var sentimentEl = document.getElementById("currentSentiment");
22+
23+
hub.onSentiment = (newValue) => {
24+
25+
console.log(newValue);
26+
27+
sentimentEl.textContent = `Current Sentiment: ${(newValue * 100).toFixed(1)}`;
28+
29+
}
30+
31+
hub.start("sentiment");
32+
33+
})();
34+
</script>
35+
</body >
36+
</html >
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Fritz.Chatbot.Commands;
6+
using Microsoft.AspNetCore.Mvc;
7+
using Microsoft.AspNetCore.Mvc.RazorPages;
8+
9+
namespace Fritz.StreamTools.Pages
10+
{
11+
public class SentimentModel : PageModel
12+
{
13+
14+
public void OnGet()
15+
{
16+
}
17+
}
18+
}

Fritz.StreamTools/Services/FollowerClient.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ internal void UpdateGitHub(IEnumerable<GitHubInformation> contributors)
3737
FollowerContext.Clients.Group("github").SendAsync("OnGitHubUpdated", contributors);
3838
}
3939

40+
internal void UpdateSentiment(double newSentiment) {
41+
42+
FollowerContext.Clients.Group("sentiment").SendAsync("OnSentimentUpdated", newSentiment);
43+
44+
}
45+
4046
}
4147

4248
}

Fritz.StreamTools/Services/MixerService.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ public class MixerService : IHostedService, IStreamService, IChatService, IDispo
3636
#region Properties
3737

3838
public string Name { get => SERVICE_NAME; }
39+
40+
public string BotUserName { get { return _Mixer.UserName; } }
41+
3942
public int CurrentFollowerCount { get; set; }
4043
public int CurrentViewerCount { get; set; }
4144
public bool IsAuthenticated => _Mixer.IsAuthenticated;
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using Fritz.Chatbot.Commands;
2+
using Microsoft.Azure.CognitiveServices.Language.TextAnalytics;
3+
using Microsoft.Azure.CognitiveServices.Language.TextAnalytics.Models;
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.Extensions.Hosting;
6+
using Microsoft.Rest;
7+
using System;
8+
using System.Collections.Generic;
9+
using System.Linq;
10+
using System.Net.Http;
11+
using System.Threading;
12+
using System.Threading.Tasks;
13+
14+
namespace Fritz.StreamTools.Services
15+
{
16+
public class SentimentService : IHostedService
17+
{
18+
19+
private readonly FollowerClient _followerClient;
20+
private bool _StopProcess = false;
21+
private TextAnalyticsClient _client;
22+
private static string _SubscriptionKey;
23+
24+
private class ApiKeyServiceClientCredentials : ServiceClientCredentials
25+
{
26+
public override Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
27+
{
28+
request.Headers.Add("Ocp-Apim-Subscription-Key", _SubscriptionKey);
29+
return base.ProcessHttpRequestAsync(request, cancellationToken);
30+
}
31+
}
32+
33+
public SentimentService(FollowerClient followerClient, IConfiguration config)
34+
{
35+
36+
_SubscriptionKey = config["FritzBot:SentimentAnalysisKey"].ToString();
37+
_followerClient = followerClient;
38+
_client = new TextAnalyticsClient(new ApiKeyServiceClientCredentials())
39+
{
40+
Endpoint = "https://centralus.api.cognitive.microsoft.com"
41+
};
42+
}
43+
44+
45+
public Task StartAsync(CancellationToken cancellationToken)
46+
{
47+
Task.Run(async () => await Run());
48+
return Task.CompletedTask;
49+
}
50+
51+
public Task StopAsync(CancellationToken cancellationToken)
52+
{
53+
54+
_StopProcess = true;
55+
return Task.CompletedTask;
56+
57+
}
58+
59+
public async Task Run()
60+
{
61+
62+
while (!_StopProcess)
63+
{
64+
65+
if (SentimentSink.RecentChatMessages.Any())
66+
{
67+
68+
var messageList = SentimentSink.RecentChatMessages.Select((value, index) => new MultiLanguageInput { Text = value, Id = index.ToString(), Language = "en" }).ToList();
69+
SentimentSink.RecentChatMessages.Clear();
70+
71+
SentimentBatchResult results = await _client.SentimentAsync(
72+
new MultiLanguageBatchInput(messageList)
73+
);
74+
75+
var avgScore = results.Documents
76+
.Where(d => d.Score.HasValue)
77+
.Average(d => d.Score).Value;
78+
_followerClient.UpdateSentiment(avgScore);
79+
80+
}
81+
82+
await Task.Delay(100);
83+
84+
}
85+
86+
}
87+
88+
}
89+
}

0 commit comments

Comments
 (0)