# app.py
import streamlit as st
import pandas as pd
from prediction import recommend_phones
from eda import render_eda, get_dataset_info
# =========================================================
# PAGE CONFIG
# =========================================================
st.set_page_config(
page_title="PhoneFinder",
page_icon="๐ฑ",
layout="wide",
initial_sidebar_state="expanded"
)
# =========================================================
# CSS
# =========================================================
st.markdown("""
""", unsafe_allow_html=True)
# =========================================================
# SIDEBAR
# =========================================================
with st.sidebar:
st.image(
"FTDS-053-RMT-GROUP1-LOGO.png",
width=180
)
st.markdown("## ๐ฑ Navigation")
page = st.radio(
"",
[
"๐ Home",
"๐ EDA",
"๐ Recommendation"
]
)
# =========================================================
# HOME PAGE
# =========================================================
if page == "๐ Home":
col1, col2, col3 = st.columns([1, 1, 1])
with col2:
st.image("FTDS-053-RMT-GROUP1-LOGO.png", width=320)
st.markdown(
'
PhoneFinder
',
unsafe_allow_html=True
)
st.markdown(
'AI-Powered Smartphone Recommendation System
',
unsafe_allow_html=True
)
st.markdown("
", unsafe_allow_html=True)
st.markdown(
'โ The Problem
',
unsafe_allow_html=True
)
st.write("""
With hundreds of smartphone options available across different price ranges,
users often struggle to find devices that truly match their needs and budget.
Many people purchase smartphones based only on trends or brand popularity,
instead of choosing devices optimized for their actual use case.
""")
st.markdown("
", unsafe_allow_html=True)
st.markdown(
'๐ก Our Solution
',
unsafe_allow_html=True
)
st.write("""
PhoneFinder provides smartphone recommendations based on broad user priorities such as:
- Flagship
- Gaming / Performance
- Camera-Focused
- Budget-Focused
The system combines clustering and similarity-based recommendation techniques
to recommend smartphones that best match the user's budget and preferences.
""")
st.markdown("
", unsafe_allow_html=True)
info = get_dataset_info()
col1, col2, col3 = st.columns(3)
with col1:
st.markdown(f"""
๐ฑ
{info['total_phones']}
Smartphones
""", unsafe_allow_html=True)
with col2:
st.markdown(f"""
๐ฐ
${info['avg_price']}
Average Price
""", unsafe_allow_html=True)
with col3:
st.markdown("""
๐ฏ
4
Recommendation Types
""", unsafe_allow_html=True)
# =========================================================
# EDA PAGE
# =========================================================
elif page == "๐ EDA":
st.markdown(
'Exploratory Data Analysis
',
unsafe_allow_html=True
)
st.markdown(
'Understanding smartphone market patterns and specifications
',
unsafe_allow_html=True
)
st.markdown("
", unsafe_allow_html=True)
render_eda()
# =========================================================
# RECOMMENDATION PAGE
# =========================================================
elif page == "๐ Recommendation":
st.markdown(
'Find Your Smartphone
',
unsafe_allow_html=True
)
st.markdown(
'AI-powered smartphone recommendation engine
',
unsafe_allow_html=True
)
st.markdown("
", unsafe_allow_html=True)
# =====================================================
# INPUT UTAMA: Budget, Priority, Top N
# =====================================================
col1, col2 = st.columns(2)
with col1:
budget = st.slider(
"๐ฐ Budget (USD)",
min_value=50,
max_value=2000,
value=500,
step=50
)
top_n = st.slider(
"๐ Top N Results",
min_value=1,
max_value=10,
value=5
)
with col2:
priority = st.selectbox(
"๐ฏ Priority",
[
"flagship",
"gaming",
"camera",
"budget"
]
)
st.markdown("
", unsafe_allow_html=True)
# =====================================================
# FILTER SPESIFIKASI MINIMUM
# =====================================================
st.markdown("""
๐ง Minimum Specification Filters (Optional)
""", unsafe_allow_html=True)
fcol1, fcol2, fcol3, fcol4 = st.columns(4)
with fcol1:
min_ram = st.selectbox(
"๐ฅ๏ธ Minimum RAM (GB)",
options=[0, 2, 4, 6, 8, 12, 16],
index=0,
format_func=lambda x: "No Filter" if x == 0 else f"{x} GB"
)
with fcol2:
min_camera = st.selectbox(
"๐ท Minimum Camera (MP)",
options=[0, 12, 24, 48, 50, 64, 108, 200],
index=0,
format_func=lambda x: "No Filter" if x == 0 else f"{x} MP"
)
with fcol3:
min_battery = st.selectbox(
"๐ Minimum Battery (mAh)",
options=[0, 3000, 4000, 4500, 5000, 5500, 6000],
index=0,
format_func=lambda x: "No Filter" if x == 0 else f"{x:,} mAh"
)
with fcol4:
min_year = st.selectbox(
"๐
Minimum Release Year",
options=[0, 2020, 2021, 2022, 2023, 2024, 2025],
index=0,
format_func=lambda x: "No Filter" if x == 0 else str(x)
)
st.markdown("
", unsafe_allow_html=True)
search = st.button("๐ Find Phones")
# =====================================================
# RESULTS
# =====================================================
if search:
with st.spinner("Finding best smartphone matches..."):
results, seg_name = recommend_phones(
budget_usd=budget,
priority=priority,
top_n=top_n,
min_ram=min_ram,
min_camera_mp=min_camera,
min_battery=min_battery,
min_year=min_year,
)
st.markdown("
", unsafe_allow_html=True)
# Tampilkan info filter yang aktif
active_filters = []
if min_ram > 0:
active_filters.append(f"RAM โฅ {min_ram} GB")
if min_camera > 0:
active_filters.append(f"Camera โฅ {min_camera} MP")
if min_battery > 0:
active_filters.append(f"Battery โฅ {min_battery:,} mAh")
if min_year > 0:
active_filters.append(f"Release Year โฅ {min_year}")
if active_filters:
st.info(f"๐ง Active filters: {' ยท '.join(active_filters)}")
# Jika tidak ada hasil
if results.empty:
st.warning(
"โ ๏ธ No smartphones found matching your filters and budget. "
"Try lowering the minimum specifications or increasing your budget."
)
else:
SEG_COLORS = {
'Budget': '#534AB7',
'Camera-focused': '#993C1D',
'Gaming / Performance': '#0F6E56',
'Flagship': '#854F0B',
}
color = SEG_COLORS.get(
seg_name.split(' (')[0],
'#534AB7'
)
st.markdown(
f"""
Matched Segment: {seg_name}
""",
unsafe_allow_html=True
)
st.markdown("
", unsafe_allow_html=True)
for rank, row in results.iterrows():
name = f"{row.get('brand','')} {row.get('model','')}".strip()
price = (
f"${row['price']:.0f}"
if pd.notna(row.get('price'))
else 'N/A'
)
score = row.get('Match Score (%)', 0)
st.markdown(f"""
#{rank} {name}
{price}
Match Score: {score:.1f}%
{int(row['ram'])} GB RAM
{int(row['battery_capacity'])} mAh
{int(row['main_camera_mp'])} MP Camera
""", unsafe_allow_html=True)
st.progress(int(score))