ryanbalch commited on
Commit
6b65dee
·
1 Parent(s): 6a7f780

add highlights/timeline for games

Browse files
api/scripts/create_game_highlights.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openai import OpenAI
2
+ import base64
3
+ from model_player import Player
4
+ import json
5
+
6
+ client = OpenAI()
7
+
8
+
9
+ def get_ai_response(prompt):
10
+ response = client.responses.create(
11
+ model="gpt-4o",
12
+ input=prompt
13
+ )
14
+ return response.output_text
15
+
16
+
17
+ def player_to_dict(player):
18
+ return {
19
+ "name": player.name,
20
+ "position": player.position,
21
+ "shirt_number": player.shirt_number,
22
+ "preferred_foot": player.preferred_foot,
23
+ "role": player.role,
24
+ "form": player.form,
25
+ }
26
+
27
+
28
+ prompt = """
29
+ You are simulating a fictional soccer match and creating a realistic event timeline from kickoff to final whistle.
30
+
31
+ Here is the match context:
32
+ - Match type: {match_type}
33
+ - Location: {location}
34
+ - Date: {date}
35
+ - Home team: {home_team}
36
+ - Away team: {away_team}
37
+ - Winner: {winner}
38
+ - Score: {score}
39
+
40
+ Here is the {home_team} roster:
41
+ {home_roster}
42
+
43
+ Here is the {away_team} roster:
44
+ {away_roster}
45
+
46
+ Rules:
47
+ - Spread out events across 90+ minutes
48
+ - Substitutions should use players not in the starting 11 if available
49
+ - Vary event types and timing
50
+
51
+ Only return a JSON array of chronological match events, formatted exactly like this example:
52
+
53
+ [
54
+ {{
55
+ "minute": // string, e.g. 45+2
56
+ "team": // home or away team name
57
+ "event": // e.g. Goal, Yellow Card, Substitution, etc.
58
+ "player": // name + number
59
+ "description": // 1-sentence summary
60
+ }}
61
+ ]
62
+ """
63
+
64
+
65
+ # # match 1
66
+ # match_type = "semifinal 1"
67
+ # location = "El Templo del Sol (fictional stadium in Mérida, Mexico)"
68
+ # date = "July 10, 2025"
69
+ # home_team = Player.teams[2]
70
+ # away_team = Player.teams[3]
71
+ # winner = Player.teams[2]
72
+ # score = "2–1"
73
+ # home_roster = None
74
+ # away_roster = None
75
+
76
+
77
+ # match 2
78
+ match_type = "semifinal 2"
79
+ location = "Everglade Arena (fictional stadium in Miami, Florida)"
80
+ date = "July 11, 2025"
81
+ home_team = Player.teams[1]
82
+ away_team = Player.teams[0]
83
+ winner = Player.teams[1]
84
+ score = "3-3 (4-2 pens)"
85
+ home_roster = None
86
+ away_roster = None
87
+
88
+ home_players = Player.get_players(team=home_team)
89
+ away_players = Player.get_players(team=away_team)
90
+
91
+ home_roster = [player_to_dict(player) for player in home_players]
92
+ away_roster = [player_to_dict(player) for player in away_players]
93
+
94
+ prompt = prompt.format(
95
+ match_type=match_type,
96
+ location=location,
97
+ date=date,
98
+ home_team=home_team,
99
+ away_team=away_team,
100
+ home_roster=home_roster,
101
+ away_roster=away_roster,
102
+ winner=winner,
103
+ score=score,
104
+ )
105
+
106
+ # print(prompt)
107
+
108
+ response = get_ai_response(prompt)
109
+
110
+ # Parse the AI response as JSON
111
+ try:
112
+ if response.startswith("```json") and response.endswith("```"):
113
+ response = response[7:-3]
114
+ events = json.loads(response)
115
+ except Exception as e:
116
+ print("Error parsing AI response as JSON:", e)
117
+ print("Raw response was:\n", response)
118
+ raise
119
+
120
+ # Pretty-print JSON to terminal
121
+ print(json.dumps(events, indent=4, sort_keys=True))
122
+
123
+ # Write pretty JSON to file
124
+ with open(f"/workspace/data/huge-league/games/{match_type.replace(' ', '_')}.json", "w") as f:
125
+ json.dump(events, f, indent=4, sort_keys=True)
126
+
127
+ # Optionally, if you want a more human-readable text format, uncomment below:
128
+ # def pretty_print_events(events):
129
+ # for event in events:
130
+ # print(f"[{event['minute']}] {event['team']} - {event['event']} - {event['player']}: {event['description']}")
131
+ # pretty_print_events(events)
132
+
api/scripts/model_player.py CHANGED
@@ -1,11 +1,12 @@
1
  import os
2
  import json
3
  from pydantic import BaseModel, Field, ValidationError
4
- from typing import Literal, Optional
5
  import hashlib
6
 
7
 
8
  class Player(BaseModel):
 
9
  number: int
10
  name: str
11
  age: int
@@ -87,9 +88,12 @@ class Player(BaseModel):
87
  return cls.model_validate(data)
88
 
89
  @classmethod
90
- def get_players(cls):
91
  for filename in os.listdir("/workspace/data/huge-league/players"):
92
- yield cls.load(filename)
 
 
 
93
 
94
  def save_image(self, image_bytes):
95
  filename = self.filename.replace(".json", ".png")
 
1
  import os
2
  import json
3
  from pydantic import BaseModel, Field, ValidationError
4
+ from typing import Literal, Optional, ClassVar
5
  import hashlib
6
 
7
 
8
  class Player(BaseModel):
9
+ teams: ClassVar[list[str]] = ['Fraser Valley United', 'Everglade FC', 'Yucatan Force', 'Tierra Alta FC']
10
  number: int
11
  name: str
12
  age: int
 
88
  return cls.model_validate(data)
89
 
90
  @classmethod
91
+ def get_players(cls, team=None):
92
  for filename in os.listdir("/workspace/data/huge-league/players"):
93
+ player = cls.load(filename)
94
+ if team and player.team != team:
95
+ continue
96
+ yield player
97
 
98
  def save_image(self, image_bytes):
99
  filename = self.filename.replace(".json", ".png")
data/huge-league/games/semifinal_1.json ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "description": "Ram\u00f3n Jim\u00e9nez scored with a powerful left-footed strike from the edge of the box.",
4
+ "event": "Goal",
5
+ "minute": "12",
6
+ "player": "Ram\u00f3n Jim\u00e9nez #10",
7
+ "team": "Yucatan Force"
8
+ },
9
+ {
10
+ "description": "Ricardo Cordero received a yellow card for a late tackle on Jos\u00e9 Delgado.",
11
+ "event": "Yellow Card",
12
+ "minute": "28",
13
+ "player": "Ricardo Cordero #5",
14
+ "team": "Tierra Alta FC"
15
+ },
16
+ {
17
+ "description": "Felipe Z\u00fa\u00f1iga equalized with a header from a cross by Gabriel Fonseca.",
18
+ "event": "Goal",
19
+ "minute": "34",
20
+ "player": "Felipe Z\u00fa\u00f1iga #10",
21
+ "team": "Tierra Alta FC"
22
+ },
23
+ {
24
+ "description": "Javier Mart\u00ednez replaced Ram\u00f3n S\u00e1nchez to add more width to the attack.",
25
+ "event": "Substitution",
26
+ "minute": "45+1",
27
+ "player": "Javier Mart\u00ednez #20",
28
+ "team": "Yucatan Force"
29
+ },
30
+ {
31
+ "description": "Jos\u00e9 Delgado curled in a stunning right-foot shot from outside the box.",
32
+ "event": "Goal",
33
+ "minute": "54",
34
+ "player": "Jos\u00e9 Delgado #11",
35
+ "team": "Yucatan Force"
36
+ },
37
+ {
38
+ "description": "Leonardo Salazar came on for Esteban Camacho to inject fresh energy into the attack.",
39
+ "event": "Substitution",
40
+ "minute": "67",
41
+ "player": "Leonardo Salazar #18",
42
+ "team": "Tierra Alta FC"
43
+ },
44
+ {
45
+ "description": "Santiago Ortega was booked for a tactical foul on Joaqu\u00edn Araya.",
46
+ "event": "Yellow Card",
47
+ "minute": "70",
48
+ "player": "Santiago Ortega #7",
49
+ "team": "Yucatan Force"
50
+ },
51
+ {
52
+ "description": "Sebasti\u00e1n Alvarado replaced Mauricio P\u00e9rez to bolster the midfield.",
53
+ "event": "Substitution",
54
+ "minute": "79",
55
+ "player": "Sebasti\u00e1n Alvarado #20",
56
+ "team": "Tierra Alta FC"
57
+ },
58
+ {
59
+ "description": "Emilio Navarro came on for H\u00e9ctor L\u00f3pez to help secure the lead.",
60
+ "event": "Substitution",
61
+ "minute": "85",
62
+ "player": "Emilio Navarro #18",
63
+ "team": "Yucatan Force"
64
+ },
65
+ {
66
+ "description": "Pablo Ure\u00f1a received a caution for dissent after a disputed throw-in call.",
67
+ "event": "Yellow Card",
68
+ "minute": "90+3",
69
+ "player": "Pablo Ure\u00f1a #8",
70
+ "team": "Tierra Alta FC"
71
+ }
72
+ ]
data/huge-league/games/semifinal_2.json ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "description": "Lucas Harris cuts in from the right wing and curls a shot into the far corner.",
4
+ "event": "Goal",
5
+ "minute": "5",
6
+ "player": "Lucas Harris 11",
7
+ "team": "Fraser Valley United"
8
+ },
9
+ {
10
+ "description": "Brandon Hernandez receives a yellow card for a late tackle on Mason Walker.",
11
+ "event": "Yellow Card",
12
+ "minute": "16",
13
+ "player": "Brandon Hernandez 5",
14
+ "team": "Everglade FC"
15
+ },
16
+ {
17
+ "description": "Ryan Williams equalizes with a powerful header from a corner delivered by Michael Smith.",
18
+ "event": "Goal",
19
+ "minute": "28",
20
+ "player": "Ryan Williams 7",
21
+ "team": "Everglade FC"
22
+ },
23
+ {
24
+ "description": "Elijah Gagnon comes on for Thomas Walker to add fresh legs up front.",
25
+ "event": "Substitution",
26
+ "minute": "33",
27
+ "player": "Elijah Gagnon 19",
28
+ "team": "Fraser Valley United"
29
+ },
30
+ {
31
+ "description": "Andrew Anderson gives Everglade FC the lead with a finesse shot from the left side.",
32
+ "event": "Goal",
33
+ "minute": "41",
34
+ "player": "Andrew Anderson 9",
35
+ "team": "Everglade FC"
36
+ },
37
+ {
38
+ "description": "Jacob Thompson is booked for dissent following a controversial foul call.",
39
+ "event": "Yellow Card",
40
+ "minute": "45+1",
41
+ "player": "Jacob Thompson 4",
42
+ "team": "Fraser Valley United"
43
+ },
44
+ {
45
+ "description": "Thomas Brown levels the score with a spectacular long-range strike.",
46
+ "event": "Goal",
47
+ "minute": "56",
48
+ "player": "Thomas Brown 7",
49
+ "team": "Fraser Valley United"
50
+ },
51
+ {
52
+ "description": "Ryan Brown replaces Michael Smith to add energy on the right wing.",
53
+ "event": "Substitution",
54
+ "minute": "63",
55
+ "player": "Ryan Brown 21",
56
+ "team": "Everglade FC"
57
+ },
58
+ {
59
+ "description": "Owen Campbell is brought on for Mason Walker to bolster the midfield.",
60
+ "event": "Substitution",
61
+ "minute": "74",
62
+ "player": "Owen Campbell 17",
63
+ "team": "Fraser Valley United"
64
+ },
65
+ {
66
+ "description": "Elijah Gagnon puts Fraser Valley United ahead with a close-range finish.",
67
+ "event": "Goal",
68
+ "minute": "80",
69
+ "player": "Elijah Gagnon 19",
70
+ "team": "Fraser Valley United"
71
+ },
72
+ {
73
+ "description": "Matthew Martin equalizes in dramatic fashion with a header from a free-kick.",
74
+ "event": "Goal",
75
+ "minute": "87",
76
+ "player": "Matthew Martin 10",
77
+ "team": "Everglade FC"
78
+ },
79
+ {
80
+ "description": "Joseph Thomas enters for Austin Jackson to strengthen the team's defense.",
81
+ "event": "Substitution",
82
+ "minute": "90+3",
83
+ "player": "Joseph Thomas 15",
84
+ "team": "Everglade FC"
85
+ },
86
+ {
87
+ "description": "Ryan Williams receives a yellow card for time-wasting.",
88
+ "event": "Yellow Card",
89
+ "minute": "90+5",
90
+ "player": "Ryan Williams 7",
91
+ "team": "Everglade FC"
92
+ },
93
+ {
94
+ "description": "Everglade FC wins the penalty shootout 4-2, securing a spot in the final.",
95
+ "event": "Penalty Shootout",
96
+ "minute": "Full-Time",
97
+ "player": "Various",
98
+ "team": "Everglade FC"
99
+ }
100
+ ]