poe2-bot/tools/OcrDaemon/Models.cs
2026-02-12 22:07:54 -05:00

548 lines
13 KiB
C#

namespace OcrDaemon;
using System.Text.Json.Serialization;
class Request
{
[JsonPropertyName("cmd")]
public string? Cmd { get; set; }
[JsonPropertyName("region")]
public RegionRect? Region { get; set; }
[JsonPropertyName("path")]
public string? Path { get; set; }
[JsonPropertyName("cols")]
public int Cols { get; set; }
[JsonPropertyName("rows")]
public int Rows { get; set; }
[JsonPropertyName("threshold")]
public int Threshold { get; set; }
[JsonPropertyName("minCellSize")]
public int MinCellSize { get; set; }
[JsonPropertyName("maxCellSize")]
public int MaxCellSize { get; set; }
[JsonPropertyName("file")]
public string? File { get; set; }
[JsonPropertyName("debug")]
public bool Debug { get; set; }
[JsonPropertyName("targetRow")]
public int TargetRow { get; set; } = -1;
[JsonPropertyName("targetCol")]
public int TargetCol { get; set; } = -1;
[JsonPropertyName("engine")]
public string? Engine { get; set; }
[JsonPropertyName("preprocess")]
public string? Preprocess { get; set; }
[JsonPropertyName("params")]
public DiffOcrParams? Params { get; set; }
[JsonPropertyName("edgeParams")]
public EdgeOcrParams? EdgeParams { get; set; }
[JsonPropertyName("cursorX")]
public int? CursorX { get; set; }
[JsonPropertyName("cursorY")]
public int? CursorY { get; set; }
}
class RegionRect
{
[JsonPropertyName("x")]
public int X { get; set; }
[JsonPropertyName("y")]
public int Y { get; set; }
[JsonPropertyName("width")]
public int Width { get; set; }
[JsonPropertyName("height")]
public int Height { get; set; }
}
class ReadyResponse
{
[JsonPropertyName("ok")]
public bool Ok => true;
[JsonPropertyName("ready")]
public bool Ready => true;
}
class OkResponse
{
[JsonPropertyName("ok")]
public bool Ok => true;
}
class ErrorResponse(string message)
{
[JsonPropertyName("ok")]
public bool Ok => false;
[JsonPropertyName("error")]
public string Error => message;
}
class OcrResponse
{
[JsonPropertyName("ok")]
public bool Ok => true;
[JsonPropertyName("text")]
public string Text { get; set; } = "";
[JsonPropertyName("lines")]
public List<OcrLineResult> Lines { get; set; } = [];
}
class DiffOcrResponse
{
[JsonPropertyName("ok")]
public bool Ok => true;
[JsonPropertyName("text")]
public string Text { get; set; } = "";
[JsonPropertyName("lines")]
public List<OcrLineResult> Lines { get; set; } = [];
[JsonPropertyName("region")]
public RegionRect? Region { get; set; }
}
class OcrLineResult
{
[JsonPropertyName("text")]
public string Text { get; set; } = "";
[JsonPropertyName("words")]
public List<OcrWordResult> Words { get; set; } = [];
}
class OcrWordResult
{
[JsonPropertyName("text")]
public string Text { get; set; } = "";
[JsonPropertyName("x")]
public int X { get; set; }
[JsonPropertyName("y")]
public int Y { get; set; }
[JsonPropertyName("width")]
public int Width { get; set; }
[JsonPropertyName("height")]
public int Height { get; set; }
}
class CaptureResponse
{
[JsonPropertyName("ok")]
public bool Ok => true;
[JsonPropertyName("image")]
public string Image { get; set; } = "";
}
class GridResponse
{
[JsonPropertyName("ok")]
public bool Ok => true;
[JsonPropertyName("cells")]
public List<List<bool>> Cells { get; set; } = [];
[JsonPropertyName("items")]
public List<GridItem>? Items { get; set; }
[JsonPropertyName("matches")]
public List<GridMatch>? Matches { get; set; }
}
class GridItem
{
[JsonPropertyName("row")]
public int Row { get; set; }
[JsonPropertyName("col")]
public int Col { get; set; }
[JsonPropertyName("w")]
public int W { get; set; }
[JsonPropertyName("h")]
public int H { get; set; }
}
class GridMatch
{
[JsonPropertyName("row")]
public int Row { get; set; }
[JsonPropertyName("col")]
public int Col { get; set; }
[JsonPropertyName("similarity")]
public double Similarity { get; set; }
}
class DetectGridResponse
{
[JsonPropertyName("ok")]
public bool Ok => true;
[JsonPropertyName("detected")]
public bool Detected { get; set; }
[JsonPropertyName("region")]
public RegionRect? Region { get; set; }
[JsonPropertyName("cols")]
public int Cols { get; set; }
[JsonPropertyName("rows")]
public int Rows { get; set; }
[JsonPropertyName("cellWidth")]
public double CellWidth { get; set; }
[JsonPropertyName("cellHeight")]
public double CellHeight { get; set; }
}
class TemplateMatchResponse
{
[JsonPropertyName("ok")]
public bool Ok => true;
[JsonPropertyName("found")]
public bool Found { get; set; }
[JsonPropertyName("x")]
public int X { get; set; }
[JsonPropertyName("y")]
public int Y { get; set; }
[JsonPropertyName("width")]
public int Width { get; set; }
[JsonPropertyName("height")]
public int Height { get; set; }
[JsonPropertyName("confidence")]
public double Confidence { get; set; }
}
sealed class DiffCropParams
{
[JsonPropertyName("diffThresh")]
public int DiffThresh { get; set; } = 20;
[JsonPropertyName("rowThreshDiv")]
public int RowThreshDiv { get; set; } = 40;
[JsonPropertyName("colThreshDiv")]
public int ColThreshDiv { get; set; } = 8;
[JsonPropertyName("maxGap")]
public int MaxGap { get; set; } = 20;
[JsonPropertyName("trimCutoff")]
public double TrimCutoff { get; set; } = 0.4;
[JsonPropertyName("ocrPad")]
public int OcrPad { get; set; } = 10;
public override string ToString() =>
$"diffThresh={DiffThresh} maxGap={MaxGap} trimCutoff={TrimCutoff:F2} rowThreshDiv={RowThreshDiv} colThreshDiv={ColThreshDiv} ocrPad={OcrPad}";
}
sealed class OcrParams
{
// preprocessing
[JsonPropertyName("kernelSize")]
public int KernelSize { get; set; } = 41;
[JsonPropertyName("upscale")]
public int Upscale { get; set; } = 2;
[JsonPropertyName("useBackgroundSub")]
public bool UseBackgroundSub { get; set; } = true;
[JsonPropertyName("dimPercentile")]
public int DimPercentile { get; set; } = 40;
[JsonPropertyName("textThresh")]
public int TextThresh { get; set; } = 60;
[JsonPropertyName("softThreshold")]
public bool SoftThreshold { get; set; } = false;
// Tesseract-specific
[JsonPropertyName("usePerLineOcr")]
public bool UsePerLineOcr { get; set; } = false;
[JsonPropertyName("lineGapTolerance")]
public int LineGapTolerance { get; set; } = 10;
[JsonPropertyName("linePadY")]
public int LinePadY { get; set; } = 20;
[JsonPropertyName("psm")]
public int Psm { get; set; } = 6;
// post-merge / Python engine tuning
[JsonPropertyName("mergeGap")]
public int MergeGap { get; set; } = 0;
[JsonPropertyName("linkThreshold")]
public double? LinkThreshold { get; set; }
[JsonPropertyName("textThreshold")]
public double? TextThreshold { get; set; }
[JsonPropertyName("lowText")]
public double? LowText { get; set; }
[JsonPropertyName("widthThs")]
public double? WidthThs { get; set; }
[JsonPropertyName("paragraph")]
public bool? Paragraph { get; set; }
public override string ToString() =>
UseBackgroundSub
? $"bgSub dimPct={DimPercentile} textThresh={TextThresh} soft={SoftThreshold} upscale={Upscale} mergeGap={MergeGap}"
: $"topHat kernel={KernelSize} upscale={Upscale} mergeGap={MergeGap}";
}
sealed class DiffOcrParams
{
[JsonPropertyName("crop")]
public DiffCropParams Crop { get; set; } = new();
[JsonPropertyName("ocr")]
public OcrParams Ocr { get; set; } = new();
public override string ToString() => $"[{Crop}] [{Ocr}]";
}
sealed class EdgeCropParams
{
[JsonPropertyName("darkThresh")]
public int DarkThresh { get; set; } = 40;
[JsonPropertyName("minDarkRun")]
public int MinDarkRun { get; set; } = 200;
[JsonPropertyName("runGapTolerance")]
public int RunGapTolerance { get; set; } = 15;
[JsonPropertyName("rowThreshDiv")]
public int RowThreshDiv { get; set; } = 40;
[JsonPropertyName("colThreshDiv")]
public int ColThreshDiv { get; set; } = 8;
[JsonPropertyName("maxGap")]
public int MaxGap { get; set; } = 15;
[JsonPropertyName("trimCutoff")]
public double TrimCutoff { get; set; } = 0.3;
[JsonPropertyName("ocrPad")]
public int OcrPad { get; set; } = 10;
public override string ToString() =>
$"darkThresh={DarkThresh} minRun={MinDarkRun} runGap={RunGapTolerance} maxGap={MaxGap} trimCutoff={TrimCutoff:F2} rowDiv={RowThreshDiv} colDiv={ColThreshDiv}";
}
sealed class EdgeOcrParams
{
[JsonPropertyName("crop")]
public EdgeCropParams Crop { get; set; } = new();
[JsonPropertyName("ocr")]
public OcrParams Ocr { get; set; } = new();
public override string ToString() => $"[{Crop}] [{Ocr}]";
}
class TestCase
{
[JsonPropertyName("id")]
public string Id { get; set; } = "";
[JsonPropertyName("image")]
public string Image { get; set; } = "";
[JsonPropertyName("fullImage")]
public string FullImage { get; set; } = "";
[JsonPropertyName("expected")]
public List<string> Expected { get; set; } = [];
}
class TestCaseResult
{
[JsonPropertyName("id")]
public string Id { get; set; } = "";
[JsonPropertyName("passed")]
public bool Passed { get; set; }
[JsonPropertyName("score")]
public double Score { get; set; }
[JsonPropertyName("matched")]
public List<string> Matched { get; set; } = [];
[JsonPropertyName("missed")]
public List<string> Missed { get; set; } = [];
[JsonPropertyName("extra")]
public List<string> Extra { get; set; } = [];
}
class TestResponse
{
[JsonPropertyName("ok")]
public bool Ok => true;
[JsonPropertyName("passed")]
public int Passed { get; set; }
[JsonPropertyName("failed")]
public int Failed { get; set; }
[JsonPropertyName("total")]
public int Total { get; set; }
[JsonPropertyName("results")]
public List<TestCaseResult> Results { get; set; } = [];
}
class TuneResponse
{
[JsonPropertyName("ok")]
public bool Ok => true;
[JsonPropertyName("bestScore")]
public double BestScore { get; set; }
[JsonPropertyName("bestParams")]
public DiffOcrParams BestParams { get; set; } = new();
[JsonPropertyName("iterations")]
public int Iterations { get; set; }
}
// ── Crop test models ────────────────────────────────────────────────────────
class PointXY
{
[JsonPropertyName("x")]
public int X { get; set; }
[JsonPropertyName("y")]
public int Y { get; set; }
}
class CropTestCase
{
[JsonPropertyName("id")]
public string Id { get; set; } = "";
[JsonPropertyName("image")]
public string Image { get; set; } = "";
[JsonPropertyName("snapshotImage")]
public string SnapshotImage { get; set; } = "";
[JsonPropertyName("topLeft")]
public PointXY TopLeft { get; set; } = new();
[JsonPropertyName("bottomRight")]
public PointXY BottomRight { get; set; } = new();
[JsonPropertyName("cursorX")]
public int? CursorX { get; set; }
[JsonPropertyName("cursorY")]
public int? CursorY { get; set; }
}
class CropTestResult
{
[JsonPropertyName("id")]
public string Id { get; set; } = "";
[JsonPropertyName("iou")]
public double IoU { get; set; }
[JsonPropertyName("expected")]
public RegionRect Expected { get; set; } = new();
[JsonPropertyName("actual")]
public RegionRect? Actual { get; set; }
[JsonPropertyName("deltaTop")]
public int DeltaTop { get; set; }
[JsonPropertyName("deltaLeft")]
public int DeltaLeft { get; set; }
[JsonPropertyName("deltaRight")]
public int DeltaRight { get; set; }
[JsonPropertyName("deltaBottom")]
public int DeltaBottom { get; set; }
}
class CropTestResponse
{
[JsonPropertyName("ok")]
public bool Ok => true;
[JsonPropertyName("method")]
public string Method { get; set; } = "";
[JsonPropertyName("avgIoU")]
public double AvgIoU { get; set; }
[JsonPropertyName("results")]
public List<CropTestResult> Results { get; set; } = [];
}
class CropTuneResponse
{
[JsonPropertyName("ok")]
public bool Ok => true;
[JsonPropertyName("bestAvgIoU")]
public double BestAvgIoU { get; set; }
[JsonPropertyName("bestParams")]
public DiffCropParams BestParams { get; set; } = new();
[JsonPropertyName("iterations")]
public int Iterations { get; set; }
}