File size: 3,701 Bytes
4c6b43f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import streamlit as st
import joblib
import time

# -------------------------------------------------
# Page config & title
# -------------------------------------------------
st.set_page_config(page_title="Book Recommender System", layout="wide")
st.title("Book Recommender System")

# -------------------------------------------------
# Load model (cached once)
# -------------------------------------------------
@st.cache_resource
def load_model():
    model = joblib.load("model.pkl")
    return {
        "data": model["data"],
        "similarity": model["similarity"],
        "pivot_index": model["pivot_index"],
    }

with st.spinner("Loading model and book catalogue..."):
    model_data = load_model()
    data = model_data["data"]
    similarity = model_data["similarity"]
    pivot_index = model_data["pivot_index"]

st.success(f"Loaded **{len(pivot_index):,}** books successfully!")

# -------------------------------------------------
# Safe image URL
# -------------------------------------------------
def safe_image_url(book_name: str) -> str:
    try:
        url = data[data["book_name"] == book_name].iloc[0]["image_url"]
        return url if url and isinstance(url, str) and url.strip() else "https://via.placeholder.com/120x180?text=No+Image"
    except:
        return "https://via.placeholder.com/120x180?text=No+Image"

# -------------------------------------------------
# Recommend 7 books
# -------------------------------------------------
def recommend(book_name: str):
    if book_name not in pivot_index:
        st.error("Book not found in the similarity dataset!")
        return []

    book_idx = pivot_index.index(book_name)
    distances = similarity[book_idx]
    similar_items = sorted(
        enumerate(distances), key=lambda x: x[1], reverse=True
    )[1:8]  # Top 7 (skip itself)

    recs = []
    for idx, _ in similar_items:
        title = pivot_index[idx]
        img = safe_image_url(title)
        recs.append((title, img))
    return recs

# -------------------------------------------------
# UI: Book selector
# -------------------------------------------------
book_name = st.selectbox(
    "Select a book:",
    options=pivot_index,
    index=None,
    placeholder="Start typing or choose a book..."
)

# -------------------------------------------------
# Recommend button
# -------------------------------------------------
if st.button("Recommend"):
    if not book_name:
        st.warning("Please select a book first!")
    else:
        st.subheader("Recommended Books:")
        with st.spinner("Finding 7 similar books..."):
            time.sleep(0.6)  # Optional: makes spinner visible
            recommendations = recommend(book_name)

        if recommendations:
            # Force image height to 180px
            st.markdown(
                """
                <style>
                .book-img img {
                    height: 180px !important;
                    width: auto !important;
                    object-fit: contain;
                    border-radius: 8px;
                    box-shadow: 0 2px 6px rgba(0,0,0,0.1);
                }
                </style>
                """,
                unsafe_allow_html=True,
            )

            # 7 columns
            cols = st.columns(7, gap="medium")
            for i, (title, img_url) in enumerate(recommendations):
                with cols[i]:
                    st.markdown(
                        f'<div class="book-img"><img src="{img_url}"></div>',
                        unsafe_allow_html=True,
                    )
                    st.caption(title, unsafe_allow_html=True)
        else:
            st.info("No recommendations found.")