Prepare scanner branch for merge

This commit is contained in:
AzuTear
2026-07-09 08:44:50 +02:00
parent f791d1464c
commit 8b73c01e46
69 changed files with 6700 additions and 3773 deletions
+35 -1
View File
@@ -82,6 +82,7 @@ export function parseArtifactCandidate(capture: CaptureResult | null): ParsedArt
const parsedLevel = levelField.value ? Number.parseInt(levelField.value, 10) : null;
const level = parsedLevel ?? 0;
let mainStatField = inferMainStat(slotField.value, mainText);
mainStatField = promoteSlotPercentMainStat(slotField.value, mainStatField);
let mainValueField = findMainValue(mainText, mainStatField.value, slotField.value, parsedLevel);
if (!mainStatField.value && mainValueField.value) {
const inferredFromValue = inferMainStatFromValue(slotField.value, mainValueField.value, mainText, parsedLevel);
@@ -227,6 +228,8 @@ function parseSetName(setText: string, artifactName: ParsedField): ParsedField {
const setFromText = fuzzyFindKnown(`${directLine ?? ""}\n${setText}`, knownSets, 0.64);
if (setFromText && (!setFromPiece || setFromText.score >= 0.78)) return field(setFromText.value, Math.round(setFromText.score * 100), setFromText.score >= 0.95 ? "ocr" : "fallback");
if (setFromPiece) return field(setFromPiece, derivedConfidence(artifactName, 92), "derived");
const partialSetFromPiece = deriveSetFromPartialPieceName(artifactName.value);
if (partialSetFromPiece) return field(partialSetFromPiece, 72, "derived");
return setFromText ? field(setFromText.value, Math.round(setFromText.score * 100), "fallback") : field("", 0, "missing");
}
@@ -275,6 +278,22 @@ function firstUsefulLine(text: string, rejectIncludes: string[]) {
.find((line) => line.length > 5 && !rejectIncludes.some((reject) => simplifyForMatch(line).includes(simplifyForMatch(reject)))) ?? "";
}
function deriveSetFromPartialPieceName(text: string) {
const words = cleanupOcrLabel(text)
.split(/\s+/)
.map((word) => simplifyForMatch(word))
.filter((word) => word.length >= 5);
if (words.length < 2) return "";
const candidates = knownPieceNames.filter((piece) => {
const normalizedPiece = simplifyForMatch(piece);
const hits = words.filter((word) => normalizedPiece.includes(word)).length;
return hits >= 2;
});
const sets = [...new Set(candidates.map((piece) => pieceToSet.get(piece)).filter((set): set is string => Boolean(set)))];
return sets.length === 1 ? sets[0] : "";
}
function findMainValue(text: string, mainStat: string, slot: string, level: number | null): ParsedField {
const cleaned = text.replace(/\b20\b/g, " ").replace(/[Oo]/g, "0");
const percentValue = extractPercentValue(cleaned);
@@ -504,7 +523,7 @@ function parseEquippedCharacter(text: string): ParsedField {
const wholeTextMatch = fallbackSearch ? fuzzyFindKnown(fallbackSearch, knownCharacters, 0.88) : null;
if (wholeTextMatch) return field(wholeTextMatch.value, Math.round(wholeTextMatch.score * 100), "fallback");
return afterLabel ? field(afterLabel, 50, "fallback") : field("Not detected", 45, "missing");
return field("Not detected", 45, "missing");
}
function field(value: string, confidence: number, source: ParsedField["source"]): ParsedField {
@@ -520,6 +539,20 @@ function promotePercentVariant(stat: string, text: string) {
return stat;
}
function promoteSlotPercentMainStat(slot: string, mainStat: ParsedField): ParsedField {
if (!["ATK", "HP", "DEF"].includes(mainStat.value)) return mainStat;
const references = getSlotMainStatValueReferences(slot);
const hasFlat = references.some((candidate) => candidate.stat === mainStat.value);
const hasPercent = references.some((candidate) => candidate.stat === `${mainStat.value}%`);
if (hasFlat || !hasPercent) return mainStat;
return {
...mainStat,
value: `${mainStat.value}%`,
confidence: Math.max(mainStat.confidence, 90),
source: "derived",
};
}
function getSlotMainStatValueReferences(slot: string): MainStatValueReference[] {
const valueReferences = mainStatValueReferences[slot];
return Array.isArray(valueReferences) ? valueReferences as MainStatValueReference[] : [];
@@ -607,6 +640,7 @@ function cleanupOcrLabel(line: string) {
function cleanupCharacterNoise(text: string) {
return text
.replace(/^.*?equipped\s*:?\s*/i, "")
.replace(/^(?:by|to)\s+/i, "")
.replace(/[^A-Za-z'\-\s]/g, " ")
.replace(/\s+/g, " ")
.trim();