Hackathon Project Story
Inspiration
From countless phone calls to far too many debates on what we should do for the hackathon, our idea was like nothing we had ever discussed.
After getting off a plane with a few hours of sleep and walking to the nearest IHOP, we read the challenges that the different sponsors were hosting.
Initially planning something medical-related turned into a conversation on how we could enhance the sports experience for the average person and make someone who doesn’t even know the difference between American football and European football the next Kirk Herbstreit.
What We Learned
A new experience for us, React Native—although similar to React—proved to bring new challenges in creating a mobile app.
However, through trial and error, our first app saying Hello World was up in a matter of 30 minutes.
Now came the hard part: actually creating the full working model that we had dreamed of.
How We Built It
Our idea focused on generating content from a live feed that analyzed if a play was deemed worthy of being categorized as a highlight and placed on a user’s feed.
This became challenging to find, so we had to improvise and found a sample NFL game on YouTube featuring the Baltimore Ravens against the Detroit Lions.
To compose the information associated with the play and really help the user contextualize what is going on, we used the SportsRadar API, which gave us play-by-play data on exactly what happened in this game.
Then the process is as such:
- Extract the audio from the real-time feed to understand what the commentator is saying.
- Combine this with SportsRadar play-by-play data to determine if the play should be shown to the user as a highlight.
- If this was successful, the user would see a generated “reel” on their feed, with an option of swiping right to learn more about the play.
Challenges We Faced
In terms of challenges, a big learning curve was around seeing how we could access the game ID and then integrate the API calls within our backend.
To work around this, we thoroughly studied how SportsRadar worked by reading their documentation and learning how to set up and make an API call.
It was also important to make sure that our backend was functioning properly and able to correctly communicate with our frontend.
After verifying this and learning the steps to use an API call, the process became straightforward.
Reflections
While we couldn’t say this was the easiest thing we’ve done, it was definitely one of the most rewarding experiences we’ve been through.
We were able to learn a lot about app development, improve our technical skills, and gain confidence in building something new from the ground up.
Code Snippets
// 1. Fetching JSON Data from API
async function fetchJson(url) {
console.log(Fetching: ${url});
if (!fetchFn) {
throw new Error("No fetch implementation available. Install node-fetch@2 or run on Node 18+ which includes global fetch.");
}
const r = await fetchFn(url);
if (!r.ok) {
const text = await r.text();
const err = new Error(Sportradar HTTP ${r.status}: ${text});
err.status = r.status;
throw err;
}
return r.json();
}
The fetchJson function makes an HTTP request to a given URL and returns the response as JSON. If the request fails, it throws an error message for debugging.
- Getting Play-by-Play Data
async function getPlayByPlay(gameId, language = "en") {
const url = ${SPORTS_RADAR_BASE}/nfl/official/trial/v7/${language}/games/${encodeURIComponent(gameId)}/pbp.json?${qs({ api_key: SPORTS_RADAR_KEY })};
const data = await fetchJson(url);
console.log(Received play-by-play data for game ${gameId});
return data;
}
The code above retrieves play-by-play data by calling the SportsRadar API. It returns a detailed JSON object with all the events of the game, which the backend then uses for further processing.
Challenges We Faced
In terms of challenges, a big learning curve was around seeing how we could access the game ID and then integrate the API calls within our backend.
To work around this, we thoroughly studied how SportsRadar worked by reading their documentation and learning how to set up and make an API call.
It was also important to make sure that our backend was functioning properly and able to correctly communicate with our frontend.
After verifying this and learning the steps to use an API call, the process became straightforward.
Reflections
While we couldn’t say this was the easiest thing we’ve done, it was definitely one of the most rewarding experiences we’ve been through.
We were able to learn a lot about app development, improve our technical skills, and gain confidence in building something new from the ground up.
Code Snippets
1.Fetching JSON Data from API
async function fetchJson(url) {
console.log(`Fetching: ${url}`);
if (!fetchFn) {
throw new Error("No fetch implementation available. Install node-fetch@2 or run on Node 18+ which includes global fetch.");
}
const r = await fetchFn(url);
if (!r.ok) {
const text = await r.text();
const err = new Error(`Sportradar HTTP ${r.status}: ${text}`);
err.status = r.status;
throw err;
}
return r.json();
}
The fetchJson function makes an HTTP request to a given URL and returns
the response as JSON. If the request fails, it throws a error message for
debugging.
2. Getting Play-by-Play Data
```javascript
async function getPlayByPlay(gameId, language = "en") {
const url = `${SPORTS_RADAR_BASE}/nfl/official/trial/v7/${language}/games/${encodeURIComponent(gameId)}/pbp.json?${qs({ api_key: SPORTS_RADAR_KEY })}`;
const data = await fetchJson(url);
console.log(`Received play-by-play data for game ${gameId}`);
return data;
}
The code above retrieves play-by-play data by calling the SportsRadar API.
It returns a detailed JSON object with all the events of the game, which the backend then uses for further processing.
3. Evaluating Plays with Gemini AI
```javascript
// Evaluate a play using Google Gemini AI
async function evaluatePlay({ playMeta, transcript }) {
const prompt = `
You are a sports-play classifier. Given the following play information and
the announcer's commentary transcript, decide if this play is a highlight.
Return ONLY a JSON object with:
- goodPlay: true or false
- reason: a short explanation
- score: confidence from 0..1
Play metadata:
${JSON.stringify(playMeta, null, 2)}
Commentary transcript:
"""${transcript}"""
`;
try {
// Send the prompt to Gemini
const response = await aiClient.models.generateContent({
model: "gemini-2.5-flash",
contents: prompt,
});
// Extract JSON result from Gemini response
const text = response?.text || "";
const match = text.match(/\{[\s\S]*\}$/);
return match ? JSON.parse(match[0]) : { goodPlay: false, reason: "Could not parse response", score: 0 };
} catch (err) {
console.error("AI evaluation error:", err.message);
return { goodPlay: false, reason: "AI evaluation error", score: 0 };
}
}
The function sends both the play metadata and commentary transcript to Gemini AI,
which then analyzes the information and returns a JSON object.
This object includes three key fields:
- `goodPlay`: Indicates whether the play is highlight-worthy.
- `reason`: Provides a brief explanation for the decision.
- `score`: Represents a confidence level between 0 and 1.
This process allows the system to automatically filter plays
and generate highlight reels in real time

Log in or sign up for Devpost to join the conversation.