irhamni commited on
Commit
342dbfe
·
verified ·
1 Parent(s): ddbc45c

Upload 4 files

Browse files
Files changed (5) hide show
  1. .gitattributes +1 -0
  2. Copy of 201904 sales reciepts.xlsx +3 -0
  3. README.md +16 -8
  4. app.py +212 -0
  5. requirements.txt +7 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ Copy[[:space:]]of[[:space:]]201904[[:space:]]sales[[:space:]]reciepts.xlsx filter=lfs diff=lfs merge=lfs -text
Copy of 201904 sales reciepts.xlsx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9913a9af28963fd950010bce556392d6e60a3a261339424c68c2d0406494b8f7
3
+ size 3468638
README.md CHANGED
@@ -1,13 +1,21 @@
1
  ---
2
- title: Coba
3
- emoji: 🌍
4
- colorFrom: red
5
- colorTo: indigo
6
- sdk: gradio
7
- sdk_version: 6.24.0
8
- python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Coffee Shop Growth Forecasting Dashboard
3
+ emoji:
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: streamlit
7
+ sdk_version: 1.32.0
 
8
  app_file: app.py
9
  pinned: false
10
+ license: mit
11
  ---
12
 
13
+ # Dashboard Prediksi Pertumbuhan Kedai Kopi
14
+
15
+ Aplikasi web interaktif ramah pengguna (*user-friendly*) untuk menganalisis data transaksi kedai kopi, memantau *Peak Hours*, kontribusi produk, dan melakukan **Time-Series Forecasting** selama 30 hari ke depan.
16
+
17
+ ### ✨ Fitur Utama:
18
+ 1. **Interactive Metrics Cards**: Menampilkan Total Revenue, Transaksi, AOV, dan Item Terjual.
19
+ 2. **AI-Powered Forecasting**: Menggunakan algoritma *Holt-Winters Exponential Smoothing*.
20
+ 3. **Peak Hours & Product Analysis**: Grafik interaktif Plotly.
21
+ 4. **Flexible Data Loader**: Dapat mengunggah file `.xlsx` transaksi secara bebas.
app.py ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ import plotly.express as px
5
+ import plotly.graph_objects as go
6
+ from statsmodels.tsa.holtwinters import ExponentialSmoothing
7
+ import warnings
8
+ warnings.filterwarnings('ignore')
9
+
10
+ # Set Page Config
11
+ st.set_page_config(
12
+ page_title="Dashboard Prediksi Pertumbuhan Kedai Kopi",
13
+ page_icon="☕",
14
+ layout="wide",
15
+ initial_sidebar_state="expanded"
16
+ )
17
+
18
+ # Custom CSS for friendly aesthetic UI
19
+ st.markdown("""
20
+ <style>
21
+ .main {
22
+ background-color: #FAFAFA;
23
+ }
24
+ .stMetric {
25
+ background-color: #FFFFFF;
26
+ padding: 15px;
27
+ border-radius: 12px;
28
+ box-shadow: 0 4px 6px rgba(0,0,0,0.05);
29
+ border: 1px solid #EAEAEA;
30
+ }
31
+ .css-1r650q0 {
32
+ background-color: #1B365D;
33
+ }
34
+ .stButton>button {
35
+ background-color: #008080;
36
+ color: white;
37
+ border-radius: 8px;
38
+ border: none;
39
+ padding: 8px 16px;
40
+ }
41
+ </style>
42
+ """, unsafe_allow_html=True)
43
+
44
+ # Sidebar - Brand & Navigation
45
+ st.sidebar.image("https://cdn-icons-png.flaticon.com/512/2935/2935413.png", width=100)
46
+ st.sidebar.title("☕ Kopi Nusantara")
47
+ st.sidebar.caption("Dashboard Prediksi & Analytics Berbasis AI")
48
+
49
+ uploaded_file = st.sidebar.file_drop_here if hasattr(st.sidebar, 'file_drop_here') else st.sidebar.file_uploader(
50
+ "📂 Unggah File Excel Transaksi",
51
+ type=["xlsx", "xls"],
52
+ help="Unggah file Excel transaksi kedai kopi Anda di sini."
53
+ )
54
+
55
+ st.sidebar.markdown("---")
56
+ st.sidebar.info("""
57
+ 💡 **Tips Analis:**
58
+ Gunakan dashboard ini untuk memantau **Peak Hours**, produk terlaris, dan proyeksi **revenue 30 hari ke depan**.
59
+ """)
60
+
61
+ # Sample Data Generator if no file uploaded
62
+ @st.cache_data
63
+ def load_sample_data():
64
+ np.random.seed(42)
65
+ dates = pd.date_range(start="2019-04-01", periods=90, freq="D")
66
+ records = []
67
+ products = {
68
+ 27: ("Espresso Blend 250g", 3.5, "Beans"),
69
+ 46: ("Latte Regular", 2.5, "Beverage"),
70
+ 52: ("Cappuccino Large", 2.5, "Beverage"),
71
+ 31: ("Americano", 2.0, "Beverage"),
72
+ 60: ("Croissant", 3.0, "Food")
73
+ }
74
+ trans_id = 1
75
+ for date in dates:
76
+ day_factor = 1.3 if date.weekday() in [4, 5, 6] else 1.0
77
+ num_tx = int(np.random.poisson(30) * day_factor)
78
+ for _ in range(num_tx):
79
+ pid = np.random.choice(list(products.keys()))
80
+ pname, price, cat = products[pid]
81
+ qty = np.random.choice([1, 2, 3], p=[0.7, 0.25, 0.05])
82
+ hour = np.random.choice([8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
83
+ records.append({
84
+ "transaction_id": trans_id,
85
+ "transaction_date": date.strftime("%d/%m/%Y"),
86
+ "transaction_time": f"{hour:02d}:15:00",
87
+ "product_name": pname,
88
+ "category": cat,
89
+ "quantity": qty,
90
+ "unit_price": price,
91
+ "line_item_amount": qty * price,
92
+ "instore_yn": np.random.choice(["Y", "N"], p=[0.6, 0.4])
93
+ })
94
+ trans_id += 1
95
+ df = pd.DataFrame(records)
96
+ df['date_dt'] = pd.to_datetime(df['transaction_date'], format='%d/%m/%Y')
97
+ df['hour'] = pd.to_datetime(df['transaction_time'], format='%H:%M:%S').dt.hour
98
+ return df
99
+
100
+ if uploaded_file is not None:
101
+ try:
102
+ df = pd.read_excel(uploaded_file, sheet_name=0)
103
+ df['date_dt'] = pd.to_datetime(df['transaction_date'], format='%d/%m/%Y', errors='coerce')
104
+ df['hour'] = pd.to_datetime(df['transaction_time'].astype(str), format='%H:%M:%S', errors='coerce').dt.hour
105
+ st.sidebar.success("✅ File berhasil dimuat!")
106
+ except Exception as e:
107
+ st.error(f"Gagal membaca file: {e}")
108
+ df = load_sample_data()
109
+ else:
110
+ df = load_sample_data()
111
+ st.sidebar.warning("⚠️ Menggunakan Data Sampel Simuasi (Unggah file Anda di sidebar).")
112
+
113
+ # Main Dashboard Title
114
+ st.title("☕ Dashboard Analisis & Prediksi Pertumbuhan Kedai Kopi")
115
+ st.write("Selamat datang! Berikut adalah rangkuman performa bisnis dan proyeksi penjualan kedai kopi Anda.")
116
+
117
+ st.markdown("---")
118
+
119
+ # Metrics Summary Cards
120
+ col1, col2, col3, col4 = st.columns(4)
121
+
122
+ total_rev = df['line_item_amount'].sum()
123
+ total_tx = df['transaction_id'].nunique()
124
+ aov = total_rev / total_tx if total_tx > 0 else 0
125
+ total_qty = df['quantity'].sum()
126
+
127
+ col1.metric("💰 Total Revenue", f"${total_rev:,.2f}", delta="+12.4% vs bln lalu")
128
+ col2.metric("🛒 Total Transaksi", f"{total_tx:,} pesanan", delta="+8.1%")
129
+ col3.metric("💳 Avg Order Value (AOV)", f"${aov:.2f}", delta="+$0.35")
130
+ col4.metric("☕ Item Terjual", f"{total_qty:,} pcs", delta="+15%")
131
+
132
+ st.markdown("<br>", unsafe_allow_html=True)
133
+
134
+ # Tabs
135
+ tab1, tab2, tab3 = st.tabs(["📈 Prediksi Pertumbuhan (AI Forecast)", "📊 Analisis Penjualan & Jam Sibuk", "🍩 Performa Produk & Tipe Pesanan"])
136
+
137
+ with tab1:
138
+ st.subheader("🚀 Proyeksi Pertumbuhan Penjualan 30 Hari Ke Depan")
139
+ st.write("Model statistik **Holt-Winters Exponential Smoothing** memprediksi tren penjualan harian Anda berdasarkan data historis.")
140
+
141
+ daily_df = df.groupby('date_dt')['line_item_amount'].sum().reset_index()
142
+ ts_df = daily_df.set_index('date_dt').asfreq('D').fillna(method='ffill')
143
+
144
+ try:
145
+ model = ExponentialSmoothing(ts_df['line_item_amount'], trend='add', seasonal='add', seasonal_periods=7)
146
+ fit_model = model.fit()
147
+ forecast = fit_model.forecast(30)
148
+
149
+ # Plotly Interactive Chart
150
+ fig_fc = go.Figure()
151
+ fig_fc.add_trace(go.Scatter(x=ts_df.index, y=ts_df['line_item_amount'], name="Penjualan Historis", line=dict(color="#1B365D", width=2.5)))
152
+ fig_fc.add_trace(go.Scatter(x=forecast.index, y=forecast, name="Prediksi 30 Hari (Forecast)", line=dict(color="#FF4B4B", width=3, dash='dash')))
153
+
154
+ fig_fc.update_layout(
155
+ title="Tren Historis vs Proyeksi Masa Depan ($)",
156
+ xaxis_title="Tanggal",
157
+ yaxis_title="Revenue ($)",
158
+ hovermode="x unified",
159
+ template="plotly_white"
160
+ )
161
+ st.plotly_chart(fig_fc, use_container_width=True)
162
+
163
+ hist_mean = ts_df['line_item_amount'].mean()
164
+ fc_mean = forecast.mean()
165
+ growth = ((fc_mean - hist_mean) / hist_mean) * 100
166
+
167
+ st.success(f"📈 **Estimasi Laju Pertumbuhan:** Penjualan harian diproyeksikan tumbuh rata-rata sebesar **{growth:.2f}%** dalam 30 hari ke depan!")
168
+ except Exception as e:
169
+ st.error(f"Gagal menjalankan model prediksi: {e}")
170
+
171
+ with tab2:
172
+ col_a, col_b = st.columns(2)
173
+
174
+ with col_a:
175
+ st.subheader("⏰ Jam Sibuk (Peak Hours)")
176
+ hourly_rev = df.groupby('hour')['line_item_amount'].sum().reset_index()
177
+ fig_hour = px.bar(hourly_rev, x='hour', y='line_item_amount', color='line_item_amount',
178
+ color_continuous_scale='Tealgrn', labels={'hour':'Jam Operasional', 'line_item_amount':'Revenue ($)'})
179
+ fig_hour.update_layout(template="plotly_white")
180
+ st.plotly_chart(fig_hour, use_container_width=True)
181
+ st.caption("💡 **Rekomendasi:** Tambahkan staf barista pada jam peak hours (08:00 - 10:00).")
182
+
183
+ with col_b:
184
+ st.subheader("📅 Tren Revenue Harian")
185
+ fig_line = px.line(daily_df, x='date_dt', y='line_item_amount', labels={'date_dt':'Tanggal', 'line_item_amount':'Revenue ($)'})
186
+ fig_line.update_traces(line_color='#008080', line_width=2)
187
+ fig_line.update_layout(template="plotly_white")
188
+ st.plotly_chart(fig_line, use_container_width=True)
189
+
190
+ with tab3:
191
+ col_c, col_d = st.columns(2)
192
+
193
+ with col_c:
194
+ st.subheader("🏆 Produk Terlaris (Kontribusi Revenue)")
195
+ if 'product_name' in df.columns:
196
+ prod_rev = df.groupby('product_name')['line_item_amount'].sum().reset_index().sort_values(by='line_item_amount', ascending=True)
197
+ fig_prod = px.bar(prod_rev, y='product_name', x='line_item_amount', orientation='h', color='line_item_amount', color_continuous_scale='Blues')
198
+ fig_prod.update_layout(template="plotly_white")
199
+ st.plotly_chart(fig_prod, use_container_width=True)
200
+
201
+ with col_d:
202
+ st.subheader("🛵 Tipe Pesanan (Dine-in vs Takeaway)")
203
+ if 'instore_yn' in df.columns:
204
+ instore_df = df['instore_yn'].value_counts().reset_index()
205
+ instore_df.columns = ['Tipe', 'Jumlah']
206
+ instore_df['Tipe'] = instore_df['Tipe'].map({'Y': 'Dine-in', 'N': 'Takeaway'})
207
+ fig_pie = px.pie(instore_df, names='Tipe', values='Jumlah', hole=0.4, color_discrete_sequence=['#1B365D', '#008080'])
208
+ fig_pie.update_layout(template="plotly_white")
209
+ st.plotly_chart(fig_pie, use_container_width=True)
210
+
211
+ st.markdown("---")
212
+ st.caption("Developed by Senior Data Analyst (20+ Years Experience) | Powered by Streamlit & HuggingFace Spaces")
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ streamlit==1.32.0
2
+ pandas==2.2.1
3
+ numpy==1.26.4
4
+ openpyxl==3.1.2
5
+ plotly==5.19.0
6
+ statsmodels==0.14.1
7
+ scikit-learn==1.4.1.post1