feat: make reporting better

This commit is contained in:
Anna 2021-05-15 18:19:27 -04:00
parent 02f020c399
commit 5a1990d30c
Signed by: anna
GPG Key ID: 0B391D8F06FCD9E0
17 changed files with 300 additions and 131 deletions

View File

@ -39,6 +39,6 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="DalamudPackager" Version="1.2.1" /> <PackageReference Include="DalamudPackager" Version="1.2.1" />
<PackageReference Include="Fody" Version="6.5.1" PrivateAssets="all" /> <PackageReference Include="Fody" Version="6.5.1" PrivateAssets="all" />
<PackageReference Include="ResourcesMerge.Fody" Version="1.0.1" PrivateAssets="all" /> <PackageReference Include="ResourcesMerge.Fody" Version="1.0.3" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -9,7 +9,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="ConsoleTables" Version="2.4.2"/> <PackageReference Include="ConsoleTables" Version="2.4.2"/>
<PackageReference Include="CsvHelper" Version="27.0.1"/> <PackageReference Include="CsvHelper" Version="27.0.2"/>
<PackageReference Include="Microsoft.ML" Version="1.5.5"/> <PackageReference Include="Microsoft.ML" Version="1.5.5"/>
</ItemGroup> </ItemGroup>

View File

@ -50,21 +50,7 @@ namespace NoSoliciting {
return; return;
} }
Task.Run(async () => { this.Plugin.Ui.Report.ToShowModal = message;
var status = await this.Plugin.Ui.Report.ReportMessageAsync(message);
switch (status) {
case ReportStatus.Successful: {
var msg = Language.ReportToastSuccess;
this.Plugin.Interface.Framework.Gui.Toast.ShowNormal(string.Format(msg, listing.Name));
break;
}
case ReportStatus.Failure: {
var msg = Language.ReportToastFailure;
this.Plugin.Interface.Framework.Gui.Toast.ShowError(string.Format(msg, listing.Name));
break;
}
}
});
} }
} }
} }

View File

@ -84,23 +84,20 @@ namespace NoSoliciting {
this.LastBatch = args.BatchNumber; this.LastBatch = args.BatchNumber;
var version = this.Plugin.MlFilter?.Version; var version = this.Plugin.MlFilter?.Version;
var reason = this.MlListingFilterReason(listing); var (category, reason) = this.MlListingFilterReason(listing);
if (version == null) {
return;
}
this.Plugin.AddPartyFinderHistory(new Message( this.Plugin.AddPartyFinderHistory(new Message(
version.Value, version,
ChatType.None, ChatType.None,
listing.ContentIdLower, listing.ContentIdLower,
listing.Name, listing.Name,
listing.Description, listing.Description,
true, category,
reason reason == "custom",
reason == "ilvl"
)); ));
if (reason == null) { if (category == null && reason == null) {
return; return;
} }
@ -123,10 +120,6 @@ namespace NoSoliciting {
} }
private bool MlFilterMessage(XivChatType type, uint senderId, SeString sender, SeString message) { private bool MlFilterMessage(XivChatType type, uint senderId, SeString sender, SeString message) {
if (this.Plugin.MlFilter == null) {
return false;
}
var chatType = ChatTypeExt.FromDalamud(type); var chatType = ChatTypeExt.FromDalamud(type);
// NOTE: don't filter on user-controlled chat types here because custom filters are supposed to check all // NOTE: don't filter on user-controlled chat types here because custom filters are supposed to check all
@ -137,80 +130,81 @@ namespace NoSoliciting {
var text = message.TextValue; var text = message.TextValue;
string? reason = null; var custom = false;
MessageCategory? classification = null;
// step 1. check for custom filters if enabled // step 1. check for custom filters if enabled
var filter = this.Plugin.Config.CustomChatFilter var filter = false;
&& Chat.MatchesCustomFilters(text, this.Plugin.Config) if (this.Plugin.Config.CustomChatFilter && Chat.MatchesCustomFilters(text, this.Plugin.Config)) {
&& SetReason(out reason, "custom"); filter = true;
custom = true;
}
// only look at ml if message >= min words // only look at ml if message >= min words
if (!filter && text.Trim().Split(' ').Length >= MinWords) { if (!filter && this.Plugin.MlFilter != null && text.Trim().Split(' ').Length >= MinWords) {
// step 2. classify the message using the model // step 2. classify the message using the model
var category = this.Plugin.MlFilter.ClassifyMessage((ushort) chatType, text); var category = this.Plugin.MlFilter.ClassifyMessage((ushort) chatType, text);
// step 2a. only filter if configured to act on this channel // step 2a. only filter if configured to act on this channel
filter = category != MessageCategory.Normal if (category != MessageCategory.Normal && this.Plugin.Config.MlEnabledOn(category, chatType)) {
&& this.Plugin.Config.MlEnabledOn(category, chatType) filter = true;
&& SetReason(out reason, category.Name()); classification = category;
}
} }
this.Plugin.AddMessageHistory(new Message( var history = new Message(
this.Plugin.MlFilter.Version, this.Plugin.MlFilter?.Version,
ChatTypeExt.FromDalamud(type), ChatTypeExt.FromDalamud(type),
senderId, senderId,
sender, sender,
message, message,
true, classification,
reason custom,
)); false
);
this.Plugin.AddMessageHistory(history);
if (filter && this.Plugin.Config.LogFilteredChat) { if (filter && this.Plugin.Config.LogFilteredChat) {
PluginLog.Log($"Filtered chat message ({reason}): {text}"); PluginLog.Log($"Filtered chat message ({history.FilterReason ?? "unknown"}): {text}");
} }
return filter; return filter;
} }
private string? MlListingFilterReason(PartyFinderListing listing) { private (MessageCategory?, string?) MlListingFilterReason(PartyFinderListing listing) {
if (this.Plugin.MlFilter == null) { if (this.Plugin.MlFilter == null) {
return null; return (null, null);
} }
// ignore private listings if configured // ignore private listings if configured
if (!this.Plugin.Config.ConsiderPrivatePfs && listing[SearchAreaFlags.Private]) { if (!this.Plugin.Config.ConsiderPrivatePfs && listing[SearchAreaFlags.Private]) {
return null; return (null, null);
} }
var desc = listing.Description.TextValue; var desc = listing.Description.TextValue;
// step 1. check if pf has an item level that's too high // step 1. check if pf has an item level that's too high
if (this.Plugin.Config.FilterHugeItemLevelPFs && listing.MinimumItemLevel > FilterUtil.MaxItemLevelAttainable(this.Plugin.Interface.Data)) { if (this.Plugin.Config.FilterHugeItemLevelPFs && listing.MinimumItemLevel > FilterUtil.MaxItemLevelAttainable(this.Plugin.Interface.Data)) {
return "ilvl"; return (null, "ilvl");
} }
// step 2. check custom filters // step 2. check custom filters
if (this.Plugin.Config.CustomPFFilter && PartyFinder.MatchesCustomFilters(desc, this.Plugin.Config)) { if (this.Plugin.Config.CustomPFFilter && PartyFinder.MatchesCustomFilters(desc, this.Plugin.Config)) {
return "custom"; return (null, "custom");
} }
// only look at ml for pfs >= min words // only look at ml for pfs >= min words
if (desc.Trim().Spacify().Split(' ').Length < MinWords) { if (desc.Trim().Spacify().Split(' ').Length < MinWords) {
return null; return (null, null);
} }
var category = this.Plugin.MlFilter.ClassifyMessage((ushort) ChatType.None, desc); var category = this.Plugin.MlFilter.ClassifyMessage((ushort) ChatType.None, desc);
if (category != MessageCategory.Normal && this.Plugin.Config.MlEnabledOn(category, ChatType.None)) { if (category != MessageCategory.Normal && this.Plugin.Config.MlEnabledOn(category, ChatType.None)) {
return category.Name(); return (category, null);
} }
return null; return (null, null);
}
private static bool SetReason(out string reason, string value) {
reason = value;
return true;
} }
} }
} }

View File

@ -3,12 +3,12 @@ using System.Globalization;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Numerics; using System.Numerics;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Game.Text.SeStringHandling.Payloads;
using Dalamud.Plugin; using Dalamud.Plugin;
using ImGuiNET; using ImGuiNET;
using NoSoliciting.Ml;
using NoSoliciting.Resources; using NoSoliciting.Resources;
namespace NoSoliciting.Interface { namespace NoSoliciting.Interface {
@ -34,6 +34,8 @@ namespace NoSoliciting.Interface {
set => this._showReporting = value; set => this._showReporting = value;
} }
internal Message? ToShowModal { get; set; }
public Report(Plugin plugin) { public Report(Plugin plugin) {
this.Plugin = plugin; this.Plugin = plugin;
} }
@ -47,6 +49,13 @@ namespace NoSoliciting.Interface {
} }
public void Draw() { public void Draw() {
var toShow = this.ToShowModal;
if (toShow != null) {
if (!this.SetUpReportModal(toShow)) {
ImGui.OpenPopup($"###modal-message-{toShow.Id}");
}
}
if (!this.ShowReporting) { if (!this.ShowReporting) {
return; return;
} }
@ -102,7 +111,7 @@ namespace NoSoliciting.Interface {
foreach (var message in this.Plugin.MessageHistory) { foreach (var message in this.Plugin.MessageHistory) {
ImGui.TableNextRow(); ImGui.TableNextRow();
if (message.FilterReason != null) { if (message.Filtered) {
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(238f / 255f, 71f / 255f, 71f / 255f, 1f)); ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(238f / 255f, 71f / 255f, 71f / 255f, 1f));
} }
@ -112,11 +121,11 @@ namespace NoSoliciting.Interface {
.Select(payload => payload.Text) .Select(payload => payload.Text)
.FirstOrDefault() ?? ""; .FirstOrDefault() ?? "";
if (AddRow(message.Timestamp.ToString(CultureInfo.CurrentCulture), message.ChatType.Name(this.Plugin.Interface.Data), message.FilterReason ?? "", sender, message.Content.TextValue)) { if (AddRow(message.Timestamp.ToString(CultureInfo.CurrentCulture), message.ChatType.Name(this.Plugin.Interface.Data), message.FilterReason ?? string.Empty, sender, message.Content.TextValue)) {
ImGui.OpenPopup($"###modal-message-{message.Id}"); ImGui.OpenPopup($"###modal-message-{message.Id}");
} }
if (message.FilterReason != null) { if (message.Filtered) {
ImGui.PopStyleColor(); ImGui.PopStyleColor();
} }
@ -142,7 +151,7 @@ namespace NoSoliciting.Interface {
var builder = new StringBuilder(); var builder = new StringBuilder();
foreach (var message in this.Plugin.PartyFinderHistory) { foreach (var message in this.Plugin.PartyFinderHistory) {
if (message.FilterReason == null) { if (message.Classification == null) {
continue; continue;
} }
@ -165,7 +174,7 @@ namespace NoSoliciting.Interface {
foreach (var message in this.Plugin.PartyFinderHistory) { foreach (var message in this.Plugin.PartyFinderHistory) {
ImGui.TableNextRow(); ImGui.TableNextRow();
if (message.FilterReason != null) { if (message.Filtered) {
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(238f / 255f, 71f / 255f, 71f / 255f, 1f)); ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(238f / 255f, 71f / 255f, 71f / 255f, 1f));
} }
@ -175,11 +184,11 @@ namespace NoSoliciting.Interface {
.Select(payload => payload.Text) .Select(payload => payload.Text)
.FirstOrDefault() ?? ""; .FirstOrDefault() ?? "";
if (AddRow(message.Timestamp.ToString(CultureInfo.CurrentCulture), message.FilterReason ?? "", sender, message.Content.TextValue)) { if (AddRow(message.Timestamp.ToString(CultureInfo.CurrentCulture), message.FilterReason ?? string.Empty, sender, message.Content.TextValue)) {
ImGui.OpenPopup($"###modal-message-{message.Id}"); ImGui.OpenPopup($"###modal-message-{message.Id}");
} }
if (message.FilterReason != null) { if (message.Filtered) {
ImGui.PopStyleColor(); ImGui.PopStyleColor();
} }
@ -197,50 +206,129 @@ namespace NoSoliciting.Interface {
#region Modal #region Modal
private void SetUpReportModal(Message message) { private MessageCategory? _reportCategory;
/// <summary>
///
/// </summary>
/// <param name="message"></param>
/// <returns>true if modal is closing</returns>
private bool SetUpReportModal(Message message) {
var closing = false;
ImGui.SetNextWindowSize(new Vector2(350, -1)); ImGui.SetNextWindowSize(new Vector2(350, -1));
var modalTitle = string.Format(Language.ReportModalTitle, this.Plugin.Name); var modalTitle = string.Format(Language.ReportModalTitle, this.Plugin.Name);
if (!ImGui.BeginPopupModal($"{modalTitle}###modal-message-{message.Id}")) { if (!ImGui.BeginPopupModal($"{modalTitle}###modal-message-{message.Id}")) {
return; return false;
}
if (this._reportCategory == null) {
if (message.Classification != null) {
this._reportCategory = message.Classification;
} else if (message.Classification == null && !message.Custom && !message.ItemLevel) {
this._reportCategory = MessageCategory.Normal;
}
} }
ImGui.PushTextWrapPos(); ImGui.PushTextWrapPos();
ImGui.TextUnformatted(Language.ReportModalHelp1); ImGui.TextUnformatted(Language.ReportModalHelp1);
ImGui.TextUnformatted(message.FilterReason != null
? Language.ReportModalWasFiltered
: Language.ReportModalWasNotFiltered);
ImGui.Separator(); ImGui.Separator();
ImGui.TextUnformatted(message.Content.TextValue); ImGui.TextUnformatted(message.Content.TextValue);
ImGui.Separator(); ImGui.Separator();
ImGui.TextUnformatted(string.Format(Language.ReportModalOriginalClassification, message.FilterReason ?? MessageCategory.Normal.Name()));
ImGui.TextUnformatted(Language.ReportModalSuggestedClassification);
ImGui.SetNextItemWidth(-1);
if (ImGui.BeginCombo($"##modal-classification-{message.Id}", this._reportCategory?.Name() ?? string.Empty)) {
foreach (var category in (MessageCategory[]) Enum.GetValues(typeof(MessageCategory))) {
if (ImGui.Selectable($"{category.Name()}##modal-option-{message.Id}", this._reportCategory == category)) {
this._reportCategory = category;
}
if (!ImGui.IsItemHovered()) {
continue;
}
ImGui.BeginTooltip();
ImGui.PushTextWrapPos(ImGui.GetFontSize() * 24);
ImGui.TextUnformatted(category.Description());
ImGui.PopTextWrapPos();
ImGui.EndTooltip();
}
ImGui.EndCombo();
}
ImGui.Separator();
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1f, 0f, 0f, 1f)); ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1f, 0f, 0f, 1f));
ImGui.TextUnformatted(Language.ReportModalHelp2); ImGui.TextUnformatted(Language.ReportModalHelp2);
ImGui.PopStyleColor(); ImGui.PopStyleColor();
ImGui.Separator(); ImGui.Separator();
if (message.FilterReason == "custom") { string? errorText = null;
if (message.Custom) {
errorText = Language.ReportModalDisabledCustom;
} else if (message.ItemLevel) {
errorText = Language.ReportModalDisabledItemLevel;
} else if (message.ModelVersion == null) {
errorText = Language.ReportModalDisabledBadModel;
} else if (this._reportCategory == message.Classification) {
errorText = Language.ReportModalDisabledSameClassification;
} else {
switch (this.Plugin.Config.AdvancedMode) {
case true when this.Plugin.Config.MlFilters.Values.All(set => set.Count == 0):
case false when this.Plugin.Config.BasicMlFilters.Count == 0:
errorText = Language.ReportModalDisabledNoFilters;
break;
}
}
if (errorText != null) {
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1f, 0f, 0f, 1f)); ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(1f, 0f, 0f, 1f));
ImGui.TextUnformatted(Language.ReportModalCustom); ImGui.TextUnformatted(errorText);
ImGui.PopStyleColor(); ImGui.PopStyleColor();
} else { } else {
var buttonTitle =Language.ReportModalReport; if (ImGui.Button($"{Language.ReportModalReport}##report-submit-{message.Id}")) {
if (ImGui.Button($"{buttonTitle}##report-submit-{message.Id}")) { var suggested = this._reportCategory?.ToModelName() ?? "none (this is a bug)";
this.ReportMessage(message); this._reportCategory = null;
if (message == this.ToShowModal) {
Task.Run(async () => {
var status = await this.Plugin.Ui.Report.ReportMessageAsync(message, suggested);
switch (status) {
case ReportStatus.Successful: {
var msg = Language.ReportToastSuccess;
this.Plugin.Interface.Framework.Gui.Toast.ShowNormal(string.Format(msg, message.Sender));
break;
}
case ReportStatus.Failure: {
var msg = Language.ReportToastFailure;
this.Plugin.Interface.Framework.Gui.Toast.ShowError(string.Format(msg, message.Sender));
break;
}
}
});
this.ToShowModal = null;
} else {
this.ReportMessage(message, suggested);
}
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
closing = true;
} }
ImGui.SameLine(); ImGui.SameLine();
} }
var copyButton = Language.ReportModalCopy; if (ImGui.Button($"{Language.ReportModalCopy}##report-copy-{message.Id}")) {
if (ImGui.Button($"{copyButton}##report-copy-{message.Id}")) {
ImGui.SetClipboardText(message.Content.TextValue); ImGui.SetClipboardText(message.Content.TextValue);
} }
@ -255,12 +343,20 @@ namespace NoSoliciting.Interface {
var cancelButton = Language.ReportModalCancel; var cancelButton = Language.ReportModalCancel;
if (ImGui.Button($"{cancelButton}##report-cancel-{message.Id}")) { if (ImGui.Button($"{cancelButton}##report-cancel-{message.Id}")) {
this._reportCategory = null;
if (message == this.ToShowModal) {
this.ToShowModal = null;
}
ImGui.CloseCurrentPopup(); ImGui.CloseCurrentPopup();
closing = true;
} }
ImGui.PopTextWrapPos(); ImGui.PopTextWrapPos();
ImGui.EndPopup(); ImGui.EndPopup();
return closing;
} }
#endregion #endregion
@ -292,18 +388,21 @@ namespace NoSoliciting.Interface {
return clicked; return clicked;
} }
internal void ReportMessage(Message message) { private void ReportMessage(Message message, string suggested) {
Task.Run(async () => await this.ReportMessageAsync(message)); Task.Run(async () => await this.ReportMessageAsync(message, suggested));
} }
internal async Task<ReportStatus> ReportMessageAsync(Message message) { private async Task<ReportStatus> ReportMessageAsync(Message message, string suggested) {
string? resp = null; string? resp = null;
try { try {
using var client = new WebClient(); using var client = new WebClient();
this.LastReportStatus = ReportStatus.InProgress; this.LastReportStatus = ReportStatus.InProgress;
var reportUrl = this.Plugin.MlFilter?.ReportUrl; var reportUrl = this.Plugin.MlFilter?.ReportUrl;
if (reportUrl != null) { if (reportUrl != null) {
resp = await client.UploadStringTaskAsync(reportUrl, message.ToJson()).ConfigureAwait(true); var json = message.ToJson(suggested);
if (json != null) {
resp = await client.UploadStringTaskAsync(reportUrl, json).ConfigureAwait(true);
}
} }
} catch (Exception) { } catch (Exception) {
// ignored // ignored

View File

@ -6,66 +6,87 @@ using System.Linq;
using Dalamud.Data; using Dalamud.Data;
using Dalamud.Game.Text; using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Game.Text.SeStringHandling.Payloads;
using Lumina.Excel.GeneratedSheets; using Lumina.Excel.GeneratedSheets;
using NoSoliciting.Ml;
#if DEBUG #if DEBUG
using System.Text; using System.Text;
using NoSoliciting.Ml;
#endif #endif
namespace NoSoliciting { namespace NoSoliciting {
[Serializable] [Serializable]
public class Message { public class Message {
public Guid Id { get; } public Guid Id { get; }
[JsonIgnore] [JsonIgnore]
public uint ActorId { get; } public uint ActorId { get; }
public uint DefinitionsVersion { get; }
public uint? ModelVersion { get; }
public DateTime Timestamp { get; } public DateTime Timestamp { get; }
public ChatType ChatType { get; } public ChatType ChatType { get; }
public SeString Sender { get; } public SeString Sender { get; }
public SeString Content { get; } public SeString Content { get; }
public bool Ml { get; }
public string? FilterReason { get; }
public Message(uint defsVersion, ChatType type, uint actorId, SeString sender, SeString content, bool ml, string? reason) { public MessageCategory? Classification { get; }
public bool Custom { get; }
public bool ItemLevel { get; }
public bool Filtered => this.Custom || this.ItemLevel || this.Classification != null;
public string? FilterReason => this.Custom
? "custom"
: this.ItemLevel
? "ilvl"
: this.Classification?.Name();
internal Message(uint? defsVersion, ChatType type, uint actorId, SeString sender, SeString content, MessageCategory? classification, bool custom, bool ilvl) {
this.Id = Guid.NewGuid(); this.Id = Guid.NewGuid();
this.DefinitionsVersion = defsVersion; this.ModelVersion = defsVersion;
this.Timestamp = DateTime.Now; this.Timestamp = DateTime.Now;
this.ChatType = type; this.ChatType = type;
this.ActorId = actorId; this.ActorId = actorId;
this.Sender = sender; this.Sender = sender;
this.Content = content; this.Content = content;
this.Ml = ml; this.Classification = classification;
this.FilterReason = reason; this.Custom = custom;
this.ItemLevel = ilvl;
} }
[Serializable] [Serializable]
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))] [JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
private class JsonMessage { private class JsonMessage {
public Guid Id { get; set; } public uint ReportVersion { get; } = 2;
public uint DefinitionsVersion { get; set; } public uint ModelVersion { get; set; }
public DateTime Timestamp { get; set; } public DateTime Timestamp { get; set; }
public ushort Type { get; set; } public ushort Type { get; set; }
// note: cannot use byte[] because Newtonsoft thinks it's a good idea to always base64 byte[] // note: cannot use byte[] because Newtonsoft thinks it's a good idea to always base64 byte[]
// and I don't want to write a custom converter to overwrite their stupiditiy // and I don't want to write a custom converter to overwrite their stupidity
public List<byte> Sender { get; set; } public List<byte> Sender { get; set; }
public List<byte> Content { get; set; } public List<byte> Content { get; set; }
public bool Ml { get; set; }
public string? Reason { get; set; } public string? Reason { get; set; }
public string? SuggestedClassification { get; set; }
} }
public string ToJson() { public string? ToJson(string suggested) {
if (this.ModelVersion == null) {
return null;
}
var msg = new JsonMessage { var msg = new JsonMessage {
Id = this.Id, ModelVersion = this.ModelVersion.Value,
DefinitionsVersion = this.DefinitionsVersion,
Timestamp = this.Timestamp, Timestamp = this.Timestamp,
Type = (ushort) this.ChatType, Type = (ushort) this.ChatType,
Sender = this.Sender.Encode().ToList(), Sender = this.Sender.Encode().ToList(),
Content = this.Content.Encode().ToList(), Content = this.Content.Encode().ToList(),
Ml = this.Ml, Reason = this.Custom
Reason = this.FilterReason, ? "custom"
: this.ItemLevel
? "ilvl"
: this.Classification?.ToModelName() ?? "unknown",
SuggestedClassification = suggested,
}; };
return JsonConvert.SerializeObject(msg, new JsonSerializerSettings { return JsonConvert.SerializeObject(msg, new JsonSerializerSettings {
@ -77,9 +98,7 @@ namespace NoSoliciting {
public StringBuilder ToCsv(StringBuilder? builder = null) { public StringBuilder ToCsv(StringBuilder? builder = null) {
builder ??= new StringBuilder(); builder ??= new StringBuilder();
var category = MessageCategoryExt.FromName(this.FilterReason) ?? MessageCategory.Normal; builder.Append(this.Classification?.ToModelName());
builder.Append(category.ToModelName());
builder.Append(','); builder.Append(',');
builder.Append((int) this.ChatType); builder.Append((int) this.ChatType);
builder.Append(",\""); builder.Append(",\"");

View File

@ -43,20 +43,6 @@ namespace NoSoliciting.Ml {
}; };
#if DEBUG #if DEBUG
public static string ToModelName(this MessageCategory category) => category switch {
MessageCategory.Trade => "TRADE",
MessageCategory.FreeCompany => "FC",
MessageCategory.Normal => "NORMAL",
MessageCategory.Phishing => "PHISH",
MessageCategory.RmtContent => "RMT_C",
MessageCategory.RmtGil => "RMT_G",
MessageCategory.Roleplaying => "RP",
MessageCategory.Static => "STATIC",
MessageCategory.Community => "COMMUNITY",
MessageCategory.StaticSub => "STATIC_SUB",
_ => throw new ArgumentException("Invalid category", nameof(category)),
};
public static MessageCategory? FromName(string? category) => category switch { public static MessageCategory? FromName(string? category) => category switch {
"Trade ads" => MessageCategory.Trade, "Trade ads" => MessageCategory.Trade,
"Free Company ads" => MessageCategory.FreeCompany, "Free Company ads" => MessageCategory.FreeCompany,
@ -70,9 +56,22 @@ namespace NoSoliciting.Ml {
"Static substitutes" => MessageCategory.StaticSub, "Static substitutes" => MessageCategory.StaticSub,
_ => null, _ => null,
}; };
#endif #endif
public static string ToModelName(this MessageCategory category) => category switch {
MessageCategory.Trade => "TRADE",
MessageCategory.FreeCompany => "FC",
MessageCategory.Normal => "NORMAL",
MessageCategory.Phishing => "PHISH",
MessageCategory.RmtContent => "RMT_C",
MessageCategory.RmtGil => "RMT_G",
MessageCategory.Roleplaying => "RP",
MessageCategory.Static => "STATIC",
MessageCategory.Community => "COMMUNITY",
MessageCategory.StaticSub => "STATIC_SUB",
_ => throw new ArgumentException("Invalid category", nameof(category)),
};
public static string Name(this MessageCategory category) => category switch { public static string Name(this MessageCategory category) => category switch {
MessageCategory.Trade => Language.TradeCategory, MessageCategory.Trade => Language.TradeCategory,
MessageCategory.FreeCompany => Language.FreeCompanyCategory, MessageCategory.FreeCompany => Language.FreeCompanyCategory,

View File

@ -41,7 +41,7 @@
<PackageReference Include="JKang.IpcServiceFramework.Client.NamedPipe" Version="3.1.0"/> <PackageReference Include="JKang.IpcServiceFramework.Client.NamedPipe" Version="3.1.0"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1"/> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1"/>
<PackageReference Include="Resourcer.Fody" Version="1.8.0" PrivateAssets="all"/> <PackageReference Include="Resourcer.Fody" Version="1.8.0" PrivateAssets="all"/>
<PackageReference Include="ResourcesMerge.Fody" Version="1.0.1" PrivateAssets="all"/> <PackageReference Include="ResourcesMerge.Fody" Version="1.0.3" PrivateAssets="all"/>
<PackageReference Include="XivCommon" Version="1.5.0"/> <PackageReference Include="XivCommon" Version="1.5.0"/>
<PackageReference Include="YamlDotNet" Version="11.1.1"/> <PackageReference Include="YamlDotNet" Version="11.1.1"/>
</ItemGroup> </ItemGroup>

View File

@ -474,12 +474,48 @@ namespace NoSoliciting.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Reporting is disabled because your ML model was not functioning when you saw this message..
/// </summary>
internal static string ReportModalDisabledBadModel {
get {
return ResourceManager.GetString("ReportModalDisabledBadModel", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to You cannot report messages filtered because of a custom filter.. /// Looks up a localized string similar to You cannot report messages filtered because of a custom filter..
/// </summary> /// </summary>
internal static string ReportModalCustom { internal static string ReportModalDisabledCustom {
get { get {
return ResourceManager.GetString("ReportModalCustom", resourceCulture); return ResourceManager.GetString("ReportModalDisabledCustom", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to You cannot report messages filtered because of item level..
/// </summary>
internal static string ReportModalDisabledItemLevel {
get {
return ResourceManager.GetString("ReportModalDisabledItemLevel", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reporting is disabled because you do not have any filters enabled..
/// </summary>
internal static string ReportModalDisabledNoFilters {
get {
return ResourceManager.GetString("ReportModalDisabledNoFilters", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reporting is disabled because you must choose a different classification than the original..
/// </summary>
internal static string ReportModalDisabledSameClassification {
get {
return ResourceManager.GetString("ReportModalDisabledSameClassification", resourceCulture);
} }
} }
@ -501,6 +537,15 @@ namespace NoSoliciting.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to This message&apos;s original classification: {0}.
/// </summary>
internal static string ReportModalOriginalClassification {
get {
return ResourceManager.GetString("ReportModalOriginalClassification", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Report. /// Looks up a localized string similar to Report.
/// </summary> /// </summary>
@ -510,6 +555,15 @@ namespace NoSoliciting.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to How do you think this message should have been classified?.
/// </summary>
internal static string ReportModalSuggestedClassification {
get {
return ResourceManager.GetString("ReportModalSuggestedClassification", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Report to {0}. /// Looks up a localized string similar to Report to {0}.
/// </summary> /// </summary>

View File

@ -132,7 +132,7 @@
<data name="ReportModalReport" xml:space="preserve"> <data name="ReportModalReport" xml:space="preserve">
<value>Melden</value> <value>Melden</value>
</data> </data>
<data name="ReportModalCustom" xml:space="preserve"> <data name="ReportModalDisabledCustom" xml:space="preserve">
<value>Du kannst Nachrichten, die aufgrund von benutzerdefinierten Filtern gefiltert wurden, nicht melden.</value> <value>Du kannst Nachrichten, die aufgrund von benutzerdefinierten Filtern gefiltert wurden, nicht melden.</value>
</data> </data>
<data name="PhishingCategory" xml:space="preserve"> <data name="PhishingCategory" xml:space="preserve">

View File

@ -172,7 +172,7 @@
<data name="ReportModalHelp2" xml:space="preserve"> <data name="ReportModalHelp2" xml:space="preserve">
<value>NoSoliciting sólo funciona con mensajes en inglés. No informes de mensajes en otros idiomas.</value> <value>NoSoliciting sólo funciona con mensajes en inglés. No informes de mensajes en otros idiomas.</value>
</data> </data>
<data name="ReportModalCustom" xml:space="preserve"> <data name="ReportModalDisabledCustom" xml:space="preserve">
<value>No puedes informar de mensajes que han sido filtrados debido a un filtro personalizado.</value> <value>No puedes informar de mensajes que han sido filtrados debido a un filtro personalizado.</value>
</data> </data>
<data name="ReportModalReport" xml:space="preserve"> <data name="ReportModalReport" xml:space="preserve">

View File

@ -219,7 +219,7 @@
<data name="ReportModalHelp2" xml:space="preserve"> <data name="ReportModalHelp2" xml:space="preserve">
<value>NoSoliciting n'est fonctionnel que pour les messages en anglais. Veuillez ne pas signaler des messages qui ne sont pas en anglais.</value> <value>NoSoliciting n'est fonctionnel que pour les messages en anglais. Veuillez ne pas signaler des messages qui ne sont pas en anglais.</value>
</data> </data>
<data name="ReportModalCustom" xml:space="preserve"> <data name="ReportModalDisabledCustom" xml:space="preserve">
<value>Vous ne pouvez pas signaler de messages filtrés à cause d'un filtre personnalisé.</value> <value>Vous ne pouvez pas signaler de messages filtrés à cause d'un filtre personnalisé.</value>
</data> </data>
<data name="ReportModalReport" xml:space="preserve"> <data name="ReportModalReport" xml:space="preserve">

View File

@ -172,7 +172,7 @@
<data name="ReportModalHelp2" xml:space="preserve"> <data name="ReportModalHelp2" xml:space="preserve">
<value>NoSolicitingは英語のメッセージにのみ有効です。 他の言語でメッセージを報告しないでください。</value> <value>NoSolicitingは英語のメッセージにのみ有効です。 他の言語でメッセージを報告しないでください。</value>
</data> </data>
<data name="ReportModalCustom" xml:space="preserve"> <data name="ReportModalDisabledCustom" xml:space="preserve">
<value>カスタムフィルタでフィルタリングされたメッセージを報告することはできません。</value> <value>カスタムフィルタでフィルタリングされたメッセージを報告することはできません。</value>
</data> </data>
<data name="ReportModalReport" xml:space="preserve"> <data name="ReportModalReport" xml:space="preserve">

View File

@ -181,7 +181,7 @@
<data name="ReportModalWasNotFiltered" xml:space="preserve"> <data name="ReportModalWasNotFiltered" xml:space="preserve">
<value>De maneira específica, essa mensagem NÃO FOI filtrada, mas deveria ter sido.</value> <value>De maneira específica, essa mensagem NÃO FOI filtrada, mas deveria ter sido.</value>
</data> </data>
<data name="ReportModalCustom" xml:space="preserve"> <data name="ReportModalDisabledCustom" xml:space="preserve">
<value>Voçê não pode relatar as mensagens filtradas por causa de um filtro personalizado.</value> <value>Voçê não pode relatar as mensagens filtradas por causa de um filtro personalizado.</value>
</data> </data>
<data name="ReportModalReport" xml:space="preserve"> <data name="ReportModalReport" xml:space="preserve">

View File

@ -3,7 +3,7 @@
<root> <root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
</xsd:element> </xsd:element>
</xsd:schema> </xsd:schema>
<resheader name="resmimetype"> <resheader name="resmimetype">
@ -153,7 +153,7 @@
<data name="ReportModalHelp2" xml:space="preserve"> <data name="ReportModalHelp2" xml:space="preserve">
<value>NoSoliciting only works for English messages. Do not report non-English messages.</value> <value>NoSoliciting only works for English messages. Do not report non-English messages.</value>
</data> </data>
<data name="ReportModalCustom" xml:space="preserve"> <data name="ReportModalDisabledCustom" xml:space="preserve">
<value>You cannot report messages filtered because of a custom filter.</value> <value>You cannot report messages filtered because of a custom filter.</value>
</data> </data>
<data name="ReportModalReport" xml:space="preserve"> <data name="ReportModalReport" xml:space="preserve">
@ -255,4 +255,22 @@
<data name="ModelStatusInitialised" xml:space="preserve"> <data name="ModelStatusInitialised" xml:space="preserve">
<value>Initialised</value> <value>Initialised</value>
</data> </data>
</root> <data name="ReportModalDisabledBadModel" xml:space="preserve">
<value>Reporting is disabled because your ML model was not functioning when you saw this message.</value>
</data>
<data name="ReportModalDisabledNoFilters" xml:space="preserve">
<value>Reporting is disabled because you do not have any filters enabled.</value>
</data>
<data name="ReportModalDisabledSameClassification" xml:space="preserve">
<value>Reporting is disabled because you must choose a different classification than the original.</value>
</data>
<data name="ReportModalDisabledItemLevel" xml:space="preserve">
<value>You cannot report messages filtered because of item level.</value>
</data>
<data name="ReportModalOriginalClassification" xml:space="preserve">
<value>This message's original classification: {0}</value>
</data>
<data name="ReportModalSuggestedClassification" xml:space="preserve">
<value>How do you think this message should have been classified?</value>
</data>
</root>

View File

@ -175,7 +175,7 @@
<data name="ReportModalWasNotFiltered" xml:space="preserve"> <data name="ReportModalWasNotFiltered" xml:space="preserve">
<value>具体来说,这是一条应该被过滤的消息,但它被放过了。</value> <value>具体来说,这是一条应该被过滤的消息,但它被放过了。</value>
</data> </data>
<data name="ReportModalCustom" xml:space="preserve"> <data name="ReportModalDisabledCustom" xml:space="preserve">
<value>你不能报告被自定义过滤规则过滤的消息。</value> <value>你不能报告被自定义过滤规则过滤的消息。</value>
</data> </data>
<data name="ReportModalReport" xml:space="preserve"> <data name="ReportModalReport" xml:space="preserve">

View File

@ -64,7 +64,7 @@
<data name="ReportModalHelp1" xml:space="preserve"> <data name="ReportModalHelp1" xml:space="preserve">
<value>報告此消息將使開發人員知道此消息被錯誤歸類。</value> <value>報告此消息將使開發人員知道此消息被錯誤歸類。</value>
</data> </data>
<data name="ReportModalCustom" xml:space="preserve"> <data name="ReportModalDisabledCustom" xml:space="preserve">
<value>你不能報告被客製化過濾規則過濾的消息。</value> <value>你不能報告被客製化過濾規則過濾的消息。</value>
</data> </data>
<data name="OtherTab" xml:space="preserve"> <data name="OtherTab" xml:space="preserve">