feat: use separate process for classifying
This commit is contained in:
parent
b2e719faa0
commit
87c5602319
|
@ -1,36 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.ML;
|
||||
using NoSoliciting.Interface;
|
||||
|
||||
namespace NoSoliciting.CursedWorkaround {
|
||||
[Serializable]
|
||||
public class CursedWorkaround : MarshalByRefObject, IClassifier, IDisposable {
|
||||
private MLContext Context { get; set; } = null!;
|
||||
private ITransformer Model { get; set; } = null!;
|
||||
private DataViewSchema Schema { get; set; } = null!;
|
||||
private PredictionEngine<Data, Prediction> PredictionEngine { get; set; } = null!;
|
||||
|
||||
public override object? InitializeLifetimeService() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Initialise(byte[] data) {
|
||||
this.Context = new MLContext();
|
||||
this.Context.ComponentCatalog.RegisterAssembly(typeof(Data).Assembly);
|
||||
using var stream = new MemoryStream(data);
|
||||
var model = this.Context.Model.Load(stream, out var schema);
|
||||
this.Model = model;
|
||||
this.Schema = schema;
|
||||
this.PredictionEngine = this.Context.Model.CreatePredictionEngine<Data, Prediction>(this.Model, this.Schema);
|
||||
}
|
||||
|
||||
public string Classify(ushort channel, string message) {
|
||||
return this.PredictionEngine.Predict(new Data(channel, message)).Category;
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
this.PredictionEngine.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System.Text;
|
||||
using JKang.IpcServiceFramework;
|
||||
using JKang.IpcServiceFramework.Services;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace NoSoliciting.Interface {
|
||||
public class BetterIpcSerialiser : IIpcMessageSerializer {
|
||||
private static readonly JsonSerializerSettings Settings = new() {
|
||||
TypeNameHandling = TypeNameHandling.Auto,
|
||||
};
|
||||
|
||||
public byte[] SerializeRequest(IpcRequest request) {
|
||||
var json = JsonConvert.SerializeObject(request, Formatting.None, Settings);
|
||||
return Encoding.UTF8.GetBytes(json);
|
||||
}
|
||||
|
||||
public IpcResponse? DeserializeResponse(byte[] binary) {
|
||||
var json = Encoding.UTF8.GetString(binary);
|
||||
return JsonConvert.DeserializeObject<IpcResponse>(json, Settings);
|
||||
}
|
||||
|
||||
public IpcRequest? DeserializeRequest(byte[] binary) {
|
||||
var json = Encoding.UTF8.GetString(binary);
|
||||
return JsonConvert.DeserializeObject<IpcRequest>(json, Settings);
|
||||
}
|
||||
|
||||
public byte[] SerializeResponse(IpcResponse response) {
|
||||
var json = JsonConvert.SerializeObject(response, Formatting.None, Settings);
|
||||
return Encoding.UTF8.GetBytes(json);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<LangVersion>8</LangVersion>
|
||||
<TargetFrameworks>net48;netcoreapp3.1</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.ML" Version="1.5.4" />
|
||||
<PackageReference Include="JKang.IpcServiceFramework.Core" Version="3.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
29
NoSoliciting.Interface/Data.cs → NoSoliciting.Internal.Interface/Data.cs
Normal file → Executable file
29
NoSoliciting.Interface/Data.cs → NoSoliciting.Internal.Interface/Data.cs
Normal file → Executable file
|
@ -7,8 +7,11 @@ using System.Text.RegularExpressions;
|
|||
using Microsoft.ML.Data;
|
||||
using Microsoft.ML.Transforms;
|
||||
|
||||
namespace NoSoliciting.Interface {
|
||||
namespace NoSoliciting.Internal.Interface {
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
[SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global")]
|
||||
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
public class Data {
|
||||
[LoadColumn(0)]
|
||||
public string? Category { get; set; }
|
||||
|
@ -30,6 +33,7 @@ namespace NoSoliciting.Interface {
|
|||
#region computed
|
||||
|
||||
[CustomMappingFactoryAttribute("Compute")]
|
||||
[SuppressMessage("ReSharper", "UnusedType.Global")]
|
||||
public class ComputeContext : CustomMappingFactory<Data, Computed> {
|
||||
private Dictionary<string, float> Weights { get; }
|
||||
|
||||
|
@ -51,18 +55,18 @@ namespace NoSoliciting.Interface {
|
|||
}
|
||||
|
||||
private static readonly Regex[] PlotWords = {
|
||||
new Regex(@"\bplot\b", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new Regex(@"\bapartment\b", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new Regex(@"\bapt\b", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new Regex(@"p.{0,2}\d", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new(@"\bplot\b", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new(@"\bapartment\b", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new(@"\bapt\b", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new(@"p.{0,2}\d", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
};
|
||||
|
||||
private static readonly Regex[] WardWords = {
|
||||
new Regex(@"\bward\b", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new Regex(@"w.{0,2}\d", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new(@"\bward\b", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new(@"w.{0,2}\d", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
};
|
||||
|
||||
private static readonly Regex NumbersRegex = new Regex(@"\d{1,2}.{0,2}\d{1,2}", RegexOptions.Compiled);
|
||||
private static readonly Regex NumbersRegex = new(@"\d{1,2}.{0,2}\d{1,2}", RegexOptions.Compiled);
|
||||
|
||||
private static readonly string[] TradeWords = {
|
||||
"B> ",
|
||||
|
@ -73,8 +77,9 @@ namespace NoSoliciting.Interface {
|
|||
"WTS",
|
||||
};
|
||||
|
||||
private static readonly Regex SketchUrlRegex = new Regex(@"\.com-\w+\.\w+", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
private static readonly Regex SketchUrlRegex = new(@"\.com-\w+\.\w+", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
|
||||
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Global")]
|
||||
public class Computed {
|
||||
public float Weight { get; set; } = 1;
|
||||
|
||||
|
@ -110,12 +115,14 @@ namespace NoSoliciting.Interface {
|
|||
#endregion
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global")]
|
||||
[SuppressMessage("ReSharper", "UnusedMember.Global")]
|
||||
public class Prediction {
|
||||
[ColumnName("PredictedLabel")]
|
||||
public string Category { get; set; }
|
||||
public string Category { get; set; } = "UNKNOWN";
|
||||
|
||||
[ColumnName("Score")]
|
||||
public float[] Probabilities { get; set; }
|
||||
public float[] Probabilities { get; set; } = new float[0];
|
||||
}
|
||||
|
||||
internal static class Ext {
|
|
@ -0,0 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netcoreapp3.1;net48</TargetFrameworks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.ML" Version="1.5.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
11
NoSoliciting.CursedWorkaround/FodyWeavers.xml → NoSoliciting.MessageClassifier/FodyWeavers.xml
Normal file → Executable file
11
NoSoliciting.CursedWorkaround/FodyWeavers.xml → NoSoliciting.MessageClassifier/FodyWeavers.xml
Normal file → Executable file
|
@ -1,9 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<Costura>
|
||||
<ExcludeAssemblies>
|
||||
Costura
|
||||
NoSoliciting.Interface
|
||||
</ExcludeAssemblies>
|
||||
</Costura>
|
||||
<Costura>
|
||||
<ExcludeAssemblies>
|
||||
Costura
|
||||
</ExcludeAssemblies>
|
||||
</Costura>
|
||||
</Weavers>
|
|
@ -1,30 +1,30 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<LangVersion>8</LangVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Costura.Fody" Version="4.1.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<ProjectReference Include="..\NoSoliciting.Interface\NoSoliciting.Interface.csproj" />
|
||||
<ProjectReference Include="..\NoSoliciting.Internal.Interface\NoSoliciting.Internal.Interface.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Costura.Fody" Version="4.1.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Fody" Version="6.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="JKang.IpcServiceFramework.Hosting.NamedPipe" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.ML" Version="1.5.4" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NoSoliciting.Interface\NoSoliciting.Interface.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="costura64\CpuMathNative.dll" />
|
||||
<EmbeddedResource Include="costura64\CpuMathNative.dll" />
|
||||
<EmbeddedResource Include="costura64\*.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using JKang.IpcServiceFramework.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.ML;
|
||||
using NoSoliciting.Interface;
|
||||
using NoSoliciting.Internal.Interface;
|
||||
|
||||
namespace NoSoliciting.MessageClassifier {
|
||||
internal static class Program {
|
||||
private static void Main() {
|
||||
Host.CreateDefaultBuilder()
|
||||
.ConfigureServices(services => {
|
||||
services.AddSingleton<IClassifier, ClassifierService>();
|
||||
})
|
||||
.ConfigureIpcHost(builder => {
|
||||
builder.AddNamedPipeEndpoint<IClassifier>(options => {
|
||||
options.PipeName = "NoSoliciting.MessageClassifier";
|
||||
options.Serializer = new BetterIpcSerialiser();
|
||||
});
|
||||
})
|
||||
.Build()
|
||||
.Run();
|
||||
}
|
||||
}
|
||||
|
||||
internal class ClassifierService : IClassifier, IDisposable {
|
||||
private MLContext Context { get; set; } = null!;
|
||||
private ITransformer Model { get; set; } = null!;
|
||||
private DataViewSchema Schema { get; set; } = null!;
|
||||
private PredictionEngine<Data, Prediction>? PredictionEngine { get; set; }
|
||||
|
||||
public void Initialise(byte[] data) {
|
||||
if (this.PredictionEngine != null) {
|
||||
this.PredictionEngine.Dispose();
|
||||
this.PredictionEngine = null;
|
||||
}
|
||||
|
||||
this.Context = new MLContext();
|
||||
this.Context.ComponentCatalog.RegisterAssembly(typeof(Data).Assembly);
|
||||
using var stream = new MemoryStream(data);
|
||||
var model = this.Context.Model.Load(stream, out var schema);
|
||||
this.Model = model;
|
||||
this.Schema = schema;
|
||||
this.PredictionEngine = this.Context.Model.CreatePredictionEngine<Data, Prediction>(this.Model, this.Schema);
|
||||
}
|
||||
|
||||
public string Classify(ushort channel, string message) {
|
||||
return this.PredictionEngine?.Predict(new Data(channel, message))?.Category ?? "UNKNOWN";
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
this.PredictionEngine?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -3,17 +3,18 @@
|
|||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConsoleTables" Version="2.4.2" />
|
||||
<PackageReference Include="CsvHelper" Version="19.0.0" />
|
||||
<PackageReference Include="CsvHelper" Version="21.3.1" />
|
||||
<PackageReference Include="Microsoft.ML" Version="1.5.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NoSoliciting.Interface\NoSoliciting.Interface.csproj" />
|
||||
<ProjectReference Include="..\NoSoliciting.Internal.Interface\NoSoliciting.Internal.Interface.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -9,7 +9,7 @@ using CsvHelper.Configuration;
|
|||
using Microsoft.ML;
|
||||
using Microsoft.ML.Data;
|
||||
using Microsoft.ML.Transforms.Text;
|
||||
using NoSoliciting.Interface;
|
||||
using NoSoliciting.Internal.Interface;
|
||||
|
||||
namespace NoSoliciting.Trainer {
|
||||
internal static class Program {
|
||||
|
@ -36,7 +36,7 @@ namespace NoSoliciting.Trainer {
|
|||
using (var fileStream = new FileStream("../../../data.csv", FileMode.Create)) {
|
||||
using var stream = new StreamWriter(fileStream);
|
||||
using var csv = new CsvWriter(stream, new CsvConfiguration(CultureInfo.InvariantCulture) {
|
||||
NewLine = NewLine.LF,
|
||||
NewLine = "\n",
|
||||
});
|
||||
csv.WriteRecords(records);
|
||||
}
|
||||
|
@ -179,10 +179,4 @@ namespace NoSoliciting.Trainer {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Ext {
|
||||
public static bool ContainsIgnoreCase(this string haystack, string needle) {
|
||||
return CultureInfo.InvariantCulture.CompareInfo.IndexOf(haystack, needle, CompareOptions.IgnoreCase) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Text;
|
|||
|
||||
namespace NoSoliciting.Trainer {
|
||||
public static class Util {
|
||||
private static readonly Dictionary<char, string> Replacements = new Dictionary<char, string> {
|
||||
private static readonly Dictionary<char, string> Replacements = new() {
|
||||
// numerals
|
||||
['\ue055'] = "1",
|
||||
['\ue056'] = "2",
|
||||
|
|
|
@ -9,12 +9,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoSoliciting.Tests", "NoSoliciting.Tests\NoSoliciting.Tests.csproj", "{1962D91F-543A-4214-88FD-788BB7ACECE3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoSoliciting.CursedWorkaround", "NoSoliciting.CursedWorkaround\NoSoliciting.CursedWorkaround.csproj", "{F3238422-A9D8-4E71-9365-9EFFEC85CB59}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoSoliciting.Interface", "NoSoliciting.Interface\NoSoliciting.Interface.csproj", "{E88E57AB-EFB8-4F2F-93DB-F63123638C44}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoSoliciting.Trainer", "NoSoliciting.Trainer\NoSoliciting.Trainer.csproj", "{3D774127-F7A9-4B6D-AB2F-3AAF80D15586}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoSoliciting.MessageClassifier", "NoSoliciting.MessageClassifier\NoSoliciting.MessageClassifier.csproj", "{16689469-6A74-4197-818A-EA44697BD815}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NoSoliciting.Internal.Interface", "NoSoliciting.Internal.Interface\NoSoliciting.Internal.Interface.csproj", "{742F1B3F-030F-4886-B05D-0D41D4DDA8FD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -29,10 +31,6 @@ Global
|
|||
{1962D91F-543A-4214-88FD-788BB7ACECE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1962D91F-543A-4214-88FD-788BB7ACECE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1962D91F-543A-4214-88FD-788BB7ACECE3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F3238422-A9D8-4E71-9365-9EFFEC85CB59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F3238422-A9D8-4E71-9365-9EFFEC85CB59}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F3238422-A9D8-4E71-9365-9EFFEC85CB59}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F3238422-A9D8-4E71-9365-9EFFEC85CB59}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E88E57AB-EFB8-4F2F-93DB-F63123638C44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E88E57AB-EFB8-4F2F-93DB-F63123638C44}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E88E57AB-EFB8-4F2F-93DB-F63123638C44}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
@ -41,6 +39,14 @@ Global
|
|||
{3D774127-F7A9-4B6D-AB2F-3AAF80D15586}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3D774127-F7A9-4B6D-AB2F-3AAF80D15586}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3D774127-F7A9-4B6D-AB2F-3AAF80D15586}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{16689469-6A74-4197-818A-EA44697BD815}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{16689469-6A74-4197-818A-EA44697BD815}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{16689469-6A74-4197-818A-EA44697BD815}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{16689469-6A74-4197-818A-EA44697BD815}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{742F1B3F-030F-4886-B05D-0D41D4DDA8FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{742F1B3F-030F-4886-B05D-0D41D4DDA8FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{742F1B3F-030F-4886-B05D-0D41D4DDA8FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{742F1B3F-030F-4886-B05D-0D41D4DDA8FD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
AssemblyName="$(AssemblyName)"
|
||||
VersionComponents="3"
|
||||
MakeZip="true"
|
||||
Include="NoSoliciting.json;NoSoliciting.dll;NoSoliciting.Interface.dll;NoSoliciting.CursedWorkaround.dll;YamlDotNet.dll"/>
|
||||
Include="NoSoliciting.json;NoSoliciting.dll;NoSoliciting.pdb"/>
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<Resourcer />
|
||||
</Weavers>
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Target Name="ILRepacker" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
|
||||
|
||||
<ItemGroup>
|
||||
<InputAssemblies Include="$(OutputPath)\NoSoliciting.dll"/>
|
||||
<InputAssemblies Include="$(OutputPath)\NoSoliciting.Interface.dll"/>
|
||||
<InputAssemblies Include="$(OutputPath)\J*.dll"/>
|
||||
<InputAssemblies Include="$(OutputPath)\M*.dll"/>
|
||||
<InputAssemblies Include="$(OutputPath)\S*.dll"/>
|
||||
<InputAssemblies Include="$(OutputPath)\Y*.dll"/>
|
||||
</ItemGroup>
|
||||
<ILRepack
|
||||
Parallel="true"
|
||||
Internalize="true"
|
||||
InputAssemblies="@(InputAssemblies)"
|
||||
LibraryPath="$(OutputPath)"
|
||||
TargetKind="Dll"
|
||||
OutputFile="$(OutputPath)\$(AssemblyName).dll"
|
||||
/>
|
||||
|
||||
</Target>
|
||||
</Project>
|
|
@ -1,10 +1,14 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Plugin;
|
||||
using JKang.IpcServiceFramework.Client;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NoSoliciting.Interface;
|
||||
using Resourcer;
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
@ -22,37 +26,25 @@ namespace NoSoliciting.Ml {
|
|||
#endif
|
||||
|
||||
public uint Version { get; }
|
||||
private IClassifier Classifier { get; }
|
||||
|
||||
private MlFilter(uint version, IClassifier classifier) {
|
||||
this.Version = version;
|
||||
private Process Process { get; }
|
||||
private IIpcClient<IClassifier> Classifier { get; }
|
||||
|
||||
private MlFilter(uint version, Process process, IIpcClient<IClassifier> classifier) {
|
||||
this.Process = process;
|
||||
this.Classifier = classifier;
|
||||
this.Version = version;
|
||||
}
|
||||
|
||||
// private MLContext Context { get; }
|
||||
// private ITransformer Model { get; }
|
||||
// private DataViewSchema Schema { get; }
|
||||
// private PredictionEngine<MessageData, MessagePrediction> PredictionEngine { get; }
|
||||
//
|
||||
// private MlFilter(uint version, MLContext context, ITransformer model, DataViewSchema schema) {
|
||||
// this.Version = version;
|
||||
// this.Context = context;
|
||||
// this.Model = model;
|
||||
// this.Schema = schema;
|
||||
// this.PredictionEngine = this.Context.Model.CreatePredictionEngine<MessageData, MessagePrediction>(this.Model, this.Schema);
|
||||
// }
|
||||
|
||||
public MessageCategory ClassifyMessage(ushort channel, string message) {
|
||||
// var data = new MessageData(channel, message);
|
||||
// var pred = this.PredictionEngine.Predict(data);
|
||||
var rawCategory = this.Classifier.Classify(channel, message);
|
||||
var category = MessageCategoryExt.FromString(rawCategory);
|
||||
var prediction = this.Classifier.InvokeAsync(classifier => classifier.Classify(channel, message)).Result;
|
||||
var category = MessageCategoryExt.FromString(prediction);
|
||||
|
||||
if (category != null) {
|
||||
return (MessageCategory) category;
|
||||
}
|
||||
|
||||
PluginLog.LogWarning($"Unknown message category: {rawCategory}");
|
||||
PluginLog.LogWarning($"Unknown message category: {prediction}");
|
||||
return MessageCategory.Normal;
|
||||
}
|
||||
|
||||
|
@ -82,18 +74,33 @@ namespace NoSoliciting.Ml {
|
|||
UpdateCachedFile(plugin, ModelName, data);
|
||||
UpdateCachedFile(plugin, ManifestName, Encoding.UTF8.GetBytes(manifest.Item2));
|
||||
|
||||
// var context = new MLContext();
|
||||
// using var stream = new MemoryStream(data);
|
||||
// var model = context.Model.Load(stream, out var schema);
|
||||
using var exe = Resource.AsStream("NoSoliciting.NoSoliciting.MessageClassifier.exe");
|
||||
var pluginFolder = Util.PluginFolder(plugin);
|
||||
Directory.CreateDirectory(pluginFolder);
|
||||
var exePath = Path.Combine(pluginFolder, "NoSoliciting.MessageClassifier.exe");
|
||||
using (var exeFile = File.Create(exePath)) {
|
||||
await exe.CopyToAsync(exeFile);
|
||||
}
|
||||
|
||||
// return new MlFilter(manifest.Item1.Version, context, model, schema);
|
||||
var startInfo = new ProcessStartInfo(exePath) {
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
};
|
||||
var process = Process.Start(startInfo);
|
||||
|
||||
plugin.Classifier.Initialise(data);
|
||||
var serviceProvider = new ServiceCollection()
|
||||
.AddNamedPipeIpcClient<IClassifier>("client", (_, options) => {
|
||||
options.PipeName = "NoSoliciting.MessageClassifier";
|
||||
options.Serializer = new BetterIpcSerialiser();
|
||||
})
|
||||
.BuildServiceProvider();
|
||||
|
||||
return new MlFilter(
|
||||
manifest.Item1.Version,
|
||||
plugin.Classifier
|
||||
);
|
||||
var clientFactory = serviceProvider.GetRequiredService<IIpcClientFactory<IClassifier>>();
|
||||
var client = clientFactory.CreateClient("client");
|
||||
|
||||
await client.InvokeAsync(classifier => classifier.Initialise(data));
|
||||
|
||||
return new MlFilter(manifest.Item1.Version, process!, client);
|
||||
}
|
||||
|
||||
private static async Task<byte[]?> DownloadModel(Uri url) {
|
||||
|
@ -167,7 +174,8 @@ namespace NoSoliciting.Ml {
|
|||
}
|
||||
|
||||
public void Dispose() {
|
||||
// this.PredictionEngine.Dispose();
|
||||
this.Process.Kill();
|
||||
this.Process.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.ML.Data;
|
||||
|
||||
namespace NoSoliciting.Ml {
|
||||
public enum MessageCategory {
|
||||
|
|
|
@ -36,7 +36,15 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DalamudPackager" Version="1.2.0" />
|
||||
<PackageReference Include="YamlDotNet" Version="9.1.1" />
|
||||
<PackageReference Include="Fody" Version="6.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ILRepack.Lib.MSBuild.Task" Version="2.0.18.2" />
|
||||
<PackageReference Include="JKang.IpcServiceFramework.Client.NamedPipe" Version="3.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.0" />
|
||||
<PackageReference Include="Resourcer.Fody" Version="1.8.0" PrivateAssets="all" />
|
||||
<PackageReference Include="YamlDotNet" Version="9.1.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
|
@ -50,8 +58,9 @@
|
|||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="..\NoSoliciting.MessageClassifier\bin\Release\net48\NoSoliciting.MessageClassifier.exe" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NoSoliciting.CursedWorkaround\NoSoliciting.CursedWorkaround.csproj" />
|
||||
<ProjectReference Include="..\NoSoliciting.Interface\NoSoliciting.Interface.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -41,15 +41,6 @@ namespace NoSoliciting {
|
|||
public IClassifier Classifier { get; private set; } = null!;
|
||||
|
||||
public void Initialize(DalamudPluginInterface pluginInterface) {
|
||||
// FIXME: eventually this cursed workaround for old System.Numerics.Vectors should be destroyed
|
||||
this.InnerDomain = AppDomain.CreateDomain(LibraryName, AppDomain.CurrentDomain.Evidence, new AppDomainSetup {
|
||||
ApplicationName = LibraryName,
|
||||
ConfigurationFile = $"{LibraryName}.dll.config",
|
||||
ApplicationBase = Path.GetDirectoryName(this.AssemblyLocation),
|
||||
});
|
||||
this.InnerDomain.InitializeLifetimeService();
|
||||
this.Classifier = (IClassifier) this.InnerDomain.CreateInstanceAndUnwrap(LibraryName, $"{LibraryName}.CursedWorkaround");
|
||||
|
||||
string path = Environment.GetEnvironmentVariable("PATH")!;
|
||||
string newPath = Path.GetDirectoryName(this.AssemblyLocation)!;
|
||||
Environment.SetEnvironmentVariable("PATH", $"{path};{newPath}");
|
||||
|
@ -141,9 +132,6 @@ namespace NoSoliciting {
|
|||
this.Interface.UiBuilder.OnBuildUi -= this.Ui.Draw;
|
||||
this.Interface.UiBuilder.OnOpenConfigUi -= this.Ui.OpenSettings;
|
||||
this.Interface.CommandManager.RemoveHandler("/prmt");
|
||||
|
||||
// AppDomain.CurrentDomain.AssemblyResolve -= this.ResolveAssembly;
|
||||
AppDomain.Unload(this.InnerDomain);
|
||||
}
|
||||
|
||||
this._disposedValue = true;
|
||||
|
|
Loading…
Reference in New Issue