Files
genshin-assistant/src/lib/scanDiagnosticsLog.ts
T
2026-07-07 22:02:24 +02:00

133 lines
4.0 KiB
TypeScript

import { detailFingerprint } from "./autoScanLoop";
import type { CaptureResult, ClickResult, KeyPressResult } from "../types/global";
export type ScanDiagnosticSeverity = "info" | "ok" | "warn" | "error";
type InventoryGrid = NonNullable<CaptureResult["inventoryGrid"]>;
type InventoryCount = NonNullable<CaptureResult["inventoryCount"]>;
export interface ScanDiagnosticEvent {
id: string;
at: string;
phase: string;
severity: ScanDiagnosticSeverity;
message: string;
details?: Record<string, string | number | boolean | null | undefined>;
capture?: {
id: string;
name: string;
width: number;
height: number;
capturedAt: string;
target?: CaptureResult["captureTarget"];
fingerprint: string;
inventoryFingerprint?: string;
layoutWarning?: string;
grid?: {
rows: number;
cols: number;
confidence: number;
source: InventoryGrid["source"];
targets: number;
};
count?: {
current: number;
total: number;
confidence: number;
source: InventoryCount["source"];
text: string;
};
artifactDetail?: NonNullable<CaptureResult["artifactDetail"]>;
paimonMenu?: NonNullable<CaptureResult["paimonMenu"]>;
sanctified?: boolean;
screenshots?: {
detail?: string;
inventory?: string;
full?: string;
};
};
}
export function createScanDiagnosticEvent(input: {
phase: string;
severity?: ScanDiagnosticSeverity;
message: string;
details?: ScanDiagnosticEvent["details"];
capture?: CaptureResult | null;
includeFullScreenshot?: boolean;
}): ScanDiagnosticEvent {
return {
id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
at: new Date().toISOString(),
phase: input.phase,
severity: input.severity ?? "info",
message: input.message,
details: input.details,
capture: input.capture ? summarizeCapture(input.capture, Boolean(input.includeFullScreenshot)) : undefined,
};
}
export function summarizeClickResult(result: ClickResult) {
return {
ok: result.ok,
moved: result.moved,
clicked: result.clicked,
inputBlocked: result.inputBlocked,
focused: result.focused,
cursor: `${result.cursorX ?? "?"},${result.cursorY ?? "?"}`,
foreground: result.foregroundProcess,
target: result.targetProcess,
};
}
export function summarizeKeyPressResult(result: KeyPressResult | null | undefined) {
return {
ok: Boolean(result?.ok),
key: result?.key,
inputBlocked: Boolean(result?.inputBlocked),
focused: Boolean(result?.focused),
eventsSent: result?.eventsSent ?? 0,
foreground: result?.foregroundProcess,
target: result?.targetProcess,
};
}
function summarizeCapture(capture: CaptureResult, includeFullScreenshot: boolean): NonNullable<ScanDiagnosticEvent["capture"]> {
return {
id: capture.id,
name: capture.name,
width: capture.width,
height: capture.height,
capturedAt: capture.capturedAt,
target: capture.captureTarget,
fingerprint: detailFingerprint(capture),
inventoryFingerprint: capture.inventoryFingerprint,
layoutWarning: capture.layout?.warning || undefined,
grid: capture.inventoryGrid
? {
rows: capture.inventoryGrid.rows,
cols: capture.inventoryGrid.cols,
confidence: capture.inventoryGrid.confidence,
source: capture.inventoryGrid.source,
targets: capture.inventoryGrid.centers.length,
}
: undefined,
count: capture.inventoryCount
? {
current: capture.inventoryCount.current,
total: capture.inventoryCount.total,
confidence: capture.inventoryCount.confidence,
source: capture.inventoryCount.source,
text: capture.inventoryCount.text,
}
: undefined,
artifactDetail: capture.artifactDetail,
paimonMenu: capture.paimonMenu,
sanctified: capture.sanctified,
screenshots: {
detail: capture.detailDataUrl,
inventory: capture.inventoryDataUrl,
full: includeFullScreenshot ? capture.dataUrl : undefined,
},
};
}