Spaces:
Configuration error
Configuration error
Download src/build_booklet.py from Brettapps/Trifecta-Lab: direct link, hf CLI and curl.
- Browser
- Download file 6.36 kB
-
https://huggingface.co/spaces/Brettapps/Trifecta-Lab/resolve/main/src/build_booklet.py
- Command line
-
hf download hf://spaces/Brettapps/Trifecta-Lab/src/build_booklet.py
-
curl -L -o build_booklet.py https://huggingface.co/spaces/Brettapps/Trifecta-Lab/resolve/main/src/build_booklet.py
6.36 kB
| """Generate PDF booklet for Trifecta-Bro predictions.""" | |
| from __future__ import annotations | |
| from pathlib import Path | |
| from typing import Any | |
| from reportlab.lib import colors | |
| from reportlab.lib.pagesizes import A4 | |
| from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle | |
| from reportlab.lib.units import mm | |
| from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer | |
| from src.prediction_model import Race, Runner, TrifectaPredictor | |
| TITLE = "Trifecta-Bro" | |
| SUBTITLE = "Australian Gallops Prediction Booklet" | |
| def build_booklet(races: list[dict[str, Any]], output_path: Path) -> Path: | |
| predictor = TrifectaPredictor() | |
| doc = SimpleDocTemplate( | |
| str(output_path), | |
| pagesize=A4, | |
| title=TITLE, | |
| author="Trifecta-Bro", | |
| ) | |
| styles = getSampleStyleSheet() | |
| title_style = ParagraphStyle( | |
| "TBTitle", | |
| parent=styles["Title"], | |
| fontSize=22, | |
| textColor=colors.HexColor("#111827"), | |
| spaceAfter=4, | |
| ) | |
| subtitle_style = ParagraphStyle( | |
| "TBSubtitle", | |
| parent=styles["Normal"], | |
| fontSize=10, | |
| textColor=colors.HexColor("#6B7280"), | |
| spaceAfter=12, | |
| ) | |
| heading_style = ParagraphStyle( | |
| "TBHeading", | |
| parent=styles["Heading2"], | |
| fontSize=14, | |
| textColor=colors.HexColor("#0F172A"), | |
| spaceAfter=6, | |
| ) | |
| body_style = ParagraphStyle( | |
| "TBBody", | |
| parent=styles["Normal"], | |
| fontSize=9, | |
| leading=12, | |
| ) | |
| story: list[Any] = [ | |
| Paragraph(TITLE, title_style), | |
| Paragraph(SUBTITLE, subtitle_style), | |
| Spacer(1, 4 * mm), | |
| ] | |
| for race_payload in races: | |
| race = _to_race(race_payload) | |
| story.append(Paragraph(f"Race {race.race_number}: {race.race_name}", heading_style)) | |
| meta = Table( | |
| [ | |
| ["Distance", race.distance, "Condition", race.condition], | |
| ["Weather", race.weather or "", "Class", race.race_class], | |
| ["Prize", f"${race.prize_money}", "Runners", str(race.number_of_runners)], | |
| ], | |
| colWidths=[28 * mm, 45 * mm, 28 * mm, 45 * mm], | |
| ) | |
| meta.setStyle(TableStyle([ | |
| ("FONTNAME", (0, 0), (-1, -1), "Helvetica"), | |
| ("FONTSIZE", (0, 0), (-1, -1), 8), | |
| ("BACKGROUND", (0, 0), (0, -1), colors.HexColor("#F3F4F6")), | |
| ("BACKGROUND", (2, 0), (2, -1), colors.HexColor("#F3F4F6")), | |
| ("LEFTPADDING", (0, 0), (-1, -1), 6), | |
| ("RIGHTPADDING", (0, 0), (-1, -1), 6), | |
| ("TOPPADDING", (0, 0), (-1, -1), 4), | |
| ("BOTTOMPADDING", (0, 0), (-1, -1), 4), | |
| ("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#E5E7EB")), | |
| ])) | |
| story.append(meta) | |
| story.append(Spacer(1, 4 * mm)) | |
| prediction = predictor.predict(race) | |
| if "error" in prediction: | |
| story.append(Paragraph(f"Prediction unavailable: {prediction['error']}", body_style)) | |
| story.append(Spacer(1, 6 * mm)) | |
| continue | |
| trifecta_table = Table( | |
| [ | |
| ["Primary", prediction.get("primary", "")], | |
| ["Secondary", prediction.get("secondary") or "-"], | |
| ["Value", prediction.get("value") or "-"], | |
| ], | |
| colWidths=[32 * mm, 114 * mm], | |
| ) | |
| trifecta_table.setStyle(TableStyle([ | |
| ("FONTNAME", (0, 0), (-1, -1), "Helvetica-Bold"), | |
| ("FONTSIZE", (0, 0), (-1, -1), 9), | |
| ("BACKGROUND", (0, 0), (0, -1), colors.HexColor("#0F172A")), | |
| ("TEXTCOLOR", (0, 0), (0, -1), colors.white), | |
| ("LEFTPADDING", (0, 0), (-1, -1), 6), | |
| ("TOPPADDING", (0, 0), (-1, -1), 5), | |
| ("BOTTOMPADDING", (0, 0), (-1, -1), 5), | |
| ("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#E5E7EB")), | |
| ])) | |
| story.append(trifecta_table) | |
| story.append(Spacer(1, 4 * mm)) | |
| runner_rows = [[ | |
| "#", "Horse", "Form", "Score", "Win%", "Place%", "Bar", "Jockey" | |
| ]] | |
| for item in prediction.get("top3", []): | |
| runner_rows.append([ | |
| str(item["number"]), | |
| item["name"], | |
| "", | |
| str(item["score"]), | |
| f"{item['win_prob']:.0f}%", | |
| f"{item['place_prob']:.0f}%", | |
| "", | |
| "", | |
| ]) | |
| runner_table = Table(runner_rows, repeatRows=1) | |
| runner_table.setStyle(TableStyle([ | |
| ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"), | |
| ("FONTSIZE", (0, 0), (-1, -1), 8), | |
| ("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#F3F4F6")), | |
| ("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#E5E7EB")), | |
| ("LEFTPADDING", (0, 0), (-1, -1), 5), | |
| ("TOPPADDING", (0, 0), (-1, -1), 4), | |
| ("BOTTOMPADDING", (0, 0), (-1, -1), 4), | |
| ])) | |
| story.append(runner_table) | |
| story.append(Spacer(1, 6 * mm)) | |
| doc.build(story) | |
| return output_path | |
| def _to_race(payload: dict[str, Any]) -> Race: | |
| form = payload.get("form", {}) | |
| runners = [] | |
| for r in form.get("runners", []): | |
| runners.append(Runner( | |
| number=r.get("number", 0), | |
| name=r.get("name", ""), | |
| jockey=r.get("jockey", ""), | |
| trainer=r.get("trainer", ""), | |
| weight=r.get("weight"), | |
| barrier=r.get("barrier"), | |
| form=r.get("form", ""), | |
| last20Starts=r.get("last20Starts", ""), | |
| careerPrizeMoney=r.get("careerPrizeMoney", "$0"), | |
| scratched=bool(r.get("scratched", False)), | |
| stats=r.get("stats", {}), | |
| )) | |
| return Race( | |
| date=payload.get("date", ""), | |
| track=payload.get("track", ""), | |
| track_slug=payload.get("track_slug", ""), | |
| race_number=str(payload.get("race_number", "")), | |
| race_name=payload.get("race_name", ""), | |
| distance=payload.get("distance", ""), | |
| condition=payload.get("condition", ""), | |
| weather=payload.get("weather", ""), | |
| race_class=payload.get("race_class", ""), | |
| start_time=payload.get("start_time", ""), | |
| prize_money=payload.get("prize_money", ""), | |
| number_of_runners=int(payload.get("number_of_runners", 0) or 0), | |
| runners=runners, | |
| ) | |