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 contextual vehicle variants", AssetCanonicalKeysMergeContextualVehicleVariants),
|
||||
("Asset contextual names resolve POV ownership", AssetContextualNamesResolvePovOwnership),
|
||||
("Asset structural phrases trim neighbouring nouns", AssetStructuralPhrasesTrimNeighbouringNouns),
|
||||
("Relationship signals map to broad lookup types", RelationshipSignalsMapToBroadTypes),
|
||||
("Relationship signals infer friendship without romance", RelationshipSignalsInferFriendshipWithoutRomance),
|
||||
("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.");
|
||||
}
|
||||
|
||||
static void AssetStructuralPhrasesTrimNeighbouringNouns()
|
||||
{
|
||||
Assert(CleanStructuralAssetPhrase("memory tin and photographs") == "memory tin", "Structural asset extraction should not bundle neighbouring nouns after and.");
|
||||
}
|
||||
|
||||
static void RelationshipSignalsMapToBroadTypes()
|
||||
{
|
||||
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])!;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var nested = typeof(StoryIntelligenceRelationshipImportService).GetNestedType(
|
||||
|
||||
@ -462,7 +462,7 @@ public sealed class StoryIntelligenceAssetImportService(
|
||||
foreach (Match match in StructuralPossessiveAssetPattern.Matches(source))
|
||||
{
|
||||
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))
|
||||
{
|
||||
continue;
|
||||
@ -482,7 +482,7 @@ public sealed class StoryIntelligenceAssetImportService(
|
||||
|
||||
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))
|
||||
{
|
||||
continue;
|
||||
@ -912,6 +912,26 @@ public sealed class StoryIntelligenceAssetImportService(
|
||||
private static string CleanAssetName(string? 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)
|
||||
=> value.StartsWith("the ", StringComparison.OrdinalIgnoreCase)
|
||||
? value[4..]
|
||||
@ -930,6 +950,16 @@ public sealed class StoryIntelligenceAssetImportService(
|
||||
private static HashSet<string> CreateSet(params string[] values)
|
||||
=> values.Select(Normalise).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private static readonly string[] StructuralAssetTailSeparators =
|
||||
[
|
||||
" and ",
|
||||
" or ",
|
||||
" while ",
|
||||
" that ",
|
||||
" which ",
|
||||
","
|
||||
];
|
||||
|
||||
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",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user