fix: render flat-logged hands + on-demand "build replay"
Quick-logged hands (log_hand) store flat fields with no structured JSON, so the
hand viewer dead-ended with "no structured data to replay" — even when the full
street-by-street action was captured (e.g. the KhQh-vs-Louis hand). Now:
- hand.html renders a readable STATIC view of any flat hand (hero cards, board,
street narratives, result, lesson) instead of erroring; also handles empty/garbage
structured rows by falling back to the flat view.
- "▶ Build replay" button + poker.reconstruct_hand + POST /hand/{id}/reconstruct:
parse a flat hand's narrative into structured form on demand, making any
quick-logged hand replayable without an LLM call per log during live play.
- test_modes.py +1 (reconstruct wiring).
(Also reconstructed the two live Meadows hands and removed one empty hand in the DB.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -713,6 +713,38 @@ def record_hand(shorthand: str, session_id: int | None = None, stakes: str | Non
|
||||
return {"id": hid, "parsed": parsed, "linked": linked}
|
||||
|
||||
|
||||
def reconstruct_hand(hand_id: int, backend: str | None = None) -> dict | None:
|
||||
"""Upgrade a flat (log_hand) hand into a structured, replayable one by parsing
|
||||
its captured street narratives. On-demand so quick-logged live hands can become
|
||||
replayable without an LLM call per log during play."""
|
||||
h = get_hand(hand_id)
|
||||
if not h:
|
||||
return None
|
||||
parts = []
|
||||
if h.get("position") or h.get("hole_cards"):
|
||||
parts.append(f"Hero is {h.get('position') or '?'} with {h.get('hole_cards') or 'unknown'}.")
|
||||
for st in ("preflop", "flop", "turn", "river", "showdown"):
|
||||
if h.get(st):
|
||||
parts.append(f"{st.capitalize()}: {h[st]}")
|
||||
if h.get("board"):
|
||||
parts.append(f"Final board: {h['board']}.")
|
||||
if h.get("result") is not None:
|
||||
parts.append(f"Hero net result: {h['result']}.")
|
||||
shorthand = " ".join(parts).strip()
|
||||
if not shorthand:
|
||||
return None
|
||||
parsed = parse_hand(shorthand, backend=backend)
|
||||
if not parsed:
|
||||
return None
|
||||
parsed = _normalize_parsed(parsed)
|
||||
conn = _c()
|
||||
with conn:
|
||||
conn.execute("UPDATE poker_hands SET structured = ? WHERE id = ?",
|
||||
(json.dumps(parsed), hand_id))
|
||||
link_hand_players(hand_id, parsed, session_id=h.get("session_id"))
|
||||
return {"id": hand_id, "parsed": parsed}
|
||||
|
||||
|
||||
def get_hand(hand_id: int) -> dict | None:
|
||||
"""A stored hand with its structured JSON parsed back into a dict."""
|
||||
r = _c().execute("SELECT * FROM poker_hands WHERE id = ?", (hand_id,)).fetchone()
|
||||
|
||||
Reference in New Issue
Block a user