Skip to content

Commit 9307996

Browse files
author
ChrisMaunder
committed
v2.5.1: Reworking modulesettings schema / correcting Promise/async dichotomy
1 parent ea23919 commit 9307996

File tree

225 files changed

+6024
-5302
lines changed

Some content is hidden

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

225 files changed

+6024
-5302
lines changed

src/SDK/NET/API/ApiClient.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public async Task<ServerResponse> GetAsync(string route)
145145
}
146146
catch (Exception ex)
147147
{
148-
response = new ServerErrorResponse(ex.Message);
148+
response = new ServerErrorResponse("GetAsync error: " + ex.Message);
149149
}
150150

151151
return response;
@@ -178,7 +178,7 @@ public async Task<ServerResponse> GetAsync<T>(string route)
178178
}
179179
catch (Exception ex)
180180
{
181-
response = new ServerErrorResponse(ex.Message);
181+
response = new ServerErrorResponse("GetAsync<T> error: " + ex.Message);
182182
}
183183

184184
return response;
@@ -212,7 +212,7 @@ public async Task<ServerResponse> PostAsync<T>(string route, ServerRequestConten
212212
}
213213
catch (Exception ex)
214214
{
215-
response = new ServerErrorResponse(ex.Message);
215+
response = new ServerErrorResponse("PostAsync error: " + ex.Message);
216216
}
217217

218218
return response;

src/SDK/NET/API/ExplorerUI.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,44 @@
22

33
namespace CodeProject.AI.SDK.API
44
{
5+
/// <summary>
6+
/// Represents an option in a dropdown menu in the dashboard
7+
/// </summary>
8+
public class DashboardMenuOption
9+
{
10+
/// <summary>
11+
/// Gets or sets the label for this menu option
12+
/// </summary>
13+
public string? Label { get; set; }
14+
15+
/// <summary>
16+
/// Gets or sets the setting to be modified by this menu option
17+
/// </summary>
18+
public string? Setting { get; set; }
19+
20+
/// <summary>
21+
/// Gets or sets the value to be set by this menu option
22+
/// </summary>
23+
public string? Value { get; set; }
24+
}
25+
26+
/// <summary>
27+
/// Represents a dropdown menu in the dashboard. This will be used to construct a dropdown menu
28+
/// in the CodeProject.AI Server dashboard for the given module.
29+
/// </summary>
30+
public class DashboardMenu
31+
{
32+
/// <summary>
33+
/// Gets or sets the label for this menu
34+
/// </summary>
35+
public string? Label { get; set; }
36+
37+
/// <summary>
38+
/// Gets or sets the options for this menu
39+
/// </summary>
40+
public DashboardMenuOption[]? Options { get; set; }
41+
}
42+
543
/// <summary>
644
/// A structure containing the HTML, CSS and Javascript that are to be injected into the
745
/// Explorer web app to allow the user to explore and test a module.

src/SDK/NET/API/ModuleResponses.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ public class ModuleResponse : BaseResponse
4848
/// response.
4949
/// </summary>
5050
public long AnalysisRoundTripMs { get; set; }
51+
52+
/// <summary>
53+
/// Gets or set a dictionary representing the current module status
54+
/// </summary>
55+
public object? StatusData { get; set; }
5156
}
5257

5358
/// <summary>

src/SDK/NET/API/VersionInfo.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public class VersionInfo
3030
/// <summary>
3131
/// Gets or sets a value indicating whether this version contains a security update
3232
/// </summary>
33-
public bool? SecurityUpdate { get; set; }
33+
public bool SecurityUpdate { get; set; }
3434

3535
/// <summary>
3636
/// Gets or sets the build number
@@ -155,11 +155,19 @@ public static int Compare(VersionInfo versionA, VersionInfo versionB)
155155
if (versionA.Build != versionB.Build)
156156
return versionA.Build - versionB.Build;
157157

158-
// int result = (versionA.PreRelease ?? "").CompareTo(versionB.PreRelease ?? "");
159-
// if (result != 0)
160-
// return result;
158+
// A pre-release string will be greater than an empty string. We actually want the
159+
// opposite. 2.5.0 > 2.5.0-RC1 and 2.5.0-RTM > 2.5.0-RC1
161160

162-
return (versionA.SecurityUpdate ?? false).CompareTo(versionB.SecurityUpdate ?? false);
161+
if (string.IsNullOrWhiteSpace(versionA.PreRelease) && !string.IsNullOrWhiteSpace(versionB.PreRelease))
162+
return 1;
163+
164+
if (!string.IsNullOrWhiteSpace(versionA.PreRelease) && string.IsNullOrWhiteSpace(versionB.PreRelease))
165+
return -1;
166+
167+
if (!(versionA.PreRelease ?? string.Empty).Equals(versionB.PreRelease ?? string.Empty))
168+
return (versionA.PreRelease ?? string.Empty).CompareTo(versionB.PreRelease ?? string.Empty);
169+
170+
return versionA.SecurityUpdate.CompareTo(versionB.SecurityUpdate);
163171
}
164172
}
165173
}

src/SDK/NET/Analysis/BackendClient.cs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public BackendClient(string url, TimeSpan timeout = default, CancellationToken t
3434
_httpClient ??= new HttpClient
3535
{
3636
BaseAddress = new Uri(url),
37-
Timeout = (timeout == default) ? TimeSpan.FromMinutes(1) : timeout
37+
Timeout = (timeout == default) ? TimeSpan.FromMinutes(1) : timeout
3838
};
3939

4040
loggingTask = ProcessLoggingQueue(token);
@@ -77,33 +77,27 @@ public BackendClient(string url, TimeSpan timeout = default, CancellationToken t
7777
BackendRequest? request = null;
7878
try
7979
{
80-
//request = await _httpClient!.GetFromJsonAsync<BackendRequest>(requestUri, token)
81-
// .ConfigureAwait(false);
82-
var response = await _httpClient!.GetAsync(requestUri, token);
83-
// only process responses that have content
80+
HttpResponseMessage response = await _httpClient!.GetAsync(requestUri, token);
8481
if (response.StatusCode == System.Net.HttpStatusCode.OK)
85-
{
8682
request = await response.Content.ReadFromJsonAsync<BackendRequest>();
87-
}
88-
else
89-
{
90-
return null;
91-
}
9283
}
9384
catch (JsonException)
9485
{
86+
#if DEBUG
87+
Debug.WriteLine("JsonException GetRequest");
88+
#endif
9589
// This is probably due to timing out and therefore no JSON to parse.
9690
}
9791
#if DEBUG
9892
catch (Exception ex)
9993
{
100-
Debug.WriteLine(ex);
94+
Debug.WriteLine("Error in GetRequest: " + ex.Message);
10195
#else
10296
catch (Exception /*ex*/)
10397
{
10498
#endif
10599
Console.WriteLine($"Unable to get request from {queueName} for {moduleId}");
106-
_errorPauseSecs = Math.Min(_errorPauseSecs > 0 ? _errorPauseSecs * 2 : 5, 60);
100+
_errorPauseSecs = Math.Min(_errorPauseSecs > 0 ? _errorPauseSecs * 3/2 : 5, 30);
107101

108102
if (!token.IsCancellationRequested && _errorPauseSecs > 0)
109103
{
@@ -199,7 +193,7 @@ private async Task ProcessLoggingQueue(CancellationToken token = default)
199193
}
200194
catch(Exception e)
201195
{
202-
Debug.Write(e);
196+
Debug.Write("Error processing logging queue: " + e.Message);
203197
}
204198
}
205199
}

src/SDK/NET/Analysis/BackendRequests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ public void AddFile(string filePath)
216216
}
217217
catch (Exception e)
218218
{
219-
Debug.WriteLine(e);
219+
Debug.WriteLine("Error adding file: " + e.Message);
220220
}
221221
}
222222

src/SDK/NET/Analysis/ModuleWorkerBase.cs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Diagnostics;
2+
using System.Dynamic;
23
using System.Net.Http.Json;
34

45
using CodeProject.AI.SDK.API;
@@ -28,8 +29,11 @@ public abstract class ModuleWorkerBase : BackgroundService
2829
private readonly ILogger _logger;
2930
private readonly IHostApplicationLifetime _appLifetime;
3031

31-
private bool _cancelled = false;
32-
private bool _performSelfTest = false;
32+
private bool _cancelled = false;
33+
private bool _performSelfTest = false;
34+
private int _successInferences;
35+
private long _totalSuccessInf_ms;
36+
private int _failedInferences;
3337

3438
/// <summary>
3539
/// Gets or sets the name of this Module
@@ -93,7 +97,7 @@ public ModuleWorkerBase(ILogger logger, IConfiguration configuration,
9397
EnableGPU = configuration.GetValue<bool>("CPAI_MODULE_ENABLE_GPU", true);
9498
_accelDeviceName = configuration.GetValue<string?>("CPAI_ACCEL_DEVICE_NAME", null);
9599
_halfPrecision = configuration.GetValue<string?>("CPAI_HALF_PRECISION", null) ?? "enable"; // Can be enable, disable or force
96-
_logVerbosity = configuration.GetValue<string?>("CPAI_LOG_VERBOSITY", null) ?? "info"; // Can be Quiet, Info or Loud
100+
_logVerbosity = configuration.GetValue<string?>("CPAI_LOG_VERBOSITY", null) ?? "quiet"; // Can be Quiet, Info or Loud
97101

98102
_performSelfTest = configuration.GetValue<bool>("CPAI_MODULE_DO_SELFTEST", false);
99103

@@ -127,6 +131,22 @@ protected virtual void InitModule()
127131
/// <returns>An object to serialize back to the server.</returns>
128132
protected abstract ModuleResponse ProcessRequest(BackendRequest request);
129133

134+
/// <summary>
135+
/// Returns an object containing current stats for this module
136+
/// </summary>
137+
/// <returns>An object</returns>
138+
protected virtual dynamic? Status()
139+
{
140+
dynamic status = new ExpandoObject();
141+
status.SuccessfulInferences = _successInferences;
142+
status.FailedInferences = _failedInferences;
143+
status.NumInferences = _successInferences + _failedInferences;
144+
status.AverageInferenceMs = _successInferences > 0
145+
? _totalSuccessInf_ms / _successInferences : 0;
146+
147+
return status;
148+
}
149+
130150
/// <summary>
131151
/// Called when the module is asked to execute a self-test to ensure it install and runs
132152
/// correctly
@@ -188,13 +208,22 @@ private async Task ProcessQueue(CancellationToken token, int taskNumber)
188208
ModuleResponse response = ProcessRequest(request);
189209
stopWatch.Stop();
190210

211+
if (response.Success)
212+
{
213+
_successInferences++;
214+
_totalSuccessInf_ms += response.InferenceMs;
215+
}
216+
else
217+
_failedInferences++;
218+
191219
long processMs = stopWatch.ElapsedMilliseconds;
192220
response.ModuleName = ModuleName;
193221
response.ModuleId = _moduleId;
194222
response.ProcessMs = processMs;
195223
response.ExecutionProvider = ExecutionProvider ?? string.Empty;
196224
response.Command = request.payload?.command ?? string.Empty;
197225
response.CanUseGPU = CanUseGPU;
226+
response.StatusData = Status();
198227

199228
HttpContent content = JsonContent.Create(response, response.GetType());
200229

src/SDK/NET/Common/Constants.cs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
namespace CodeProject.AI.SDK.Common
2+
{
3+
/// <summary>
4+
/// Contains constants for CodeProject.AI Server
5+
/// </summary>
6+
public static class Constants
7+
{
8+
/// <summary>
9+
/// The name of the company publishing this (will first check project file - it should be there)
10+
/// </summary>
11+
public const string Company = "CodeProject";
12+
13+
/// <summary>
14+
/// The product name (will first check project file - it should be there)
15+
/// </summary>
16+
public const string ProductName = "CodeProject.AI Server";
17+
18+
/// <summary>
19+
/// The category of product. Handy for placing this in a subdir of the main company dir.
20+
/// </summary>
21+
public const string ProductCategory = "AI";
22+
23+
/// <summary>
24+
/// The default port the server listens on using HTTP
25+
/// </summary>
26+
public const int DefaultPort = 32168;
27+
28+
/// <summary>
29+
/// The default port the server listens on when using HTTP with SSL/TLS
30+
/// </summary>
31+
public const int DefaultPortSsl = 32016;
32+
33+
/// <summary>
34+
/// The legacy port (Deepstack compatibility) the server listens on
35+
/// </summary>
36+
public const int LegacyPort = 5000;
37+
38+
/// <summary>
39+
/// The legacy port the server listens on when running under macOS
40+
/// </summary>
41+
public const int LegacyPortOsx = 5500;
42+
43+
/// <summary>
44+
/// Used wherever there needs to be a distinction between release and dev. Typically used in
45+
/// filenames
46+
/// </summary>
47+
public const string Development = "development";
48+
49+
/// <summary>
50+
/// The name of the file containing the settings for the server
51+
/// </summary>
52+
public const string ServerSettingsFilename = "serversettings.json";
53+
54+
/// <summary>
55+
/// The name of the file containing the settings for the server for the development environment
56+
/// </summary>
57+
public const string DevServerSettingsFilename = $"serversettings.{Development}.json";
58+
59+
/// <summary>
60+
/// The name of the modules settings file without extension
61+
/// </summary>
62+
public const string ModulesSettingFilenameNoExt = "modulesettings";
63+
64+
/// <summary>
65+
/// The name of the file containing the settings for a module, or a collection of modules
66+
/// (This file can handle one or more sets of settings)
67+
/// </summary>
68+
public const string ModuleSettingsFilename = ModulesSettingFilenameNoExt + ".json";
69+
70+
/// <summary>
71+
/// The name of the file containing the settings for a module, or a collection of modules,
72+
/// for the development environment
73+
/// </summary>
74+
public const string DevModuleSettingsFilename = $"{ModulesSettingFilenameNoExt}.{Development}.json";
75+
76+
/// <summary>
77+
/// The name of the file that stores the list of known modules
78+
/// </summary>
79+
public const string ModulesListingFilename = "modules.json";
80+
};
81+
}

0 commit comments

Comments
 (0)