Skip to content

Commit e598f7b

Browse files
committed
Completed inserting new shutter effect scene in ObsProxy
1 parent fe013a0 commit e598f7b

File tree

5 files changed

+63
-126
lines changed

5 files changed

+63
-126
lines changed

Fritz.Chatbot/Commands/PredictHatCommand.cs

Lines changed: 2 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
using Fritz.StreamLib.Core;
2+
using Fritz.StreamTools.Hubs;
3+
using Microsoft.AspNetCore.SignalR;
24
using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction;
3-
using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Prediction.Models;
45
using Microsoft.Extensions.Configuration;
56
using System;
6-
using System.Linq;
7-
using System.Collections.Generic;
8-
using System.Collections.Immutable;
9-
using System.Text;
107
using System.Threading.Tasks;
11-
using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training;
12-
using System.Net;
13-
using Microsoft.AspNetCore.SignalR;
14-
using Fritz.StreamTools.Hubs;
158

169
namespace Fritz.Chatbot.Commands
1710
{
@@ -45,10 +38,6 @@ public PredictHatCommand(IConfiguration configuration, ScreenshotTrainingService
4538
public async Task Execute(IChatService chatService, string userName, ReadOnlyMemory<char> rhs)
4639
{
4740

48-
if (string.IsNullOrEmpty(IterationName)) {
49-
await IdentifyIterationName();
50-
}
51-
5241
var client = new CustomVisionPredictionClient()
5342
{
5443
ApiKey = _CustomVisionKey,
@@ -60,72 +49,9 @@ public async Task Execute(IChatService chatService, string userName, ReadOnlyMem
6049

6150
////////////////////////////
6251

63-
ImagePrediction result;
64-
try
65-
{
66-
result = await client.DetectImageWithNoStoreAsync(_AzureProjectId, IterationName, obsImage);
67-
} catch (CustomVisionErrorException ex) {
68-
69-
70-
71-
if (ex.Response.StatusCode == HttpStatusCode.NotFound) {
72-
await IdentifyIterationName();
73-
}
74-
75-
await chatService.SendMessageAsync("Unable to detect Fritz's hat right now... please try again in 1 minute");
76-
return;
77-
78-
}
79-
80-
if (DateTime.UtcNow.Subtract(result.Created).TotalSeconds > Cooldown.Value.TotalSeconds) {
81-
await chatService.SendMessageAsync($"I previously predicted this hat about {DateTime.UtcNow.Subtract(result.Created).TotalSeconds} seconds ago");
82-
}
83-
84-
var bestMatch = result.Predictions.OrderByDescending(p => p.Probability).FirstOrDefault();
85-
if (bestMatch.Probability < 0.7D && bestMatch.Probability > 0.5d) {
86-
87-
if (result.Predictions.Count(b => b.Probability > 0.4d) > 1) {
88-
89-
var guess1Data = new HatData("", ""); // (await _Repository.GetHatData(bestMatch.TagName));
90-
var guess2Data = new HatData("", ""); // (await _Repository.GetHatData(result.Predictions.OrderByDescending(p => p.Probability).Skip(1).First().TagName));
91-
await chatService.SendMessageAsync($"csharpGuess I'm not quite sure if this is {guess1Data.Name} ({bestMatch.Probability.ToString("0.0%")}) or {guess2Data.Name} ({result.Predictions.OrderByDescending(p => p.Probability).Skip(1).First().Probability.ToString("0.0%")})");
92-
return;
93-
94-
} else {
95-
var guessData = new HatData("", ""); // (await _Repository.GetHatData(bestMatch.TagName));
96-
await chatService.SendMessageAsync($"csharpGuess I'm not quite sure if this is {guessData.Name} ({bestMatch.Probability.ToString("0.0%")})");
97-
return;
98-
}
99-
100-
} else if ((bestMatch?.Probability ?? 0) <= 0.4d) {
101-
await chatService.SendMessageAsync("csharpAngry 404 Hat Not Found! Let's ask a moderator to !addhat so we can identify it next time");
102-
// do we store the image?
103-
return;
104-
}
105-
106-
var hatData = new HatData("", ""); // (await _Repository.GetHatData(bestMatch.TagName));
107-
var nameToReport = (hatData == null ? bestMatch.TagName : (string.IsNullOrEmpty(hatData.Name) ? bestMatch.TagName : hatData.Name));
108-
await chatService.SendMessageAsync($"csharpClip I think (with {bestMatch.Probability.ToString("0.0%")} certainty) Jeff is currently wearing his {nameToReport} hat csharpClip");
109-
if (hatData != null && !string.IsNullOrEmpty(hatData.Description)) await chatService.SendMessageAsync(hatData.Description);
110-
111-
await _HubContext.Clients.All.SendAsync("hatDetected", bestMatch.Probability.ToString("0.0%"), bestMatch.TagName, nameToReport, hatData?.Description);
11252

11353
}
11454

115-
private async Task IdentifyIterationName()
116-
{
117-
118-
var client = new CustomVisionTrainingClient() {
119-
ApiKey = _CustomVisionKey,
120-
Endpoint = _AzureEndpoint
121-
};
122-
123-
var iterations = await client.GetIterationsAsync(_AzureProjectId);
124-
IterationName = iterations
125-
.Where(i => !string.IsNullOrEmpty(i.PublishName) && i.Status == "Completed")
126-
.OrderByDescending(i => i.LastModified).First().PublishName;
127-
128-
}
12955
}
13056

13157
internal record HatData(string Name, string Description);

Fritz.ObsProxy/BotClient.cs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
11
using Fritz.StreamLib.Core;
22
using Microsoft.AspNetCore.SignalR.Client;
3-
using Microsoft.Extensions.Configuration;
4-
using Microsoft.Extensions.DependencyInjection;
5-
using Microsoft.Extensions.Logging;
6-
using System;
7-
using System.Collections.Generic;
83
using System.Diagnostics;
9-
using System.IO;
10-
using System.Text;
11-
using System.Threading.Channels;
12-
using System.Threading.Tasks;
134

145
namespace Fritz.ObsProxy
156
{
@@ -49,16 +40,19 @@ async Task StartAsync(int retryCount = 0)
4940
try
5041
{
5142
await _Client.StartAsync();
52-
} catch (Exception ex) {
43+
}
44+
catch (Exception ex)
45+
{
5346
// do nothing, we're gonna try again...
5447
}
5548

5649
if (_Client.State == HubConnectionState.Connected)
5750
{
5851
_Logger.LogWarning("Connected to ObsHub");
5952

60-
}
61-
else if (retryCount < 20) {
53+
}
54+
else if (retryCount < 20)
55+
{
6256
_Logger.LogWarning($"Retrying connection {retryCount}");
6357
retryCount++;
6458
await Task.Delay(100);
@@ -96,14 +90,14 @@ async IAsyncEnumerable<string> clientStreamData(string imageData)
9690
{
9791

9892
var sr = new StringReader(imageData);
99-
Debug.WriteLine($"ImageData ({imageData.Length}): " + imageData.Substring(imageData.Length-20,20));
93+
Debug.WriteLine($"ImageData ({imageData.Length}): " + imageData.Substring(imageData.Length - 20, 20));
10094

10195
var buffer = new char[2000];
10296
while (true)
10397
{
10498
var lengthRead = sr.ReadBlock(buffer, 0, 2000);
10599
if (lengthRead == 0) { break; }
106-
yield return new string(buffer,0, lengthRead);
100+
yield return new string(buffer, 0, lengthRead);
107101
buffer = new char[2000];
108102
}
109103
//After the for loop has completed and the local function exits the stream completion will be sent.

Fritz.ObsProxy/Fritz.ObsProxy.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
<PropertyGroup>
44
<TargetFramework>net9.0</TargetFramework>
5+
<ImplicitUsings>true</ImplicitUsings>
56
<UserSecretsId>dotnet-Fritz.ObsProxy-63F1EE89-A75A-469F-919F-8238E927CEB8</UserSecretsId>
67
</PropertyGroup>
78

89
<ItemGroup>
9-
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.0-*" />
10-
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0-*" />
10+
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.0" />
11+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
1112
<PackageReference Include="obs-websocket-dotnet" Version="5.0.0.3" />
1213
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
1314
</ItemGroup>

Fritz.ObsProxy/ObsClient.cs

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,12 @@
1-
using Microsoft.Extensions.Configuration;
2-
using Microsoft.Extensions.Logging;
3-
using Microsoft.VisualBasic.CompilerServices;
4-
using OBSWebsocketDotNet;
5-
using OBSWebsocketDotNet.Types;
1+
using OBSWebsocketDotNet;
62
using SixLabors.ImageSharp;
73
using SixLabors.ImageSharp.Processing;
8-
using System;
9-
using System.Collections.Generic;
10-
using System.Diagnostics;
11-
using System.IO;
12-
using System.Linq;
13-
using System.Runtime.InteropServices;
14-
using System.Text;
15-
using System.Threading;
16-
using System.Threading.Tasks;
174

185
namespace Fritz.ObsProxy;
196

207

21-
public class ObsClient : IDisposable {
8+
public class ObsClient : IDisposable
9+
{
2210
private bool _DisposedValue;
2311
private static OBSWebsocket _OBS;
2412

@@ -29,16 +17,19 @@ public class ObsClient : IDisposable {
2917

3018
public bool IsReady { get; set; } = false;
3119

32-
public ObsClient(ILoggerFactory loggerFactory, IConfiguration configuration) {
20+
public ObsClient(ILoggerFactory loggerFactory, IConfiguration configuration)
21+
{
3322
_Logger = loggerFactory.CreateLogger("ObsClient");
3423
_Configuration = configuration;
3524
_IpAddress = string.IsNullOrEmpty(configuration["ObsIpAddress"]) ? "127.0.0.1:4455" : configuration["ObsIpAddress"];
3625
_Password = configuration["ObsPassword"];
3726

38-
if (_OBS == null) {
27+
if (_OBS == null)
28+
{
3929
_OBS = new OBSWebsocket();
4030
_OBS.Connected += _OBS_Connected;
41-
_OBS.Disconnected += (s, e) => {
31+
_OBS.Disconnected += (s, e) =>
32+
{
4233
OnDisconnect();
4334
};
4435
}
@@ -50,15 +41,17 @@ public ObsClient(ILoggerFactory loggerFactory, IConfiguration configuration) {
5041
/// </summary>
5142
/// <param name="port"></param>
5243
/// <returns></returns>
53-
public void Connect() {
44+
public void Connect()
45+
{
5446

5547
Task.Run(() => _OBS.ConnectAsync($"ws://{_IpAddress}", _Password));
5648

5749
}
5850

5951
public static Action OnDisconnect { get; set; } = () => { };
6052

61-
private void _OBS_Connected(object sender, EventArgs e) {
53+
private void _OBS_Connected(object sender, EventArgs e)
54+
{
6255

6356
IsReady = true;
6457
var versionInfo = _OBS.GetVersion();
@@ -70,16 +63,29 @@ private void _OBS_Connected(object sender, EventArgs e) {
7063
public string CameraSource => _Configuration["CameraSource"];
7164

7265

73-
public string TakeScreenshot() {
66+
public string TakeScreenshot()
67+
{
7468

7569
Console.WriteLine($"IsConnected: {_OBS.IsConnected}");
7670

77-
try {
71+
try
72+
{
73+
74+
// show the pre-screenshot countdown animation
75+
var sceneName = _Configuration["OverlayScene"];
76+
var sourceName = _Configuration["OverlayCountdownSource"];
77+
var shutterSourceId = _OBS.GetSceneItemId(sceneName, sourceName, 0);
78+
_OBS.SetSceneItemEnabled(sceneName, shutterSourceId, false);
79+
_OBS.SetSceneItemEnabled(sceneName, shutterSourceId, true);
80+
Task.Delay(3500).Wait();
81+
_OBS.SetSceneItemEnabled(sceneName, shutterSourceId, false);
82+
7883
var imageFileName = System.IO.Path.GetTempFileName();
7984
_OBS.SaveSourceScreenshot(CameraSource, "png", imageFileName);
8085

8186
var outString = string.Empty;
82-
using (var tempFile = File.OpenRead(imageFileName)) {
87+
using (var tempFile = File.OpenRead(imageFileName))
88+
{
8389

8490
outString = ProcessImage(CameraSource, tempFile);
8591

@@ -89,18 +95,21 @@ public string TakeScreenshot() {
8995
return outString;
9096

9197
}
92-
catch (Exception e) {
98+
catch (Exception e)
99+
{
93100
_Logger.LogError(e, "Error while taking screenshot");
94101
return null;
95102
}
96103

97104
}
98105

99-
private string ProcessImage(string cameraSource, Stream image) {
106+
private string ProcessImage(string cameraSource, Stream image)
107+
{
100108

101109
var outString = string.Empty;
102110

103-
using (var img = Image.Load(image)) {
111+
using (var img = Image.Load(image))
112+
{
104113

105114
// TODO: Crop appropriately for the camerasource
106115
var memStream = new MemoryStream();
@@ -119,9 +128,12 @@ private string ProcessImage(string cameraSource, Stream image) {
119128

120129
#region Dispose OBS Connection
121130

122-
protected virtual void Dispose(bool disposing) {
123-
if (!_DisposedValue) {
124-
if (disposing) {
131+
protected virtual void Dispose(bool disposing)
132+
{
133+
if (!_DisposedValue)
134+
{
135+
if (disposing)
136+
{
125137
// TODO: dispose managed state (managed objects)
126138
}
127139

@@ -131,12 +143,14 @@ protected virtual void Dispose(bool disposing) {
131143
}
132144
}
133145

134-
~ObsClient() {
146+
~ObsClient()
147+
{
135148
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
136149
Dispose(disposing: false);
137150
}
138151

139-
public void Dispose() {
152+
public void Dispose()
153+
{
140154
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
141155
Dispose(disposing: true);
142156
GC.SuppressFinalize(this);

Fritz.ObsProxy/appsettings.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
"ImageFolder": "C:\\dev\\stream\\Screenshots",
1010
"ImageFolderOrg": "C:\\dev\\stream\\Screenshots",
1111
"BotUrl": "http://localhost:8000/obshub",
12-
"ObsIpAddress": "127.0.0.1:4455",
13-
"ObsPassword": "Bthu4hq3Ki0NBflq",
12+
"ObsIpAddress": "192.168.1.80:4455",
13+
"ObsPassword": "7UpJXXXwLMfXblPS",
1414
"CameraSource": "Local Sony",
15-
"ObsTest": "false"
15+
"ObsTest": "false",
16+
"OverlayScene": "S - Overlays",
17+
"OverlayCountdownSource": "Countdown-Shutter"
1618
}

0 commit comments

Comments
 (0)