Tighten structural asset phrase extraction
This commit is contained in:
parent
6aea9736d4
commit
3bf8f88f16
@ -42,6 +42,7 @@ var tests = new (string Name, Action Test)[]
|
|||||||
("Asset canonical keys merge trivial variants", AssetCanonicalKeysMergeTrivialVariants),
|
("Asset canonical keys merge trivial variants", AssetCanonicalKeysMergeTrivialVariants),
|
||||||
("Asset canonical keys merge contextual vehicle variants", AssetCanonicalKeysMergeContextualVehicleVariants),
|
("Asset canonical keys merge contextual vehicle variants", AssetCanonicalKeysMergeContextualVehicleVariants),
|
||||||
("Asset contextual names resolve POV ownership", AssetContextualNamesResolvePovOwnership),
|
("Asset contextual names resolve POV ownership", AssetContextualNamesResolvePovOwnership),
|
||||||
|
("Asset structural phrases trim neighbouring nouns", AssetStructuralPhrasesTrimNeighbouringNouns),
|
||||||
("Relationship signals map to broad lookup types", RelationshipSignalsMapToBroadTypes),
|
("Relationship signals map to broad lookup types", RelationshipSignalsMapToBroadTypes),
|
||||||
("Relationship signals infer friendship without romance", RelationshipSignalsInferFriendshipWithoutRomance),
|
("Relationship signals infer friendship without romance", RelationshipSignalsInferFriendshipWithoutRomance),
|
||||||
("Relationship events preserve chronological story order", RelationshipEventsPreserveChronologicalStoryOrder),
|
("Relationship events preserve chronological story order", RelationshipEventsPreserveChronologicalStoryOrder),
|
||||||
@ -1326,6 +1327,11 @@ static void AssetContextualNamesResolvePovOwnership()
|
|||||||
Assert(IsAssetNameCandidate("Beth's Memory Tin"), "Owned Memory Tin-style significant objects should be retained.");
|
Assert(IsAssetNameCandidate("Beth's Memory Tin"), "Owned Memory Tin-style significant objects should be retained.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void AssetStructuralPhrasesTrimNeighbouringNouns()
|
||||||
|
{
|
||||||
|
Assert(CleanStructuralAssetPhrase("memory tin and photographs") == "memory tin", "Structural asset extraction should not bundle neighbouring nouns after and.");
|
||||||
|
}
|
||||||
|
|
||||||
static void RelationshipSignalsMapToBroadTypes()
|
static void RelationshipSignalsMapToBroadTypes()
|
||||||
{
|
{
|
||||||
Assert(RelationshipTypeFromSignal("Friend") == "Friend", "Friend should map to Friend.");
|
Assert(RelationshipTypeFromSignal("Friend") == "Friend", "Friend should map to Friend.");
|
||||||
@ -1423,6 +1429,15 @@ static string ResolveContextualAssetName(string name, string? ownerOrHolder, Sce
|
|||||||
return (string)method!.Invoke(null, [name, ownerOrHolder, scene])!;
|
return (string)method!.Invoke(null, [name, ownerOrHolder, scene])!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static string CleanStructuralAssetPhrase(string name)
|
||||||
|
{
|
||||||
|
var method = typeof(StoryIntelligenceAssetImportService).GetMethod(
|
||||||
|
"CleanStructuralAssetPhrase",
|
||||||
|
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
|
||||||
|
Assert(method is not null, "CleanStructuralAssetPhrase was not found.");
|
||||||
|
return (string)method!.Invoke(null, [name])!;
|
||||||
|
}
|
||||||
|
|
||||||
static IComparable StoryOrderKey((int SceneID, decimal ChapterNumber, decimal SceneNumber, int SortOrder) shim)
|
static IComparable StoryOrderKey((int SceneID, decimal ChapterNumber, decimal SceneNumber, int SortOrder) shim)
|
||||||
{
|
{
|
||||||
var nested = typeof(StoryIntelligenceRelationshipImportService).GetNestedType(
|
var nested = typeof(StoryIntelligenceRelationshipImportService).GetNestedType(
|
||||||
|
|||||||
@ -462,7 +462,7 @@ public sealed class StoryIntelligenceAssetImportService(
|
|||||||
foreach (Match match in StructuralPossessiveAssetPattern.Matches(source))
|
foreach (Match match in StructuralPossessiveAssetPattern.Matches(source))
|
||||||
{
|
{
|
||||||
var owner = match.Groups["owner"].Value;
|
var owner = match.Groups["owner"].Value;
|
||||||
var objectName = match.Groups["asset"].Value;
|
var objectName = CleanStructuralAssetPhrase(match.Groups["asset"].Value);
|
||||||
if (string.IsNullOrWhiteSpace(owner) || string.IsNullOrWhiteSpace(objectName))
|
if (string.IsNullOrWhiteSpace(owner) || string.IsNullOrWhiteSpace(objectName))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -482,7 +482,7 @@ public sealed class StoryIntelligenceAssetImportService(
|
|||||||
|
|
||||||
foreach (Match match in StructuralSignificantAssetPattern.Matches(source))
|
foreach (Match match in StructuralSignificantAssetPattern.Matches(source))
|
||||||
{
|
{
|
||||||
var objectName = match.Groups["asset"].Value;
|
var objectName = CleanStructuralAssetPhrase(match.Groups["asset"].Value);
|
||||||
if (string.IsNullOrWhiteSpace(objectName) || !IsOwnedAssetName(objectName))
|
if (string.IsNullOrWhiteSpace(objectName) || !IsOwnedAssetName(objectName))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -912,6 +912,26 @@ public sealed class StoryIntelligenceAssetImportService(
|
|||||||
private static string CleanAssetName(string? value)
|
private static string CleanAssetName(string? value)
|
||||||
=> StoryIntelligenceEntityTextNormaliser.CleanName(value);
|
=> StoryIntelligenceEntityTextNormaliser.CleanName(value);
|
||||||
|
|
||||||
|
private static string CleanStructuralAssetPhrase(string? value)
|
||||||
|
{
|
||||||
|
var clean = CleanAssetName(value);
|
||||||
|
if (string.IsNullOrWhiteSpace(clean))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var separator in StructuralAssetTailSeparators)
|
||||||
|
{
|
||||||
|
var index = clean.IndexOf(separator, StringComparison.OrdinalIgnoreCase);
|
||||||
|
if (index > 0)
|
||||||
|
{
|
||||||
|
clean = clean[..index].Trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clean;
|
||||||
|
}
|
||||||
|
|
||||||
private static string RemoveLeadingArticle(string value)
|
private static string RemoveLeadingArticle(string value)
|
||||||
=> value.StartsWith("the ", StringComparison.OrdinalIgnoreCase)
|
=> value.StartsWith("the ", StringComparison.OrdinalIgnoreCase)
|
||||||
? value[4..]
|
? value[4..]
|
||||||
@ -930,6 +950,16 @@ public sealed class StoryIntelligenceAssetImportService(
|
|||||||
private static HashSet<string> CreateSet(params string[] values)
|
private static HashSet<string> CreateSet(params string[] values)
|
||||||
=> values.Select(Normalise).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
=> values.Select(Normalise).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
private static readonly string[] StructuralAssetTailSeparators =
|
||||||
|
[
|
||||||
|
" and ",
|
||||||
|
" or ",
|
||||||
|
" while ",
|
||||||
|
" that ",
|
||||||
|
" which ",
|
||||||
|
","
|
||||||
|
];
|
||||||
|
|
||||||
private static readonly Regex StructuralPossessiveAssetPattern = new(
|
private static readonly Regex StructuralPossessiveAssetPattern = new(
|
||||||
@"\b(?<owner>[A-Z][\p{L}'-]{1,40})'s\s+(?<asset>[A-Z][\p{L}\p{N}'-]*(?:\s+[A-Z][\p{L}\p{N}'-]*){0,3})\b",
|
@"\b(?<owner>[A-Z][\p{L}'-]{1,40})'s\s+(?<asset>[A-Z][\p{L}\p{N}'-]*(?:\s+[A-Z][\p{L}\p{N}'-]*){0,3})\b",
|
||||||
RegexOptions.Compiled);
|
RegexOptions.Compiled);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user