Spaces:
Runtime error
Runtime error
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import joblib | |
| import plotly.express as px | |
| import re | |
| import string | |
| import nltk | |
| import os | |
| from datetime import datetime | |
| from nltk.corpus import stopwords | |
| st.set_page_config(page_title="Tokopedia Project Dashboard", layout="wide") | |
| ARTIFACTS_DIR = 'artifacts' | |
| def load_resources(): | |
| try: | |
| nltk.download('stopwords') | |
| indo_stopwords = set(stopwords.words('indonesian')) | |
| custom_stopwords = { | |
| 'yg', 'dg', 'dgn', 'ny', 'nya', 'kalo', 'klo', 'gan', 'sis', 'kak', 'bro', | |
| 'bosh', 'boss', 'nomor', 'wa', 'hub', 'cod', 'ready', 'stock', 'stok', | |
| 'promo', 'murah', 'diskon', 'termurah', 'terlaris', 'bestseller' | |
| } | |
| final_stopwords = indo_stopwords.union(custom_stopwords) | |
| # Load core artifacts | |
| vectorizer = joblib.load(os.path.join(ARTIFACTS_DIR, 'tfidf_vectorizer.pkl')) | |
| # Load Price Artifacts | |
| price_preprocess = joblib.load(os.path.join(ARTIFACTS_DIR, 'price_preprocessor.pkl')) | |
| price_cols = joblib.load(os.path.join(ARTIFACTS_DIR, 'price_columns.pkl')) | |
| # Load Models | |
| price_models = { | |
| "Random Forest": joblib.load(os.path.join(ARTIFACTS_DIR, 'Random_Forest_price.pkl')), | |
| "XGBoost": joblib.load(os.path.join(ARTIFACTS_DIR, 'XGBoost_price.pkl')), | |
| "MLP": joblib.load(os.path.join(ARTIFACTS_DIR, 'MLP_price.pkl')) | |
| } | |
| return vectorizer, price_preprocess, price_cols, price_models, final_stopwords | |
| except Exception as e: | |
| st.error(f"Error loading resources: {e}") | |
| return None, None, None, None, None | |
| (vectorizer, price_preprocess, price_cols, | |
| price_models, final_stopwords) = load_resources() | |
| def get_categories(): | |
| columns = ['Other'] | |
| if price_cols: | |
| cat_cols = [c for c in price_cols if c.startswith('cat_')] | |
| columns = [c.replace('cat_', '') for c in cat_cols] | |
| return sorted(columns) | |
| def clean_text(text): | |
| if not isinstance(text, str): return "" | |
| text = text.lower() | |
| text = re.sub(r'[^a-z0-9\s]', ' ', text) | |
| text = re.sub(r'\s+', ' ', text).strip() | |
| words = text.split() | |
| return " ".join([w for w in words if w not in final_stopwords]) | |
| def get_date_features(date_obj, prefix): | |
| return { | |
| f"{prefix}_dayofweek": date_obj.weekday(), | |
| f"{prefix}_month": date_obj.month, | |
| f"{prefix}_is_weekend": 1 if date_obj.weekday() >= 5 else 0 | |
| } | |
| def prepare_raw_dataframe(user_input, target_columns, vectorizer): | |
| input_df = pd.DataFrame(0, index=[0], columns=target_columns) | |
| # Text | |
| combined_text = clean_text(user_input.get('product_name', '')) + " " + clean_text(user_input.get('description', '')) | |
| tfidf_matrix = vectorizer.transform([combined_text]) | |
| tfidf_df = pd.DataFrame(tfidf_matrix.toarray(), columns=[f"word_{w}" for w in vectorizer.get_feature_names_out()]) | |
| common_text_cols = input_df.columns.intersection(tfidf_df.columns) | |
| input_df[common_text_cols] = tfidf_df[common_text_cols] | |
| # Categories | |
| cat_col = f"cat_{user_input.get('category', 'Other')}" | |
| if cat_col in input_df.columns: | |
| input_df[cat_col] = 1 | |
| elif 'cat_Other' in input_df.columns: | |
| input_df['cat_Other'] = 1 | |
| # Numerical | |
| for key, value in user_input.items(): | |
| if key in input_df.columns: | |
| input_df[key] = value | |
| return input_df | |
| def load_and_plot_importance(model_name, target_name): | |
| filename = f"importance_data_{target_name}_{model_name.replace(' ', '_')}.csv" | |
| path = os.path.join(ARTIFACTS_DIR, filename) | |
| if os.path.exists(path): | |
| df = pd.read_csv(path) | |
| fig = px.bar( | |
| df.head(15), x='Importance', y='Feature', orientation='h', error_x='Std', | |
| title=f"Feature Importance ({model_name}) - {target_name.title()}", color='Importance' | |
| ) | |
| fig.update_layout(yaxis=dict(autorange="reversed")) | |
| st.plotly_chart(fig) | |
| st.title("🛍️ Advanced E-Commerce Predictor") | |
| with st.sidebar: | |
| st.header("1. Product Info") | |
| p_name = st.text_input("Product Name", "Samsung Galaxy S24 Ultra") | |
| p_desc = st.text_area("Description", "Original SEIN, Garansi Resmi 1 Tahun") | |
| cat_options = get_categories() | |
| category = st.selectbox("Category", cat_options) | |
| condition = st.radio("Condition", ["New", "Used"]) | |
| is_regular = st.checkbox("Regular Merchant?", value=True) | |
| is_discount = st.checkbox("Is Discounted?", value=False) | |
| st.header("2. Physical & Stock") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| weight = st.number_input("Weight (g)", value=500) | |
| min_order = st.number_input("Min Order", value=1) | |
| with col2: | |
| max_order = st.number_input("Max Order", value=100) | |
| stock = st.number_input("Stock", value=50) | |
| sold_input = st.number_input("Sold (Current)", value=0) | |
| st.header("3. Media") | |
| vid_count = st.number_input("Video Count", 0) | |
| img_count = st.number_input("Image Count", 1) | |
| with st.expander("Detailed Ratings", expanded=True): | |
| c1, c2, c3, c4, c5 = st.columns(5) | |
| r5 = c1.number_input("5 Star Count", value=10) | |
| r4 = c2.number_input("4 Star Count", value=2) | |
| r3 = c3.number_input("3 Star Count", value=0) | |
| r2 = c4.number_input("2 Star Count", value=0) | |
| r1 = c5.number_input("1 Star Count", value=0) | |
| total_rating = r5 + r4 + r3 + r2 + r1 | |
| c_qual, c_srv, c_ship = st.columns(3) | |
| rev_qual = c_qual.number_input("Reviews: Quality", 0) | |
| rev_srv = c_srv.number_input("Reviews: Service", 0) | |
| rev_ship = c_ship.number_input("Reviews: Shipping", 0) | |
| with st.expander("Shipping & Shop Metadata", expanded=False): | |
| c1, c2 = st.columns(2) | |
| with c1: | |
| ship_sameday = st.checkbox("Same Day", True) | |
| ship_reg = st.checkbox("Regular", True) | |
| ship_cargo = st.checkbox("Cargo", False) | |
| ship_eco = st.checkbox("Economy", True) | |
| with c2: | |
| shop_rating = st.slider("Shop Rating Score", 0.0, 5.0, 4.8) | |
| shop_age = st.number_input("Shop Age (Days)", 365) | |
| shop_pop = st.number_input("Shop City Popularity", 0.0) | |
| date_listing = st.date_input("Listing Created", datetime.now()) | |
| date_shop_open = st.date_input("Shop Open Since", datetime(2020, 1, 1)) | |
| feat_created = get_date_features(date_listing, "created_at") | |
| feat_shop = get_date_features(date_shop_open, "shop_open_since") | |
| listing_age_calc = (datetime.now().date() - date_listing).days | |
| total_shipping = sum([ship_sameday, ship_reg, ship_cargo, ship_eco]) | |
| base_input = { | |
| 'product_name': p_name, 'description': p_desc, 'category': category, | |
| 'condition_encoded': 1 if condition == 'New' else 0, | |
| 'is_regular_merchant': 1 if is_regular else 0, | |
| 'is_discount': 1 if is_discount else 0, | |
| 'weight_grams': weight, | |
| 'min_order': min_order, 'max_order': max_order, | |
| 'stock': stock, | |
| 'video_count': vid_count, 'image_count': img_count, | |
| 'can_shipping_sameday': 1 if ship_sameday else 0, | |
| 'can_shipping_regular': 1 if ship_reg else 0, | |
| 'can_shipping_cargo': 1 if ship_cargo else 0, | |
| 'can_shipping_economy': 1 if ship_eco else 0, | |
| 'total_shipping_types': total_shipping, | |
| 'shop_rating_score': shop_rating, | |
| 'shop_age_days': shop_age, | |
| 'shop_city_popularity': shop_pop, | |
| 'listing_age_days': listing_age_calc, | |
| 'product_rating_5_star_count': r5, | |
| 'product_rating_4_star_count': r4, | |
| 'product_rating_3_star_count': r3, | |
| 'product_rating_2_star_count': r2, | |
| 'product_rating_1_star_count': r1, | |
| 'total_product_rating': total_rating, | |
| 'total_review_about_kualitas': rev_qual, | |
| 'total_review_about_pelayanan': rev_srv, | |
| 'total_review_about_pengiriman': rev_ship, | |
| **feat_created, **feat_shop | |
| } | |
| if sold_input: | |
| base_input['sold'] = sold_input | |
| # Log Transforms (Stock & Sold) | |
| base_input['Log_stock'] = np.log1p(stock) | |
| base_input['Log_sold'] = np.log1p(sold_input) | |
| st.divider() | |
| st.subheader("💰 Price Prediction") | |
| if price_models: | |
| model_name = st.selectbox("Select Price Model", list(price_models.keys()), key="p_model") | |
| if st.button("Predict Price", type="primary"): | |
| raw_df = prepare_raw_dataframe(base_input, price_cols, vectorizer) | |
| X_scaled = price_preprocess.transform(raw_df) | |
| log_pred = price_models[model_name].predict(X_scaled)[0] | |
| price_pred = np.expm1(log_pred) | |
| st.success(f"Estimated Price: **Rp {price_pred:,.0f}**") | |
| st.markdown("### Feature Importance") | |
| load_and_plot_importance(model_name, "price") | |
| else: | |
| st.error("Price models not loaded.") | |