Man0707 commited on
Commit
11a06c2
·
verified ·
1 Parent(s): 5e36dc5

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +250 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,252 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
1
  import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ from sklearn.model_selection import train_test_split
5
+ from sklearn.preprocessing import StandardScaler
6
+ from sklearn.ensemble import RandomForestClassifier
7
+ from sklearn.metrics import accuracy_score
8
+ import time
9
+
10
+ # -------------------------- Page Config --------------------------
11
+ st.set_page_config(
12
+ page_title="Vinum Divinum • Wine Oracle",
13
+ page_icon="🍷",
14
+ layout="centered",
15
+ initial_sidebar_state="collapsed"
16
+ )
17
+
18
+ # -------------------------- Luxurious Custom CSS with Animations --------------------------
19
+ st.markdown("""
20
+ <style>
21
+ @import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@400;600;700&family=Playfair+Display:wght@700&display=swap');
22
+
23
+ .main {
24
+ background: linear-gradient(180deg, #0a001f, #001a00);
25
+ color: #e6e6e6;
26
+ font-family: 'Cormorant Garamond', serif;
27
+ }
28
+
29
+ .stApp {
30
+ background: url('https://images.unsplash.com/photo-1510812431401-41d2bd2722f3?q=80&w=2832&auto=format&fit=crop') no-repeat center center fixed;
31
+ background-size: cover;
32
+ }
33
+
34
+ .glass-card {
35
+ background: rgba(10, 25, 10, 0.65);
36
+ backdrop-filter: blur(12px);
37
+ border-radius: 20px;
38
+ padding: 2rem;
39
+ border: 1px solid rgba(100, 200, 100, 0.3);
40
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6);
41
+ margin: 1rem 0;
42
+ animation: fadeIn 1.5s ease-out;
43
+ }
44
+
45
+ @keyframes fadeIn {
46
+ from {opacity: 0; transform: translateY(30px);}
47
+ to {opacity: 1; transform: translateY(0);}
48
+ }
49
+
50
+ @keyframes glow {
51
+ 0%, 100% {box-shadow: 0 0 20px #64c864;}
52
+ 50% {box-shadow: 0 0 0 40px #00ff88;}
53
+ }
54
+
55
+ .title-glow {
56
+ font-family: 'Playfair Display', serif;
57
+ font-size: 4.5rem;
58
+ background: linear-gradient(90deg, #ffd700, #00ff88, #ff00aa);
59
+ -webkit-background-clip: text;
60
+ -webkit-text-fill-color: transparent;
61
+ text-align: center;
62
+ animation: glow 4s infinite;
63
+ margin-bottom: 0;
64
+ }
65
+
66
+ .subtitle {
67
+ font-size: 1.6rem;
68
+ text-align: center;
69
+ color: #b0ffb0;
70
+ font-style: italic;
71
+ margin-top: 0;
72
+ }
73
+
74
+ .metric-card {
75
+ background: rgba(20, 40, 20, 0.7);
76
+ padding: 1rem;
77
+ border-radius: 15px;
78
+ border: 1px solid #00ff88;
79
+ text-align: center;
80
+ color: #e0ffe0;
81
+ }
82
+
83
+ .stButton>button {
84
+ background: linear-gradient(45deg, #1e4d1e, #2e8b57);
85
+ color: gold;
86
+ font-weight: bold;
87
+ border: none;
88
+ border-radius: 50px;
89
+ padding: 0.8rem 2rem;
90
+ font-size: 1.3rem;
91
+ transition: all 0.4s;
92
+ box-shadow: 0 4px 15px rgba(0, 255, 100, 0.4);
93
+ }
94
+
95
+ .stButton>button:hover {
96
+ transform: translateY(-5px);
97
+ box-shadow: 0 10px 25px rgba(0, 255, 100, 0.7);
98
+ background: linear-gradient(45deg, #2e8b57, #00ff88);
99
+ }
100
+
101
+ .good-wine {
102
+ font-size: 4rem;
103
+ text-align: center;
104
+ color: #00ff88;
105
+ text-shadow: 0 0 30px #00ff88, 0 0 60px #00ff00;
106
+ animation: glow 2s infinite alternate;
107
+ }
108
+
109
+ .bad-wine {
110
+ font-size: 3rem;
111
+ text-align: center;
112
+ color: #ff3366;
113
+ text-shadow: 0 0 20px #ff0066;
114
+ }
115
+ </style>
116
+ """, unsafe_allow_html=True)
117
+
118
+ # -------------------------- Load Data (Same Logic) --------------------------
119
+ @st.cache_data
120
+ def load_wine_data():
121
+ red = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv", sep=";")
122
+ red["type"] = "Red"
123
+ white = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv", sep=";")
124
+ white["type"] = "White"
125
+ df = pd.concat([red, white], ignore_index=True)
126
+ df["is_good"] = (df["quality"] >= 6).astype(int)
127
+ return df
128
+
129
+ df = load_wine_data()
130
+
131
+ # -------------------------- Hero Title with Animation --------------------------
132
+ st.markdown("<h1 class='title-glow'>Vinum Divinum</h1>", unsafe_allow_html=True)
133
+ st.markdown("<p class='subtitle'>The Ancient Oracle of Wine Quality</p>", unsafe_allow_html=True)
134
+
135
+ st.markdown("<br>", unsafe_allow_html=True)
136
+
137
+ # -------------------------- Stats in Glass Cards --------------------------
138
+ with st.container():
139
+ st.markdown("<div class='glass-card'>", unsafe_allow_html=True)
140
+ c1, c2, c3, c4 = st.columns(4)
141
+ with c1:
142
+ st.markdown("<div class='metric-card'>", unsafe_allow_html=True)
143
+ st.metric("Total Vintages", f"{len(df):,}")
144
+ st.markdown("</div>", unsafe_allow_html=True)
145
+ with c2:
146
+ st.markdown("<div class='metric-card'>", unsafe_allow_html=True)
147
+ st.metric("Red Wines", f"{len(df[df['type']=='Red']):,}")
148
+ st.markdown("</div>", unsafe_allow_html=True)
149
+ with c3:
150
+ st.markdown("<div class='metric-card'>", unsafe_allow_html=True)
151
+ st.metric("White Wines", f"{len(df[df['type']=='White']):,}")
152
+ st.markdown("</div>", unsafe_allow_html=True)
153
+ with c4:
154
+ st.markdown("<div class='metric-card'>", unsafe_allow_html=True)
155
+ good_pct = df['is_good'].mean() * 100
156
+ st.metric("Deemed Worthy", f"{good_pct:.1f}%")
157
+ st.markdown("</div>", unsafe_allow_html=True)
158
+ st.markdown("</div>", unsafe_allow_html=True)
159
+
160
+ # -------------------------- Model Training (Same Powerful Model) --------------------------
161
+ X = df.drop(columns=["quality", "is_good"])
162
+ y = df["is_good"]
163
+ X = pd.get_dummies(X, columns=["type"])
164
+ numerical_cols = [c for c in X.columns if c not in ["type_Red", "type_White"]]
165
+
166
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)
167
+
168
+ scaler = StandardScaler()
169
+ X_train_scaled = scaler.fit_transform(X_train[numerical_cols])
170
+ X_train_final = np.hstack([X_train_scaled, X_train[["type_Red", "type_White"]].values])
171
+
172
+ X_test_scaled = scaler.transform(X_test[numerical_cols])
173
+ X_test_final = np.hstack([X_test_scaled, X_test[["type_Red", "type_White"]].values])
174
+
175
+ @st.cache_resource
176
+ def train_oracle():
177
+ model = RandomForestClassifier(
178
+ n_estimators=1200,
179
+ max_depth=18,
180
+ min_samples_split=5,
181
+ class_weight="balanced",
182
+ random_state=42,
183
+ n_jobs=-1
184
+ )
185
+ model.fit(X_train_final, y_train)
186
+ return model, scaler
187
+
188
+ model, scaler = train_oracle()
189
+
190
+ # Accuracy
191
+ accuracy = accuracy_score(y_test, model.predict(X_test_final))
192
+
193
+ st.markdown(f"<div class='glass-card' style='text-align:center;'><h3>Oracle Accuracy: <span style='color:#00ff88'>{accuracy:.4f}</span> ({accuracy*100:.2f}%)</h3></div>", unsafe_allow_html=True)
194
+
195
+ # -------------------------- Interactive Oracle Prediction --------------------------
196
+ st.markdown("<div class='glass-card'>", unsafe_allow_html=True)
197
+ st.markdown("<h2 style='text-align:center; color:#ffd700;'>Consult the Wine Oracle</h2>", unsafe_allow_html=True)
198
+
199
+ wine_type = st.select_slider("Select Thy Wine", options=["Red", "White"], value="Red")
200
+
201
+ col1, col2 = st.columns(2)
202
+ input_dict = {"type_Red": 1 if wine_type == "Red" else 0, "type_White": 1 if wine_type == "White" else 0}
203
+
204
+ for i, feat in enumerate(numerical_cols):
205
+ col = col1 if i % 2 == 0 else col2
206
+ with col:
207
+ min_val, max_val, avg_val = df[feat].min(), df[feat].max(), df[feat].mean()
208
+ value = st.slider(
209
+ feat.replace("_", " ").title(),
210
+ min_value=float(min_val),
211
+ max_value=float(max_val),
212
+ value=float(avg_val),
213
+ step=0.1,
214
+ format="%.2f",
215
+ key=feat
216
+ )
217
+ input_dict[feat] = value
218
+
219
+ if st.button("✨ Reveal Destiny ✨", use_container_width=True):
220
+ with st.spinner("The Oracle is tasting..."):
221
+ time.sleep(2)
222
+
223
+ # Prepare input
224
+ input_num = np.array([[input_dict[f] for f in numerical_cols]])
225
+ input_scaled = scaler.transform(input_num)
226
+ input_final = np.hstack([input_scaled, [[input_dict["type_Red"], input_dict["type_White"]]]])
227
+
228
+ pred = model.predict(input_final)[0]
229
+ prob = model.predict_proba(input_final)[0]
230
+
231
+ st.markdown("<br>", unsafe_allow_html=True)
232
+
233
+ if pred == 1:
234
+ st.balloons()
235
+ st.markdown(f"<h1 class='good-wine'>DIVINE VINTAGE!</h1>", unsafe_allow_html=True)
236
+ st.markdown(f"<h3 style='text-align:center; color:#b0ffb0;'>A {wine_type} wine blessed by Dionysus himself!</h3>", unsafe_allow_html=True)
237
+ st.success(f"Confidence of Glory: *{prob[1]:.1%}*")
238
+ st.markdown("### Raise your glass — this is nectar of the gods!")
239
+ else:
240
+ st.markdown(f"<h2 class='bad-wine'>Alas, Not This Time...</h2>", unsafe_allow_html=True)
241
+ st.error(f"Confidence of Mediocrity: *{prob[0]:.1%}*")
242
+ st.info("Perhaps offer it to the earth... or use it to clean copper?")
243
+
244
+ st.markdown("</div>", unsafe_allow_html=True)
245
 
246
+ # -------------------------- Footer --------------------------
247
+ st.markdown("""
248
+ <div style='text-align:center; margin-top: 4rem; color: #666;'>
249
+ <p>© 2025 Vinum Divinum Powered by Ancient Wisdom & Random Forests</p>
250
+ <p style='font-size:0.9rem; opacity:0.7;'>Dataset: UCI Wine Quality Model trained on 6,497 sacred bottles</p>
251
+ </div>
252
+ """, unsafe_allow_html=True)