Improve IK-style artifact scanner pipeline

This commit is contained in:
AzuTear
2026-07-07 22:02:24 +02:00
parent 8ebbe91c39
commit f791d1464c
70 changed files with 7408 additions and 445 deletions
+68 -4
View File
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo } from "react";
import { useCallback, useEffect, useMemo, useRef } from "react";
import type { Dispatch, MutableRefObject, SetStateAction } from "react";
import { runAutoReviewScan as runAutoReviewScanAction, runVisibleGridScan as runVisibleGridScanAction, type VisibleGridScanOptions } from "./scanViewScanActions";
import {
@@ -21,6 +21,8 @@ import type {
} from "../../../infrastructure/repositories/rendererBridgeRepositoryTypes";
import type { AutoScanStats, ScanSummary } from "../../../lib/scannerSession";
import type { RuntimeInfo } from "../../../types/global";
import type { createScanDiagnosticEvent } from "../../../lib/scanDiagnosticsLog";
import { validateAutoScanEntryPreflight } from "../../../lib/autoScanEntry";
type BooleanSetter = Dispatch<SetStateAction<boolean>>;
type NumberSetter = Dispatch<SetStateAction<number>>;
@@ -49,6 +51,7 @@ interface ScanViewActionInput {
setReviewStatus: StringSetter;
appendAutomationLog: (line: string) => void;
appendClickDiagnostics: (result: ClickResult, prefix?: string) => void;
appendDiagnosticEvent: (event: Omit<Parameters<typeof createScanDiagnosticEvent>[0], "includeFullScreenshot">) => void;
parseArtifact: (capture: CaptureResult | null) => ParsedArtifactCandidate | null;
artifactRepo?: ArtifactRepositoryPort;
reviewSamplesRepo?: ReviewSampleRepositoryPort;
@@ -77,6 +80,7 @@ export interface ScanViewActionResult {
loadReviewQueue: () => Promise<void>;
openReviewQueue: () => Promise<void>;
runAutoReviewScan: () => Promise<void>;
runGuidedAutoScan: (options?: { scanLimit?: number; ocrEngine?: CaptureOptions["ocrEngine"] }) => Promise<void>;
runVisibleGridScan: (options?: VisibleGridScanOptions) => Promise<void>;
}
@@ -99,6 +103,7 @@ export function useScanViewActions(input: ScanViewActionInput): ScanViewActionRe
setReviewStatus,
appendAutomationLog,
appendClickDiagnostics,
appendDiagnosticEvent,
parseArtifact,
artifactRepo,
reviewSamplesRepo,
@@ -116,6 +121,7 @@ export function useScanViewActions(input: ScanViewActionInput): ScanViewActionRe
canCaptureSource,
setReviewQueueOpen,
} = input;
const learningInitializedRef = useRef(false);
const requestScanStop = useCallback((reason = "Stop angefordert.") => {
stopVisibleScanRef.current = true;
@@ -154,8 +160,11 @@ export function useScanViewActions(input: ScanViewActionInput): ScanViewActionRe
);
useEffect(() => {
if (learningInitializedRef.current) return;
if (!learningRepo && !reviewSamplesRepo && !artifactRepo) return;
learningInitializedRef.current = true;
void initializeLearningState(reviewContext);
}, [reviewContext]);
}, [artifactRepo, learningRepo, reviewContext, reviewSamplesRepo]);
const focusDashboard = useCallback(async () => {
try {
@@ -215,12 +224,25 @@ export function useScanViewActions(input: ScanViewActionInput): ScanViewActionRe
setReviewStatus,
appendAutomationLog,
appendClickDiagnostics,
appendDiagnosticEvent,
parseArtifact,
persistParsedArtifact: parseArtifactAndPersist,
saveReviewSample: handleSaveReviewSample,
focusDashboard,
captureSelectedSource,
captureFastSelectedSource: (delayMs = 0, focusGenshin = false) => captureSelectedSource(delayMs, focusGenshin, { skipOcr: true }),
captureSelectedSource: (delayMs = 0, focusGenshin = false, options) => captureSelectedSource(delayMs, focusGenshin, {
ocrMode: "artifact",
omitFullFrame: true,
omitInventoryPreview: true,
...options,
}),
captureFastSelectedSource: (delayMs = 0, focusGenshin = false, options) => captureSelectedSource(delayMs, focusGenshin, {
skipOcr: true,
omitFullFrame: true,
omitCrops: true,
omitCropImages: true,
omitLockState: true,
...options,
}),
}),
[
autoScanRunning,
@@ -240,6 +262,7 @@ export function useScanViewActions(input: ScanViewActionInput): ScanViewActionRe
setReviewStatus,
appendAutomationLog,
appendClickDiagnostics,
appendDiagnosticEvent,
parseArtifact,
parseArtifactAndPersist,
handleSaveReviewSample,
@@ -276,12 +299,52 @@ export function useScanViewActions(input: ScanViewActionInput): ScanViewActionRe
scanActionContext,
]);
const runGuidedAutoScan = useCallback(async (options: { scanLimit?: number; ocrEngine?: CaptureOptions["ocrEngine"] } = {}) => {
if (autoScanRunning || !bridgeReady || !selectedSourceId || !automationRepo?.clickScreen || !automationRepo?.scrollScreen) {
return;
}
setReviewStatus("Auto-Scan prueft den Startzustand ohne OCR...");
const preflightCapture = await captureSelectedSource(0, true, {
skipOcr: true,
omitFullFrame: true,
omitCrops: true,
omitCropImages: true,
omitLockState: true,
});
const visibleInventoryReady = validateAutoScanEntryPreflight(preflightCapture).ok;
appendDiagnosticEvent({
phase: "guided-start",
severity: visibleInventoryReady ? "ok" : "info",
message: visibleInventoryReady
? "Artifact inventory detail view already visible; starting scan directly."
: "Artifact detail view is not ready; trying direct inventory entry, then Inventory Kamera fallback.",
capture: preflightCapture,
});
await runVisibleGridScanAction(scanActionContext, {
scanLimit: options.scanLimit,
scanEntryMode: visibleInventoryReady ? "visible-inventory" : "auto-entry",
processInitialSelection: visibleInventoryReady,
ocrEngine: options.ocrEngine,
});
}, [
autoScanRunning,
bridgeReady,
selectedSourceId,
automationRepo?.clickScreen,
automationRepo?.scrollScreen,
setReviewStatus,
captureSelectedSource,
appendDiagnosticEvent,
scanActionContext,
]);
useScanCommandListener({
automationRepo,
autoScanRunning,
isScanning,
selectedSourceId,
requestScanStop,
runGuidedAutoScan,
runVisibleGridScan,
});
@@ -291,6 +354,7 @@ export function useScanViewActions(input: ScanViewActionInput): ScanViewActionRe
loadReviewQueue: loadReviewQueueAction,
openReviewQueue: openReviewQueueModal,
runAutoReviewScan,
runGuidedAutoScan,
runVisibleGridScan,
};
}