Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updated image based on jochenjonc's work. #197

Merged
merged 15 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Build the Docker image
run: docker build -t djdd87/synoai:latest SynoAI
run: docker build -t dewitauto/synoai-fork:latest SynoAI
- name: Login to Docker Hub
run: docker login -u="${{ secrets.DOCKERHUB_USERNAME }}" -p="${{ secrets.DOCKERHUB_PASSWORD }}"
- name: Publish the Docker image
run: docker push djdd87/synoai:latest
run: docker push dewitauto/synoai-fork:latest
123 changes: 60 additions & 63 deletions SynoAI.Tests/packages.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@
"resolved": "2.4.5",
"contentHash": "OwHamvBdUKgqsXfBzWiCW/O98BTx81UKzx2bieIOQI7CZFE5NEQZGi8PBQGIKawDW96xeRffiNf20SjfC0x9hw=="
},
"BouncyCastle.Cryptography": {
"type": "Transitive",
"resolved": "2.2.1",
"contentHash": "A6Zr52zVqJKt18ZBsTnX0qhG0kwIQftVAjLmszmkiR/trSp8H+xj1gUOzk7XHwaKgyREMSV1v9XaKrBUeIOdvQ=="
},
"MailKit": {
"type": "Transitive",
"resolved": "3.4.3",
"contentHash": "Iewef8mcE1B1LrVudxQjQ0LcriPPeTbxmWMoHQzFS+P6TpEY2eVDbdKdB0Qnbmqr/5w7WfK2mNWuoSX9pI470g==",
"resolved": "4.2.0",
"contentHash": "NXm66YkEHyLXSyH1Ga/dUS8SB0vYTlGESUluLULa7pG0/eK8c/R9JzMyH0KbKQsgpLGwbji9quAlrcUOL0OjPA==",
"dependencies": {
"MimeKit": "3.4.3"
"MimeKit": "4.2.0"
}
},
"Microsoft.CodeCoverage": {
Expand Down Expand Up @@ -88,8 +93,8 @@
},
"Microsoft.VisualStudio.Azure.Containers.Tools.Targets": {
"type": "Transitive",
"resolved": "1.17.0",
"contentHash": "gfDtAL1WhkjbRdbZlt/ZeQYCbgRpNCZCGj+yeqHObsNFRDHjq8qZJOX9AyTxJpSRYMi9SJk7JDyAbbVYRgEhAA=="
"resolved": "1.19.5",
"contentHash": "Kaa1rBZdJFq5A0qgAcl6Bmk/UqLXTq9acEqxUlPEBA8oscmakLfkvuSXfG7Wa9t1/keaT85EuuDNgOo+Z9VYOQ=="
},
"Microsoft.Win32.Primitives": {
"type": "Transitive",
Expand All @@ -108,19 +113,19 @@
},
"MimeKit": {
"type": "Transitive",
"resolved": "3.4.3",
"contentHash": "7TSAcziEwk0bGWODpFTQASghXfYNBBa5VdM8KO4s5SBp5LYgIVXcQsdLBpPQ2XhZW74wfaX8RBUMs1GTMlLJcA==",
"resolved": "4.2.0",
"contentHash": "HlfWiJ6t40r8u/rCK2p/8dm1ILiWw4XHucm2HImDYIFS3uZe7IKZyaCDafEoZR7VG7AW1JQxNPQCAxmAnJfRvA==",
"dependencies": {
"Portable.BouncyCastle": "1.9.0",
"BouncyCastle.Cryptography": "2.2.1",
"System.Runtime.CompilerServices.Unsafe": "6.0.0",
"System.Security.Cryptography.Pkcs": "6.0.0",
"System.Text.Encoding.CodePages": "6.0.0"
"System.Security.Cryptography.Pkcs": "7.0.2",
"System.Text.Encoding.CodePages": "7.0.0"
}
},
"MQTTnet": {
"type": "Transitive",
"resolved": "4.1.4.563",
"contentHash": "gO9segUcKyQJcjV7w7OOdoAIkec7cUN65vEhYutbdWcj4rbtz/oL/RDvQVVbameXc6ChkjKx7/HbO+R8ejAUZQ=="
"resolved": "4.3.1.873",
"contentHash": "5Btmzjv9TWQewlHL6QPB3/deTxAfHf0cR1ixehH/4311oKUpiYrgt1uQZFTbyBWjR7zVKv1U3+s4o3IPm/++Ww=="
},
"NETStandard.Library": {
"type": "Transitive",
Expand Down Expand Up @@ -175,19 +180,14 @@
},
"Newtonsoft.Json": {
"type": "Transitive",
"resolved": "13.0.2",
"contentHash": "R2pZ3B0UjeyHShm9vG+Tu0EBb2lC8b0dFzV9gVn50ofHXh9Smjk6kTn7A/FdAsC8B5cKib1OnGYOXxRBz5XQDg=="
"resolved": "13.0.3",
"contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
},
"NuGet.Frameworks": {
"type": "Transitive",
"resolved": "5.11.0",
"contentHash": "eaiXkUjC4NPcquGWzAGMXjuxvLwc6XGKMptSyOGQeT0X70BUZObuybJFZLA0OfTdueLd3US23NBPTBb6iF3V1Q=="
},
"Portable.BouncyCastle": {
"type": "Transitive",
"resolved": "1.9.0",
"contentHash": "eZZBCABzVOek+id9Xy04HhmgykF0wZg9wpByzrWN7q8qEI0Qen9b7tfd7w8VA3dOeesumMG7C5ZPy0jk7PSRHw=="
},
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
"type": "Transitive",
"resolved": "4.3.0",
Expand Down Expand Up @@ -297,62 +297,62 @@
},
"SkiaSharp": {
"type": "Transitive",
"resolved": "2.88.3",
"contentHash": "GG8X3EdfwyBfwjl639UIiOVOKEdeoqDgYrz0P1MUCnefXt9cofN+AK8YB/v1+5cLMr03ieWCQdDmPqnFIzSxZw==",
"resolved": "2.88.5",
"contentHash": "43t9YEvcZtT+tuMN4hHH8rV8h7ttk1DRv5Tptxamy+bPuE8Up51+ME1Y1TXYAQf75686tHO488a0YKAnmJaSNg==",
"dependencies": {
"SkiaSharp.NativeAssets.Win32": "2.88.3",
"SkiaSharp.NativeAssets.macOS": "2.88.3"
"SkiaSharp.NativeAssets.Win32": "2.88.5",
"SkiaSharp.NativeAssets.macOS": "2.88.5"
}
},
"SkiaSharp.NativeAssets.Linux": {
"type": "Transitive",
"resolved": "2.88.3",
"contentHash": "wz29evZVWRqN7WHfenFwQIgqtr8f5vHCutcl1XuhWrHTRZeaIBk7ngjhyHpjUMcQxtIEAdq34ZRvMQshsBYjqg==",
"resolved": "2.88.5",
"contentHash": "VMxHc9M9ENUJA7ZZ5q5HFsYZN7DjWtlokrP0pgGqVKX/SVk858s8LiO1yoa4PGde82JJh2y8tVjFpQ6zCcSa3w==",
"dependencies": {
"SkiaSharp": "2.88.3"
"SkiaSharp": "2.88.5"
}
},
"SkiaSharp.NativeAssets.macOS": {
"type": "Transitive",
"resolved": "2.88.3",
"contentHash": "CEbWAXMGFkPV3S1snBKK7jEG3+xud/9kmSAhu0BEUKKtlMdxx+Qal0U9bntQREM9QpqP5xLWZooodi8IlV8MEg=="
"resolved": "2.88.5",
"contentHash": "snAA6ghUHBeXSOEa/lbjYMUPDKdNh4YRjU+dBoU85EMDEPlAwtkM9gESTM8FKY67ozqX8tqLzad1RRDNistGsg=="
},
"SkiaSharp.NativeAssets.Win32": {
"type": "Transitive",
"resolved": "2.88.3",
"contentHash": "MU4ASL8VAbTv5vSw1PoiWjjjpjtGhWtFYuJnrN4sNHFCePb2ohQij9JhSdqLLxk7RpRtWPdV93fbA53Pt+J0yw=="
"resolved": "2.88.5",
"contentHash": "U0GuMsdtdbHjVmuyTPRbb+ifaTPYBIV8WvPFx81ZHwzfL2TVe8SQjum8AMXSZDDlf90rhxOC5slzaL33uoHUhA=="
},
"Swashbuckle.AspNetCore": {
"type": "Transitive",
"resolved": "6.4.0",
"contentHash": "eUBr4TW0up6oKDA5Xwkul289uqSMgY0xGN4pnbOIBqCcN9VKGGaPvHX3vWaG/hvocfGDP+MGzMA0bBBKz2fkmQ==",
"resolved": "6.5.0",
"contentHash": "FK05XokgjgwlCI6wCT+D4/abtQkL1X1/B9Oas6uIwHFmYrIO9WUD5aLC9IzMs9GnHfUXOtXZ2S43gN1mhs5+aA==",
"dependencies": {
"Microsoft.Extensions.ApiDescription.Server": "6.0.5",
"Swashbuckle.AspNetCore.Swagger": "6.4.0",
"Swashbuckle.AspNetCore.SwaggerGen": "6.4.0",
"Swashbuckle.AspNetCore.SwaggerUI": "6.4.0"
"Swashbuckle.AspNetCore.Swagger": "6.5.0",
"Swashbuckle.AspNetCore.SwaggerGen": "6.5.0",
"Swashbuckle.AspNetCore.SwaggerUI": "6.5.0"
}
},
"Swashbuckle.AspNetCore.Swagger": {
"type": "Transitive",
"resolved": "6.4.0",
"contentHash": "nl4SBgGM+cmthUcpwO/w1lUjevdDHAqRvfUoe4Xp/Uvuzt9mzGUwyFCqa3ODBAcZYBiFoKvrYwz0rabslJvSmQ==",
"resolved": "6.5.0",
"contentHash": "XWmCmqyFmoItXKFsQSwQbEAsjDKcxlNf1l+/Ki42hcb6LjKL8m5Db69OTvz5vLonMSRntYO1XLqz0OP+n3vKnA==",
"dependencies": {
"Microsoft.OpenApi": "1.2.3"
}
},
"Swashbuckle.AspNetCore.SwaggerGen": {
"type": "Transitive",
"resolved": "6.4.0",
"contentHash": "lXhcUBVqKrPFAQF7e/ZeDfb5PMgE8n5t6L5B6/BQSpiwxgHzmBcx8Msu42zLYFTvR5PIqE9Q9lZvSQAcwCxJjw==",
"resolved": "6.5.0",
"contentHash": "Y/qW8Qdg9OEs7V013tt+94OdPxbRdbhcEbw4NiwGvf4YBcfhL/y7qp/Mjv/cENsQ2L3NqJ2AOu94weBy/h4KvA==",
"dependencies": {
"Swashbuckle.AspNetCore.Swagger": "6.4.0"
"Swashbuckle.AspNetCore.Swagger": "6.5.0"
}
},
"Swashbuckle.AspNetCore.SwaggerUI": {
"type": "Transitive",
"resolved": "6.4.0",
"contentHash": "1Hh3atb3pi8c+v7n4/3N80Jj8RvLOXgWxzix6w3OZhB7zBGRwsy7FWr4e3hwgPweSBpwfElqj4V4nkjYabH9nQ=="
"resolved": "6.5.0",
"contentHash": "OvbvxX+wL8skxTBttcBsVxdh73Fag4xwqEU2edh4JMn7Ws/xJHnY/JB1e9RoCb6XpDxUF3hD9A0Z1lEUx40Pfw=="
},
"System.AppContext": {
"type": "Transitive",
Expand Down Expand Up @@ -465,8 +465,8 @@
},
"System.Formats.Asn1": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "T6fD00dQ3NTbPDy31m4eQUwKW84s03z0N2C8HpOklyeaDgaJPa/TexP4/SkORMSOwc7WhKifnA6Ya33AkzmafA=="
"resolved": "7.0.0",
"contentHash": "+nfpV0afLmvJW8+pLlHxRjz3oZJw4fkyU9MMEaMhCsHi/SN9bGF9q79ROubDiwTiCHezmK0uCWkPP7tGFP/4yg=="
},
"System.Globalization": {
"type": "Transitive",
Expand Down Expand Up @@ -944,10 +944,10 @@
},
"System.Security.Cryptography.Pkcs": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "elM3x+xSRhzQysiqo85SbidJJ2YbZlnvmh+53TuSZHsD7dNuuEWser+9EFtY+rYupBwkq2avc6ZCO3/6qACgmg==",
"resolved": "7.0.2",
"contentHash": "xhFNJOcQSWhpiVGLLBQYoxAltQSQVycMkwaX1z7I7oEdT9Wr0HzSM1yeAbfoHaERIYd5s6EpLSOLs2qMchSKlA==",
"dependencies": {
"System.Formats.Asn1": "6.0.0"
"System.Formats.Asn1": "7.0.0"
}
},
"System.Security.Cryptography.Primitives": {
Expand Down Expand Up @@ -1008,11 +1008,8 @@
},
"System.Text.Encoding.CodePages": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "ZFCILZuOvtKPauZ/j/swhvw68ZRi9ATCfvGbk1QfydmcXBkIWecWKn/250UH7rahZ5OoDBaiAudJtPvLwzw85A==",
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
"resolved": "7.0.0",
"contentHash": "LSyCblMpvOe0N3E+8e0skHcrIhgV2huaNcjUUEa8hRtgEAm36aGkRoC8Jxlb6Ra6GSfF29ftduPNywin8XolzQ=="
},
"System.Text.Encoding.Extensions": {
"type": "Transitive",
Expand Down Expand Up @@ -1115,10 +1112,10 @@
},
"Telegram.Bot": {
"type": "Transitive",
"resolved": "18.0.0",
"contentHash": "BD0UchUXINymCGS+1O1tv2enCRyv+VbSJQAgfnueTZs3j7K4XXyJyW0CgyJleTrqB1oq1hS1ux6gBpi3Ajp+ZQ==",
"resolved": "19.0.0",
"contentHash": "Q16IOitgjGoaJOuqgKQy0FeF+hr/ncmlX2esrhCC7aiyhSX7roYEriWaGAHkQZR8QzbImjFfl4eQh2IxcnOrPg==",
"dependencies": {
"Newtonsoft.Json": "12.0.2"
"Newtonsoft.Json": "13.0.1"
}
},
"xunit.abstractions": {
Expand Down Expand Up @@ -1169,15 +1166,15 @@
"synoai": {
"type": "Project",
"dependencies": {
"MQTTnet": "[4.1.4.563, )",
"MailKit": "[3.4.3, )",
"Microsoft.VisualStudio.Azure.Containers.Tools.Targets": "[1.17.0, )",
"Newtonsoft.Json": "[13.0.2, )",
"SkiaSharp": "[2.88.3, )",
"SkiaSharp.NativeAssets.Linux": "[2.88.3, )",
"Swashbuckle.AspNetCore": "[6.4.0, )",
"MQTTnet": "[4.3.1.873, )",
"MailKit": "[4.2.0, )",
"Microsoft.VisualStudio.Azure.Containers.Tools.Targets": "[1.19.5, )",
"Newtonsoft.Json": "[13.0.3, )",
"SkiaSharp": "[2.88.5, )",
"SkiaSharp.NativeAssets.Linux": "[2.88.5, )",
"Swashbuckle.AspNetCore": "[6.5.0, )",
"System.Drawing.Common": "[7.0.0, )",
"Telegram.Bot": "[18.0.0, )"
"Telegram.Bot": "[19.0.0, )"
}
}
}
Expand Down
18 changes: 17 additions & 1 deletion SynoAI/AIs/AI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,24 @@

namespace SynoAI.AIs
{
internal abstract class AI
/// <summary>
/// Represents the base class for all AI implementations.
/// </summary>
public abstract class AI
{
/// <summary>
/// Gets the type of the AI being used.
/// </summary>
/// <value>The type of the AI.</value>
public abstract AIType AIType { get; }

/// <summary>
/// Processes the given image using the AI and returns the predictions.
/// </summary>
/// <param name="logger">The logger to use for logging.</param>
/// <param name="camera">The camera from which the image was captured.</param>
/// <param name="image">The image to be processed.</param>
/// <returns>A list of predictions made by the AI.</returns>
public abstract Task<IEnumerable<AIPrediction>> Process(ILogger logger, Camera camera, byte[] image);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
using SynoAI.App;
using SynoAI.Models;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace SynoAI.AIs.DeepStack
namespace SynoAI.AIs.AIProcessor
{
internal class DeepStackAI : AI
internal class AIProcessorAI : AI
{
public override AIType AIType => Config.AI;
public override async Task<IEnumerable<AIPrediction>> Process(ILogger logger, Camera camera, byte[] image)
{
Stopwatch stopwatch = Stopwatch.StartNew();
Expand All @@ -19,7 +21,12 @@ public override async Task<IEnumerable<AIPrediction>> Process(ILogger logger, Ca
{ new StringContent(minConfidence.ToString()), "min_confidence" } // From face detection example - using JSON with MinConfidence didn't always work
};

logger.LogDebug($"{camera.Name}: DeepStackAI: POSTing image with minimum confidence of {minConfidence} ({camera.Threshold}%) to {string.Join("/", Config.AIUrl, Config.AIPath)}.");
logger.LogDebug("{CameraName}: {AIType}: POSTing image with minimum confidence of {MinConfidence} ({CameraThreshold}%) to {Url}.",
camera.Name,
this.AIType,
minConfidence,
camera.Threshold,
string.Join("/", Config.AIUrl, Config.AIPath));

Uri uri = GetUri(Config.AIUrl, Config.AIPath);

Expand All @@ -28,7 +35,7 @@ public override async Task<IEnumerable<AIPrediction>> Process(ILogger logger, Ca
HttpResponseMessage response = await Shared.HttpClient.PostAsync(uri, multipartContent);
if (response.IsSuccessStatusCode)
{
DeepStackResponse deepStackResponse = await GetResponse(logger, camera, response);
AIProcessorResponse deepStackResponse = await GetResponse(logger, camera, response, this.AIType);
if (deepStackResponse.Success)
{
IEnumerable<AIPrediction> predictions = deepStackResponse.Predictions.Where(x => x.Confidence >= minConfidence).Select(x => new AIPrediction()
Expand All @@ -42,22 +49,35 @@ public override async Task<IEnumerable<AIPrediction>> Process(ILogger logger, Ca
}).ToList();

stopwatch.Stop();
logger.LogInformation($"{camera.Name}: DeepStackAI: Processed successfully ({stopwatch.ElapsedMilliseconds}ms).");
logger.LogInformation("{CameraName}: {AIType}: Processed successfully ({ElapsedMilliseconds}ms).",
camera.Name,
this.AIType,
stopwatch.ElapsedMilliseconds);

return predictions;
}
else
{
logger.LogWarning($"{camera.Name}: DeepStackAI: Failed with unknown error.");
logger.LogWarning("{cameraName}: {AIType}: Failed with unknown error.",
camera.Name,
this.AIType);
}
}
else
{
logger.LogWarning($"{camera.Name}: DeepStackAI: Failed to call API with HTTP status code '{response.StatusCode}'.");
logger.LogWarning("{cameraName}: {AIType}: Failed to call API with HTTP status code '{responseStatusCode}'.",
camera.Name,
this.AIType,
response.StatusCode);
}
}
catch (HttpRequestException ex)
{
logger.LogError($"{camera.Name}: DeepStackAI: Failed to call API error '{ex}'.");
logger.LogError("{camera.Name}: {AIType}: Failed to call API error '{ex}'.",
camera.Name,
this.AIType,
ex
);
}

return null;
Expand All @@ -81,13 +101,17 @@ protected static Uri GetUri(string basePath, string resourcePath)
/// <param name="camera"></param>
/// <param name="message">The message to parse.</param>
/// <param name="logger"></param>
/// <param name="aiType"></param>
/// <returns>A usable object.</returns>
private static async Task<DeepStackResponse> GetResponse(ILogger logger, Camera camera, HttpResponseMessage message)
private static async Task<AIProcessorResponse> GetResponse(ILogger logger, Camera camera, HttpResponseMessage message, AIType aiType)
{
string content = await message.Content.ReadAsStringAsync();
logger.LogDebug($"{camera.Name}: DeepStackAI: Responded with {content}.");
logger.LogDebug("{cameraName}: {AIType}: Responded with {content}.",
camera.Name,
aiType,
content);

return JsonConvert.DeserializeObject<DeepStackResponse>(content);
return JsonConvert.DeserializeObject<AIProcessorResponse>(content);
}
}
}
Loading
Loading