remove class mode

This commit is contained in:
2026-03-22 12:11:48 +01:00
parent 011ca5ae8c
commit 0cbb772dc4

View File

@@ -28,17 +28,18 @@ def _verdict_str(verdict: TicketVerdict) -> str:
_FC = 14 # field column visual width
_VC = 24 # value column visual width
_BET_W = 1 + (_FC + 2) + 1 + (_VC + 2) + 1 + (_VC + 2) + 1 # one bet table width
_GAP = " " # space between side-by-side tables
_VC = 24 # value column visual width (dual)
_SC = 38 # value column visual width (single classifier)
_BET_W = 1 + (_FC + 2) + 1 + (_VC + 2) + 1 + (_VC + 2) + 1 # dual table width
_BET_WS = 1 + (_FC + 2) + 1 + (_SC + 2) + 1 # single table width
_GAP = " "
_FIELD_LABELS: dict[str, str] = {
"team1Name": "team1",
"team2Name": "team2",
}
_FIELD_LABELS: dict[str, str] = {"team1Name": "team1", "team2Name": "team2"}
_FIELD_ORDER = ["type", "team1Name", "team2Name", "date", "league"]
_SKIP_FIELDS = {"ticketType"}
_BLANK_ROW = f"{' ' * (_FC + 2)}{' ' * (_VC + 2)}{' ' * (_VC + 2)}"
_BLANK_ROWS = f"{' ' * (_FC + 2)}{' ' * (_SC + 2)}"
def _vlen(text: str) -> int:
@@ -58,9 +59,10 @@ def _bet_fields(bet: Bet) -> dict[str, str]:
return fields
# ── dual-column table (compare) ──────────────────────────────────────────────
def _tbl_row(field: str, lval: str, ival: str) -> str:
label = _FIELD_LABELS.get(field, field)
return f"{_vpad(label, _FC)}{_vpad(lval, _VC)}{_vpad(ival, _VC)}"
return f"{_vpad(_FIELD_LABELS.get(field, field), _FC)}{_vpad(lval, _VC)}{_vpad(ival, _VC)}"
def _tbl_sep(left: str, mid: str, right: str) -> str:
@@ -86,51 +88,76 @@ def _bet_to_lines(idx: int, link_bet: Bet | None, img_bet: Bet | None) -> list[s
data_rows.append(_tbl_row(key, lval, ival))
header = _vpad(_ansi.bold(_ansi.cyan(f" Bet {idx} ")), _BET_W)
return [
header,
_tbl_sep("", "", ""),
_tbl_row("", _ansi.bold("link classifier"), _ansi.bold("image classifier")),
_tbl_sep("", "", ""),
*data_rows,
_tbl_sep("", "", ""),
return [header, _tbl_sep("", "", ""), _tbl_row("", _ansi.bold("link"), _ansi.bold("image")),
_tbl_sep("", "", ""), *data_rows, _tbl_sep("", "", "")]
# ── single-column table (one classifier) ─────────────────────────────────────
def _tbl_row_s(field: str, val: str) -> str:
return f"{_vpad(_FIELD_LABELS.get(field, field), _FC)}{_vpad(val, _SC)}"
def _tbl_sep_s(left: str, mid: str, right: str) -> str:
return f"{left}{'' * (_FC + 2)}{mid}{'' * (_SC + 2)}{right}"
def _bet_to_lines_single(idx: int, bet: Bet, col_label: str) -> list[str]:
fields = _bet_fields(bet)
keys = [k for k in _FIELD_ORDER if k in fields] + [k for k in fields if k not in _FIELD_ORDER]
data_rows = [
_tbl_row_s(k, (v[:_SC - 1] + "" if len(v) > _SC else v))
for k, v in ((k, fields[k]) for k in keys)
]
header = _vpad(_ansi.bold(_ansi.cyan(f" Bet {idx} ")), _BET_WS)
return [header, _tbl_sep_s("", "", ""), _tbl_row_s("", _ansi.bold(col_label)),
_tbl_sep_s("", "", ""), *data_rows, _tbl_sep_s("", "", "")]
def _pad_to(lines: list[str], target: int) -> list[str]:
# ── shared grid printer ───────────────────────────────────────────────────────
def _pad_to(lines: list[str], target: int, blank: str) -> list[str]:
result = list(lines)
while len(result) < target:
result.insert(-1, _BLANK_ROW)
result.insert(-1, blank)
return result
def _print_compare(link_ticket: Ticket, img_ticket: Ticket) -> None:
n_link = len(link_ticket.bets)
n_img = len(img_ticket.bets)
n_max = max(n_link, n_img)
def _print_bet_grid(ticket_header: str, all_lines: list[list[str]], blank: str, bet_w: int) -> None:
term_w = shutil.get_terminal_size((120, 24)).columns
n_cols = max(1, term_w // (_BET_W + len(_GAP)))
row_w = min(term_w, n_cols * (_BET_W + len(_GAP)) - len(_GAP) + 2)
header = f" Ticket {link_ticket.id} — link: {n_link} bet{'s' if n_link != 1 else ''} │ img: {n_img} bet{'s' if n_img != 1 else ''}"
n_cols = max(1, term_w // (bet_w + len(_GAP)))
row_w = min(term_w, n_cols * (bet_w + len(_GAP)) - len(_GAP) + 2)
print(f"\n{'' * row_w}")
print(_ansi.bold(header))
print(_ansi.bold(f" {ticket_header}"))
print(f"{'' * row_w}")
all_lines = [
_bet_to_lines(i + 1, link_ticket.bets[i] if i < n_link else None, img_ticket.bets[i] if i < n_img else None)
for i in range(n_max)
]
for start in range(0, n_max, n_cols):
for start in range(0, len(all_lines), n_cols):
chunk = all_lines[start:start + n_cols]
max_h = max(len(b) for b in chunk)
padded = [_pad_to(b, max_h) for b in chunk]
padded = [_pad_to(b, max_h, blank) for b in chunk]
print()
for row in zip(*padded):
print(" " + _GAP.join(row))
# ── public print functions ────────────────────────────────────────────────────
def _print_compare(link_ticket: Ticket, img_ticket: Ticket) -> None:
n_link, n_img = len(link_ticket.bets), len(img_ticket.bets)
header = f"Ticket {link_ticket.id} — link: {n_link} bet{'s' if n_link != 1 else ''} │ img: {n_img} bet{'s' if n_img != 1 else ''}"
all_lines = [
_bet_to_lines(i + 1, link_ticket.bets[i] if i < n_link else None, img_ticket.bets[i] if i < n_img else None)
for i in range(max(n_link, n_img))
]
_print_bet_grid(header, all_lines, _BLANK_ROW, _BET_W)
def _print_single(ticket: Ticket, col_label: str) -> None:
n = len(ticket.bets)
header = f"Ticket {ticket.id}{col_label}{n} bet{'s' if n != 1 else ''}"
all_lines = [_bet_to_lines_single(i + 1, ticket.bets[i], col_label) for i in range(n)]
_print_bet_grid(header, all_lines, _BLANK_ROWS, _BET_WS)
def load_config(path: str) -> Config | None:
with open(path) as f:
config_dict = yaml.safe_load(f)
@@ -145,7 +172,9 @@ def main() -> None:
parser = argparse.ArgumentParser(prog="beaky")
parser.add_argument("--config", help="Path to config file.", default="config/application.yml")
parser.add_argument("--id", type=int, help="Select a single ticket by id.")
parser.add_argument("mode", choices=["screen", "parse", "class", "resolve", "compare"], help="Mode of operation.")
parser.add_argument("mode", choices=["screen", "parse", "compare", "resolve"], help="Mode of operation.")
parser.add_argument("--classifier", choices=["link", "img", "both"], default="both",
help="Which classifier to use in compare mode (default: both).")
args = parser.parse_args()
config = load_config(args.config)
@@ -179,24 +208,19 @@ def main() -> None:
for link in selected_links:
print(link)
if args.mode == "class":
classifier = LinkClassifier()
results = []
for link in selected_links:
results.append(classifier.classify(link))
ticket = results[-1]
print(f"\n=== Link {ticket.id} ({len(ticket.bets)} bets) ===")
for bet in ticket.bets:
print(f" [{type(bet).__name__}]")
for k, v in vars(bet).items():
print(f" {k}: {v}")
if args.mode == "compare":
linkclassifier = LinkClassifier()
use_link = args.classifier in ("link", "both")
use_img = args.classifier in ("img", "both")
linkclassifier = LinkClassifier() if use_link else None
for link in selected_links:
link_ticket = linkclassifier.classify(link)
img_ticket = img_classify([f"./data/screenshots/{link.id}.png"], ticket_id=link.id)
link_ticket = linkclassifier.classify(link) if use_link else None
img_ticket = img_classify([f"./data/screenshots/{link.id}.png"], ticket_id=link.id) if use_img else None
if args.classifier == "both" and link_ticket and img_ticket:
_print_compare(link_ticket, img_ticket)
elif link_ticket:
_print_single(link_ticket, "link classifier")
elif img_ticket:
_print_single(img_ticket, "image classifier")
if args.mode == "resolve":
classifier = LinkClassifier()