fix: make skills parser handle text-based proficiency levels

Parser was only matching numeric levels "(Lv 5)" but AI was returning
text proficiencies like "(Proficient)", "(Advanced)", causing all skills
to be ignored and not categorized.

Changes to parser.js:
- Add fallback regex to match text proficiency format: "- Skill (Proficient)"
- Map text proficiencies to numeric levels:
  - Initiated/Novice → Lv 1
  - Basic/Beginner → Lv 2
  - Intermediate → Lv 4
  - Proficient → Lv 5
  - Competent → Lv 6
  - Advanced → Lv 7
  - Expert → Lv 8
  - Mastered/Master → Lv 9
  - Grandmaster/Legendary → Lv 10
- Default to Lv 5 for unrecognized proficiency text
- Try numeric format first, fall back to text format

Changes to promptBuilder.js:
- Make prompt instructions more explicit about numeric format
- Add negative examples: "write 'Lv 5' not 'Proficient'"
- Add guidance: "1=novice, 5=intermediate, 10=expert"
- Emphasize with "IMPORTANT:" prefix

Benefits:
- Parser now handles both formats (backward compatible)
- AI has clearer instructions to use numeric levels
- Skills with text proficiencies now parse correctly and show in categories
- Existing numeric format continues to work

Issue Resolution:
- Skills like "Demonic Qi Manipulation (Proficient)" now parse as Lv 5
- Categories like "Demonic Arts:", "Combat:", "Social:" now populate correctly
- Widget displays skills organized by category instead of ignoring them

Related: Skills widget, AI tracker integration
This commit is contained in:
Lucas 'Paperboy' Rose-Winters
2025-11-06 22:48:38 +11:00
parent 4dd71c95c7
commit fe5abb47ba
2 changed files with 42 additions and 2 deletions
+41 -1
View File
@@ -187,7 +187,8 @@ function extractSkills(statsText) {
}
// Check if this is a skill line (starts with -, has level info)
const skillMatch = line.match(/^-\s*(.+?)\s*\(Lv\s*(\d+)\)/i);
// Try numeric format first: "- Skill Name (Lv 5)"
let skillMatch = line.match(/^-\s*(.+?)\s*\(Lv\s*(\d+)\)/i);
if (skillMatch) {
const skillName = skillMatch[1].trim();
const level = parseInt(skillMatch[2], 10) || 1;
@@ -204,6 +205,45 @@ function extractSkills(statsText) {
} else if (currentCategory && skillsData.categories[currentCategory]) {
skillsData.categories[currentCategory].push(skill);
}
} else {
// Fallback: Try text-based proficiency format: "- Skill Name (Proficient)"
const textMatch = line.match(/^-\s*(.+?)\s*\((.+?)\)/i);
if (textMatch) {
const skillName = textMatch[1].trim();
const proficiencyText = textMatch[2].trim().toLowerCase();
// Map text proficiency to numeric level
const proficiencyMap = {
'initiated': 1,
'novice': 1,
'basic': 2,
'beginner': 2,
'intermediate': 4,
'proficient': 5,
'competent': 6,
'advanced': 7,
'expert': 8,
'mastered': 9,
'master': 9,
'grandmaster': 10,
'legendary': 10
};
const level = proficiencyMap[proficiencyText] || 5; // Default to 5 if unknown
const skill = {
name: skillName,
level: level,
xp: 0,
maxXP: 100
};
if (currentCategory === 'Uncategorized' || currentCategory === null) {
skillsData.uncategorized.push(skill);
} else if (currentCategory && skillsData.categories[currentCategory]) {
skillsData.categories[currentCategory].push(skill);
}
}
}
}
+1 -1
View File
@@ -219,7 +219,7 @@ export function generateTrackerInstructions(includeHtmlPrompt = true, includeCon
instructions += `- [Another Skill] (Lv [1-100])\n`;
instructions += `Uncategorized:\n`;
instructions += `- [Uncategorized Skill] (Lv [1-100])\n`;
instructions += `(Organize skills by logical categories like Combat, Magic, Social, Crafting, etc. Include level as integer 1-100. Skills without a clear category go in Uncategorized.)\n`;
instructions += `(Organize skills by logical categories like Combat, Magic, Social, Crafting, etc. IMPORTANT: Use numeric levels only - write "Lv 5" not "Proficient", "Lv 7" not "Advanced". Use integers 1-100 where 1=novice, 5=intermediate, 10=expert. Skills without a clear category go in Uncategorized.)\n`;
}
// Add inventory format based on feature flag