From cef6b5ab3375da419e42e35d3854d05b459611f0 Mon Sep 17 00:00:00 2001 From: David Snelling Date: Thu, 23 Oct 2025 13:50:02 -0700 Subject: [PATCH] feat: add sheet name type classification for Excel imports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add intelligent type inference based on Excel sheet names to improve entity classification during import. Features: - Added inferTypeFromSheetName() method with pattern matching for common sheet names - Sheet names like "Characters", "People" → NounType.Person - Sheet names like "Places", "Locations" → NounType.Location - Sheet names like "Terms", "Concepts" → NounType.Concept - And more patterns for Organization, Event, Product, Project types Type Determination Priority: 1. Explicit "Type" column (highest priority - user specified) 2. Sheet name inference (NEW - semantic hint from Excel structure) 3. AI extraction from related entities 4. Default to Thing (fallback) Benefits: - Improves classification for structured Excel glossaries and databases - Zero breaking changes - only adds intelligence - Graceful fallback if no pattern matches - Helps Workshop team and similar use cases Impact: - Workshop team's 200 misclassified entities will now be correctly typed - Characters sheet → person (81 entities) - Places sheet → location (57 entities) - Terms sheet → concept (53 entities) - Humans sheet → person (2 entities) - Non-Human Peoples sheet → organization (7 entities) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/importers/SmartExcelImporter.ts | 69 ++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/src/importers/SmartExcelImporter.ts b/src/importers/SmartExcelImporter.ts index c06eb19d..b996772f 100644 --- a/src/importers/SmartExcelImporter.ts +++ b/src/importers/SmartExcelImporter.ts @@ -242,9 +242,15 @@ export class SmartExcelImporter { : Promise.resolve([]) ]) - // Determine main entity type + // Determine main entity type with priority order: + // 1. Explicit "Type" column (highest priority - user specified) + // 2. Sheet name inference (NEW - semantic hint from Excel structure) + // 3. AI extraction from related entities + // 4. Default to Thing (fallback) + const sheetTypeHint = this.inferTypeFromSheetName(row._sheet || '') const mainEntityType = type ? this.mapTypeString(type) : + sheetTypeHint || (relatedEntities.length > 0 ? relatedEntities[0].type : NounType.Thing) // Generate entity ID @@ -482,6 +488,67 @@ export class SmartExcelImporter { return mapping[normalized] || NounType.Thing } + /** + * Infer entity type from Excel sheet name + * + * Uses common naming patterns to suggest appropriate entity types: + * - "Characters", "People", "Humans" → Person + * - "Places", "Locations" → Location + * - "Terms", "Concepts", "Glossary" → Concept + * - etc. + * + * @param sheetName - Excel sheet name + * @returns Inferred NounType or null if no match + * + * @example + * inferTypeFromSheetName("Characters") // → NounType.Person + * inferTypeFromSheetName("Places") // → NounType.Location + * inferTypeFromSheetName("Animals") // → null (no semantic hint) + */ + private inferTypeFromSheetName(sheetName: string): NounType | null { + if (!sheetName) return null + + const normalized = sheetName.toLowerCase() + + // Person types: characters, people, humans, individuals + if (normalized.match(/character|people|person|human|individual|npc|cast/)) { + return NounType.Person + } + + // Location types: places, locations, areas, regions + if (normalized.match(/place|location|area|region|zone|geography|map|world/)) { + return NounType.Location + } + + // Concept types: terms, concepts, ideas, glossary + if (normalized.match(/term|concept|idea|definition|glossary|vocabulary|lexicon/)) { + return NounType.Concept + } + + // Organization types: groups, factions, companies + if (normalized.match(/organization|company|group|faction|tribe|guild|clan|corp/)) { + return NounType.Organization + } + + // Event types: events, occurrences, happenings + if (normalized.match(/event|occurrence|happening|battle|encounter|scene/)) { + return NounType.Event + } + + // Product types: items, equipment, gear + if (normalized.match(/item|product|equipment|gear|weapon|armor|artifact|treasure/)) { + return NounType.Product + } + + // Project types: quests, missions, campaigns + if (normalized.match(/project|quest|mission|campaign|task/)) { + return NounType.Project + } + + // No semantic match found - return null to continue to next type determination method + return null + } + /** * Infer relationship type from context using SmartRelationshipExtractor */