-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathREADME.html
352 lines (334 loc) · 16.9 KB
/
README.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head>
<meta charset="utf-8">
<meta name="generator" content="quarto-1.3.450">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>readme</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
ul.task-list li input[type="checkbox"] {
width: 0.8em;
margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */
vertical-align: middle;
}
</style>
<script src="README_files/libs/clipboard/clipboard.min.js"></script>
<script src="README_files/libs/quarto-html/quarto.js"></script>
<script src="README_files/libs/quarto-html/popper.min.js"></script>
<script src="README_files/libs/quarto-html/tippy.umd.min.js"></script>
<script src="README_files/libs/quarto-html/anchor.min.js"></script>
<link href="README_files/libs/quarto-html/tippy.css" rel="stylesheet">
<link href="README_files/libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles">
<script src="README_files/libs/bootstrap/bootstrap.min.js"></script>
<link href="README_files/libs/bootstrap/bootstrap-icons.css" rel="stylesheet">
<link href="README_files/libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light">
</head>
<body class="fullcontent">
<div id="quarto-content" class="page-columns page-rows-contents page-layout-article">
<main class="content" id="quarto-document-content">
<section id="duke-generative-ai-hackathon" class="level1">
<h1>DUKE GENERATIVE AI HACKATHON</h1>
</section>
<section id="nba-live-commentary-generator-with-gpt-4.0" class="level1">
<h1>NBA Live Commentary Generator with GPT-4.0</h1>
<section id="table-of-contents" class="level2">
<h2 class="anchored" data-anchor-id="table-of-contents">Table of Contents</h2>
<p>———- OPTIONAL ————- - <a href="#demo">Demo</a> - need to add a video or smth - <a href="#Overview">Overview</a> - <a href="#getting-started">Getting Started</a> - <a href="#prerequisites">Prerequisites</a> - <a href="#installation">Installation</a> - <a href="#usage">Usage</a> - <a href="#api-integration">API Integration</a> - <a href="#running-the-commentary-generator">Running the Commentary Generator</a> - <a href="#contributing">Contributing</a> - <a href="#license">License</a></p>
</section>
<section id="overview" class="level2">
<h2 class="anchored" data-anchor-id="overview">Overview</h2>
<p>In the era of data-driven sports analysis and immersive fan experiences, our project aims to create an innovative solution that combines play-by-play data from the SportsRadar API and NBA API with the advanced language generation capabilities of GPT-4.0 from OpenAI. This collaboration results in a live commentary generator for NBA games that goes beyond traditional commentary by offering real-time insights and engagement with fans.</p>
<section id="problem-statement" class="level3">
<h3 class="anchored" data-anchor-id="problem-statement">Problem Statement</h3>
<p>Traditional sports commentary can sometimes fall short of capturing the excitement and intricacies of live NBA games. Often, fans rely on commentary that lacks in-depth analysis, and there’s room for improvement. Our project addresses this gap by providing live, dynamic, and insightful commentary for NBA games.</p>
</section>
<section id="key-features" class="level3">
<h3 class="anchored" data-anchor-id="key-features">Key Features</h3>
<ul>
<li><p><strong>Data Integration</strong>: We retrieve real-time play-by-play data from the SportsRadar and NBA APIs, including details on player actions, scores, and game statistics.</p></li>
<li><p><strong>Language Generation</strong>: We leverage the state-of-the-art GPT-4.0 model to transform raw data into coherent and engaging commentary. The model can provide context-aware insights, player statistics, historical comparisons, and even predict game outcomes based on the ongoing events.</p></li>
<li><p><strong>Real-time Updates</strong>: Our system constantly updates commentary as the game progresses, providing fans with the most up-to-date information and reactions to in-game developments.</p></li>
<li><p><strong>Multimodal Experience</strong>: In addition to textual commentary, we offer the option to convert the generated text into speech, creating a seamless and immersive experience for fans who prefer to listen to the commentary.</p></li>
<li><p><strong>Customization and Personalization</strong>: Users can choose the level of analysis and detail in commentary, allowing for a tailored experience, whether they’re casual fans or avid analysts.</p></li>
<li><p><strong>Cross-Platform Compatibility</strong>: The system can be integrated with websites, mobile apps, or even smart speakers, making it accessible to fans on a variety of platforms.</p></li>
</ul>
</section>
</section>
<section id="use-cases" class="level2">
<h2 class="anchored" data-anchor-id="use-cases">Use Cases</h2>
<ol type="1">
<li><p><strong>Immersive Fan Experience</strong>: Fans can access real-time commentary that goes beyond traditional play-by-play descriptions, making them feel more connected to the game.</p></li>
<li><p><strong>Enhanced Data Analysis</strong>: Analysts and coaches can use the system to gain deeper insights into team and player performance, including in-game strategy adjustments.</p></li>
<li><p><strong>Educational Tool</strong>: The commentary can serve as an educational resource for individuals interested in learning more about basketball and its strategies.</p></li>
<li><p><strong>Content Generation</strong>: Content creators can leverage the commentary to produce dynamic content, such as live blogs, podcasts, or video summaries.</p></li>
<li><p><strong>Accessible Sports Commentary</strong>: The text-to-speech feature ensures that commentary is accessible to individuals with visual impairments.</p></li>
</ol>
</section>
<section id="technical-details" class="level2">
<h2 class="anchored" data-anchor-id="technical-details">Technical Details</h2>
<ul>
<li><p>The project is implemented in Python, utilizing various libraries and APIs for data retrieval, processing, and text generation.</p></li>
<li><p>Data from the SportsRadar and NBA APIs is retrieved in real-time, and it’s structured to feed into the GPT-4.0 model.</p></li>
<li><p>The OpenAI API is used to interact with GPT-4.0 for text generation.</p></li>
<li><p>Text-to-speech capabilities can be integrated using libraries like <code>gTTS</code> (Google Text-to-Speech) or cloud-based services.</p></li>
<li><p>User interfaces can be developed for different platforms based on project requirements.</p></li>
</ul>
</section>
<section id="future-enhancements" class="level2">
<h2 class="anchored" data-anchor-id="future-enhancements">Future Enhancements</h2>
<ul>
<li><p><strong>Multilingual Support</strong>: Expanding commentary to support multiple languages to reach a broader audience.</p></li>
<li><p><strong>User Preferences</strong>: Allowing users to customize the commentary, such as choosing their favorite team or player to focus on.</p></li>
<li><p><strong>Predictive Analysis</strong>: Implementing more advanced algorithms to provide predictions and game insights based on historical data and current game dynamics.</p></li>
<li><p><strong>Integration with Smart Devices</strong>: Developing applications for smart speakers and other voice-controlled devices to provide a hands-free experience for users.</p></li>
<li><p><strong>Real-time Visualizations</strong>: Incorporating real-time graphs and visualizations to supplement the commentary.</p></li>
</ul>
</section>
<section id="conclusion" class="level2">
<h2 class="anchored" data-anchor-id="conclusion">Conclusion</h2>
<p>Our NBA Live Commentary Generator with GPT-4.0 project aims to revolutionize the way fans experience NBA games. By combining the power of real-time data with cutting-edge language generation, we offer a more engaging, insightful, and personalized experience for fans, analysts, and content creators. With a commitment to continuous improvement and innovation, we hope to enhance the world of sports commentary and analysis.</p>
<p>Feel free to adapt and expand upon this detailed overview to create a comprehensive and engaging description of your project for the hackathon.</p>
</section>
</section>
</main>
<!-- /main column -->
<script id="quarto-html-after-body" type="application/javascript">
window.document.addEventListener("DOMContentLoaded", function (event) {
const toggleBodyColorMode = (bsSheetEl) => {
const mode = bsSheetEl.getAttribute("data-mode");
const bodyEl = window.document.querySelector("body");
if (mode === "dark") {
bodyEl.classList.add("quarto-dark");
bodyEl.classList.remove("quarto-light");
} else {
bodyEl.classList.add("quarto-light");
bodyEl.classList.remove("quarto-dark");
}
}
const toggleBodyColorPrimary = () => {
const bsSheetEl = window.document.querySelector("link#quarto-bootstrap");
if (bsSheetEl) {
toggleBodyColorMode(bsSheetEl);
}
}
toggleBodyColorPrimary();
const icon = "";
const anchorJS = new window.AnchorJS();
anchorJS.options = {
placement: 'right',
icon: icon
};
anchorJS.add('.anchored');
const isCodeAnnotation = (el) => {
for (const clz of el.classList) {
if (clz.startsWith('code-annotation-')) {
return true;
}
}
return false;
}
const clipboard = new window.ClipboardJS('.code-copy-button', {
text: function(trigger) {
const codeEl = trigger.previousElementSibling.cloneNode(true);
for (const childEl of codeEl.children) {
if (isCodeAnnotation(childEl)) {
childEl.remove();
}
}
return codeEl.innerText;
}
});
clipboard.on('success', function(e) {
// button target
const button = e.trigger;
// don't keep focus
button.blur();
// flash "checked"
button.classList.add('code-copy-button-checked');
var currentTitle = button.getAttribute("title");
button.setAttribute("title", "Copied!");
let tooltip;
if (window.bootstrap) {
button.setAttribute("data-bs-toggle", "tooltip");
button.setAttribute("data-bs-placement", "left");
button.setAttribute("data-bs-title", "Copied!");
tooltip = new bootstrap.Tooltip(button,
{ trigger: "manual",
customClass: "code-copy-button-tooltip",
offset: [0, -8]});
tooltip.show();
}
setTimeout(function() {
if (tooltip) {
tooltip.hide();
button.removeAttribute("data-bs-title");
button.removeAttribute("data-bs-toggle");
button.removeAttribute("data-bs-placement");
}
button.setAttribute("title", currentTitle);
button.classList.remove('code-copy-button-checked');
}, 1000);
// clear code selection
e.clearSelection();
});
function tippyHover(el, contentFn) {
const config = {
allowHTML: true,
content: contentFn,
maxWidth: 500,
delay: 100,
arrow: false,
appendTo: function(el) {
return el.parentElement;
},
interactive: true,
interactiveBorder: 10,
theme: 'quarto',
placement: 'bottom-start'
};
window.tippy(el, config);
}
const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]');
for (var i=0; i<noterefs.length; i++) {
const ref = noterefs[i];
tippyHover(ref, function() {
// use id or data attribute instead here
let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href');
try { href = new URL(href).hash; } catch {}
const id = href.replace(/^#\/?/, "");
const note = window.document.getElementById(id);
return note.innerHTML;
});
}
let selectedAnnoteEl;
const selectorForAnnotation = ( cell, annotation) => {
let cellAttr = 'data-code-cell="' + cell + '"';
let lineAttr = 'data-code-annotation="' + annotation + '"';
const selector = 'span[' + cellAttr + '][' + lineAttr + ']';
return selector;
}
const selectCodeLines = (annoteEl) => {
const doc = window.document;
const targetCell = annoteEl.getAttribute("data-target-cell");
const targetAnnotation = annoteEl.getAttribute("data-target-annotation");
const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation));
const lines = annoteSpan.getAttribute("data-code-lines").split(",");
const lineIds = lines.map((line) => {
return targetCell + "-" + line;
})
let top = null;
let height = null;
let parent = null;
if (lineIds.length > 0) {
//compute the position of the single el (top and bottom and make a div)
const el = window.document.getElementById(lineIds[0]);
top = el.offsetTop;
height = el.offsetHeight;
parent = el.parentElement.parentElement;
if (lineIds.length > 1) {
const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]);
const bottom = lastEl.offsetTop + lastEl.offsetHeight;
height = bottom - top;
}
if (top !== null && height !== null && parent !== null) {
// cook up a div (if necessary) and position it
let div = window.document.getElementById("code-annotation-line-highlight");
if (div === null) {
div = window.document.createElement("div");
div.setAttribute("id", "code-annotation-line-highlight");
div.style.position = 'absolute';
parent.appendChild(div);
}
div.style.top = top - 2 + "px";
div.style.height = height + 4 + "px";
let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter");
if (gutterDiv === null) {
gutterDiv = window.document.createElement("div");
gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter");
gutterDiv.style.position = 'absolute';
const codeCell = window.document.getElementById(targetCell);
const gutter = codeCell.querySelector('.code-annotation-gutter');
gutter.appendChild(gutterDiv);
}
gutterDiv.style.top = top - 2 + "px";
gutterDiv.style.height = height + 4 + "px";
}
selectedAnnoteEl = annoteEl;
}
};
const unselectCodeLines = () => {
const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"];
elementsIds.forEach((elId) => {
const div = window.document.getElementById(elId);
if (div) {
div.remove();
}
});
selectedAnnoteEl = undefined;
};
// Attach click handler to the DT
const annoteDls = window.document.querySelectorAll('dt[data-target-cell]');
for (const annoteDlNode of annoteDls) {
annoteDlNode.addEventListener('click', (event) => {
const clickedEl = event.target;
if (clickedEl !== selectedAnnoteEl) {
unselectCodeLines();
const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active');
if (activeEl) {
activeEl.classList.remove('code-annotation-active');
}
selectCodeLines(clickedEl);
clickedEl.classList.add('code-annotation-active');
} else {
// Unselect the line
unselectCodeLines();
clickedEl.classList.remove('code-annotation-active');
}
});
}
const findCites = (el) => {
const parentEl = el.parentElement;
if (parentEl) {
const cites = parentEl.dataset.cites;
if (cites) {
return {
el,
cites: cites.split(' ')
};
} else {
return findCites(el.parentElement)
}
} else {
return undefined;
}
};
var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]');
for (var i=0; i<bibliorefs.length; i++) {
const ref = bibliorefs[i];
const citeInfo = findCites(ref);
if (citeInfo) {
tippyHover(citeInfo.el, function() {
var popup = window.document.createElement('div');
citeInfo.cites.forEach(function(cite) {
var citeDiv = window.document.createElement('div');
citeDiv.classList.add('hanging-indent');
citeDiv.classList.add('csl-entry');
var biblioDiv = window.document.getElementById('ref-' + cite);
if (biblioDiv) {
citeDiv.innerHTML = biblioDiv.innerHTML;
}
popup.appendChild(citeDiv);
});
return popup.innerHTML;
});
}
}
});
</script>
</div> <!-- /content -->
</body></html>