DexterSptizu commited on
Commit
24d7598
·
verified ·
1 Parent(s): ceda103

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +250 -0
app.py ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ from openai import OpenAI
4
+ from PIL import Image
5
+ import io
6
+ import base64
7
+ import pandas as pd
8
+ import plotly.express as px
9
+ import plotly.graph_objects as go
10
+ import numpy as np
11
+
12
+ st.set_page_config(
13
+ page_title="Baseball Analytics Hub",
14
+ layout="wide",
15
+ initial_sidebar_state="expanded"
16
+ )
17
+
18
+ # Custom CSS for baseball theme
19
+ def apply_custom_css():
20
+ st.markdown("""
21
+ <style>
22
+ .stApp {
23
+ max-width: 1400px;
24
+ margin: 0 auto;
25
+ }
26
+ .upload-box {
27
+ border: 2px dashed #1E4C96;
28
+ border-radius: 10px;
29
+ padding: 20px;
30
+ text-align: center;
31
+ background-color: #f8f9fa;
32
+ }
33
+ .sidebar-content {
34
+ padding: 20px;
35
+ background-color: #1E4C96;
36
+ color: white;
37
+ border-radius: 10px;
38
+ }
39
+ .response-box {
40
+ background-color: #ffffff;
41
+ padding: 20px;
42
+ border-radius: 10px;
43
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
44
+ }
45
+ .title-text {
46
+ color: #1E4C96;
47
+ text-align: center;
48
+ font-size: 2.5rem;
49
+ margin-bottom: 2rem;
50
+ }
51
+ .stats-card {
52
+ background-color: #ffffff;
53
+ padding: 20px;
54
+ border-radius: 10px;
55
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
56
+ margin: 10px;
57
+ }
58
+ </style>
59
+ """, unsafe_allow_html=True)
60
+
61
+ def initialize_session_state():
62
+ if 'history' not in st.session_state:
63
+ st.session_state.history = []
64
+ if 'player_stats' not in st.session_state:
65
+ st.session_state.player_stats = {
66
+ 'batting_avg': [],
67
+ 'hits': [],
68
+ 'home_runs': [],
69
+ 'games': []
70
+ }
71
+
72
+ def encode_image_to_base64(image):
73
+ buffered = io.BytesIO()
74
+ image.save(buffered, format="PNG")
75
+ return base64.b64encode(buffered.getvalue()).decode('utf-8')
76
+
77
+ def analyze_image(image, question, api_key):
78
+ try:
79
+ client = OpenAI(api_key=api_key)
80
+ base64_image = encode_image_to_base64(image)
81
+
82
+ # Add baseball-specific context to the prompt
83
+ baseball_context = "Analyze this baseball-related image. Consider aspects like player stance, pitch mechanics, field positioning, and game situation. "
84
+ enhanced_question = baseball_context + question
85
+
86
+ completion = client.chat.completions.create(
87
+ model="gpt-4o-mini",
88
+ messages=[
89
+ {
90
+ "role": "user",
91
+ "content": [
92
+ {"type": "text", "text": enhanced_question},
93
+ {
94
+ "type": "image_url",
95
+ "image_url": {
96
+ "url": f"data:image/png;base64,{base64_image}"
97
+ }
98
+ },
99
+ ],
100
+ }
101
+ ],
102
+ max_tokens=500
103
+ )
104
+ return completion.choices[0].message.content
105
+ except Exception as e:
106
+ return f"Error: {str(e)}"
107
+
108
+ def plot_strike_zone():
109
+ fig = go.Figure()
110
+ fig.add_shape(
111
+ type="rect",
112
+ x0=-0.85, x1=0.85,
113
+ y0=1.5, y1=3.5,
114
+ line=dict(color="red", width=2),
115
+ fillcolor="rgba(255, 0, 0, 0.1)"
116
+ )
117
+ fig.add_trace(go.Scatter(
118
+ x=np.random.uniform(-1, 1, 10),
119
+ y=np.random.uniform(1, 4, 10),
120
+ mode='markers',
121
+ marker=dict(size=10, color='blue'),
122
+ name='Pitches'
123
+ ))
124
+ fig.update_layout(
125
+ title="Strike Zone Analysis",
126
+ xaxis_title="Horizontal Location (ft)",
127
+ yaxis_title="Height (ft)",
128
+ template="plotly_white"
129
+ )
130
+ return fig
131
+
132
+ def main():
133
+ apply_custom_css()
134
+ initialize_session_state()
135
+
136
+ # Sidebar Configuration
137
+ with st.sidebar:
138
+ st.markdown('<div class="sidebar-content">', unsafe_allow_html=True)
139
+ st.header("⚾ Baseball Analytics")
140
+ api_key = st.text_input("OpenAI API Key:", type="password")
141
+
142
+ st.markdown("### 🎯 Baseball Image Analysis")
143
+ quick_prompts = [
144
+ "Analyze the batting stance and suggest improvements",
145
+ "Evaluate the pitcher's mechanics",
146
+ "Analyze the fielding position and alignment",
147
+ "Identify potential batting technique issues",
148
+ "Assess the base running form",
149
+ "Analyze the catcher's positioning",
150
+ "Evaluate the pitch grip technique"
151
+ ]
152
+ selected_prompt = st.selectbox("Select analysis type:", quick_prompts)
153
+ st.markdown("</div>", unsafe_allow_html=True)
154
+
155
+ # Main Content
156
+ st.markdown('<h1 class="title-text">⚾ Baseball Vision Analytics</h1>', unsafe_allow_html=True)
157
+
158
+ # Create tabs for different features
159
+ tab1, tab2 = st.tabs(["Image Analysis", "Performance Analytics"])
160
+
161
+ with tab1:
162
+ # Image Upload Section
163
+ col1, col2, col3 = st.columns([1, 2, 1])
164
+ with col2:
165
+ st.markdown('<div class="upload-box">', unsafe_allow_html=True)
166
+ uploaded_file = st.file_uploader(
167
+ "Upload baseball image for analysis",
168
+ type=['png', 'jpg', 'jpeg'],
169
+ help="Upload images of batting, pitching, or fielding"
170
+ )
171
+ st.markdown('</div>', unsafe_allow_html=True)
172
+
173
+ if uploaded_file:
174
+ image = Image.open(uploaded_file)
175
+
176
+ # Image Display and Analysis Section
177
+ col1, col2 = st.columns([1, 1])
178
+
179
+ with col1:
180
+ st.image(image, use_container_width=True, caption="Uploaded Baseball Image")
181
+
182
+ with col2:
183
+ st.markdown('<div class="response-box">', unsafe_allow_html=True)
184
+ question = st.text_input(
185
+ "Analysis Focus:",
186
+ value=selected_prompt,
187
+ key="question_input"
188
+ )
189
+
190
+ if st.button("🔍 Analyze", use_container_width=True):
191
+ if not api_key:
192
+ st.error("⚠️ Please enter your OpenAI API key in the sidebar.")
193
+ else:
194
+ with st.spinner("🔄 Analyzing baseball technique..."):
195
+ response = analyze_image(image, question, api_key)
196
+ st.markdown("### 📝 Analysis Result:")
197
+ st.write(response)
198
+
199
+ st.session_state.history.append({
200
+ "question": question,
201
+ "response": response,
202
+ "timestamp": pd.Timestamp.now().strftime("%Y-%m-%d %H:%M:%S")
203
+ })
204
+ st.markdown('</div>', unsafe_allow_html=True)
205
+
206
+ with tab2:
207
+ # Performance Analytics Section
208
+ col1, col2 = st.columns(2)
209
+
210
+ with col1:
211
+ st.markdown('<div class="stats-card">', unsafe_allow_html=True)
212
+ st.subheader("Strike Zone Analysis")
213
+ fig = plot_strike_zone()
214
+ st.plotly_chart(fig, use_container_width=True)
215
+ st.markdown('</div>', unsafe_allow_html=True)
216
+
217
+ with col2:
218
+ st.markdown('<div class="stats-card">', unsafe_allow_html=True)
219
+ st.subheader("Key Metrics")
220
+ metrics_col1, metrics_col2 = st.columns(2)
221
+ with metrics_col1:
222
+ st.metric("Pitch Accuracy", "68%", "+2%")
223
+ st.metric("Avg Exit Velocity", "92 mph", "-1 mph")
224
+ with metrics_col2:
225
+ st.metric("Strike Rate", "65%", "+5%")
226
+ st.metric("Spin Rate", "2400 rpm", "+100 rpm")
227
+ st.markdown('</div>', unsafe_allow_html=True)
228
+
229
+ # History Section
230
+ if st.session_state.history:
231
+ st.markdown("### 📜 Previous Analyses")
232
+ for item in reversed(st.session_state.history[-5:]):
233
+ with st.expander(f"Q: {item['question'][:50]}..."):
234
+ st.write(item['response'])
235
+ st.caption(f"Analyzed on: {item['timestamp']}")
236
+
237
+ # Footer
238
+ st.markdown("---")
239
+ st.markdown(
240
+ """
241
+ <div style='text-align: center'>
242
+ <p>Powered by Advanced Baseball Analytics and OpenAI Vision API</p>
243
+ <p>© 2024 Baseball Vision Analytics</p>
244
+ </div>
245
+ """,
246
+ unsafe_allow_html=True
247
+ )
248
+
249
+ if __name__ == "__main__":
250
+ main()