Sadmanul commited on
Commit
4c6b43f
·
1 Parent(s): caa0519

add files

Browse files
Files changed (7) hide show
  1. .gitignore +5 -0
  2. Dockerfile +17 -0
  3. README.md +38 -8
  4. app.py +111 -0
  5. code.ipynb +0 -0
  6. model.pkl +3 -0
  7. requirements.txt +5 -0
.gitignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ .env
2
+ .env1
3
+ # model.pkl
4
+ .vscode/
5
+ Datasets/
Dockerfile ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # base image
2
+ FROM python:3.9-slim
3
+
4
+ # workdir
5
+ WORKDIR /app
6
+
7
+ # copy
8
+ COPY . /app
9
+
10
+ # run
11
+ RUN pip install -r requirements.txt
12
+
13
+ # port
14
+ EXPOSE 5000
15
+
16
+ # command
17
+ CMD ["streamlit", "run", "app.py", "--server.port=5000", "--server.address=0.0.0.0", "--server.headless=true"]
README.md CHANGED
@@ -1,11 +1,41 @@
 
 
 
 
 
 
 
 
1
  ---
2
- title: Collaborative Filtering Recommender System
3
- emoji: 🌍
4
- colorFrom: red
5
- colorTo: green
6
- sdk: docker
7
- pinned: false
8
- license: mit
9
  ---
10
 
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🎬 Book Recommender System (Collaborative Filtering)
2
+
3
+ ![Python](https://img.shields.io/badge/Python-3.9%2B-blue.svg)
4
+ ![NLP](https://img.shields.io/badge/Domain-Natural%20Language%20Processing-orange.svg)
5
+ ![Scikit-learn](https://img.shields.io/badge/Library-Scikit--learn-yellow.svg)
6
+ ![Streamlit](https://img.shields.io/badge/Framework-Streamlit-red.svg)
7
+ ![License](https://img.shields.io/badge/License-MIT-green.svg)
8
+
9
  ---
10
+
11
+ ## 📖 Project Overview
12
+
13
+ The **Book Recommender System** is a **collaborative filtering recommendation model** built using Python and NLP techniques.
14
+
 
 
15
  ---
16
 
17
+ ## 🧩 Project Workflow
18
+
19
+ <p align="center">
20
+ <img src="/assets/process_flow.png" alt="Workflow" width="850" style="border-radius:8px;">
21
+ </p>
22
+
23
+ <p align="center">
24
+ <img src="/assets/demo.png" alt="Workflow" width="850" style="border-radius:8px;">
25
+ </p>
26
+
27
+
28
+
29
+
30
+
31
+
32
+ ## 👨‍💻 Author
33
+
34
+ **Sadmanul Hoque**
35
+ 📧 sadmnulhoque21@gmail.com
36
+ 🌐 [LinkedIn Profile](https://www.linkedin.com/in/sadmanul-hoque/)
37
+ 💾 [GitHub Profile](https://github.com/masterArnob)
38
+
39
+
40
+
41
+
app.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import joblib
3
+ import time
4
+
5
+ # -------------------------------------------------
6
+ # Page config & title
7
+ # -------------------------------------------------
8
+ st.set_page_config(page_title="Book Recommender System", layout="wide")
9
+ st.title("Book Recommender System")
10
+
11
+ # -------------------------------------------------
12
+ # Load model (cached once)
13
+ # -------------------------------------------------
14
+ @st.cache_resource
15
+ def load_model():
16
+ model = joblib.load("model.pkl")
17
+ return {
18
+ "data": model["data"],
19
+ "similarity": model["similarity"],
20
+ "pivot_index": model["pivot_index"],
21
+ }
22
+
23
+ with st.spinner("Loading model and book catalogue..."):
24
+ model_data = load_model()
25
+ data = model_data["data"]
26
+ similarity = model_data["similarity"]
27
+ pivot_index = model_data["pivot_index"]
28
+
29
+ st.success(f"Loaded **{len(pivot_index):,}** books successfully!")
30
+
31
+ # -------------------------------------------------
32
+ # Safe image URL
33
+ # -------------------------------------------------
34
+ def safe_image_url(book_name: str) -> str:
35
+ try:
36
+ url = data[data["book_name"] == book_name].iloc[0]["image_url"]
37
+ return url if url and isinstance(url, str) and url.strip() else "https://via.placeholder.com/120x180?text=No+Image"
38
+ except:
39
+ return "https://via.placeholder.com/120x180?text=No+Image"
40
+
41
+ # -------------------------------------------------
42
+ # Recommend 7 books
43
+ # -------------------------------------------------
44
+ def recommend(book_name: str):
45
+ if book_name not in pivot_index:
46
+ st.error("Book not found in the similarity dataset!")
47
+ return []
48
+
49
+ book_idx = pivot_index.index(book_name)
50
+ distances = similarity[book_idx]
51
+ similar_items = sorted(
52
+ enumerate(distances), key=lambda x: x[1], reverse=True
53
+ )[1:8] # Top 7 (skip itself)
54
+
55
+ recs = []
56
+ for idx, _ in similar_items:
57
+ title = pivot_index[idx]
58
+ img = safe_image_url(title)
59
+ recs.append((title, img))
60
+ return recs
61
+
62
+ # -------------------------------------------------
63
+ # UI: Book selector
64
+ # -------------------------------------------------
65
+ book_name = st.selectbox(
66
+ "Select a book:",
67
+ options=pivot_index,
68
+ index=None,
69
+ placeholder="Start typing or choose a book..."
70
+ )
71
+
72
+ # -------------------------------------------------
73
+ # Recommend button
74
+ # -------------------------------------------------
75
+ if st.button("Recommend"):
76
+ if not book_name:
77
+ st.warning("Please select a book first!")
78
+ else:
79
+ st.subheader("Recommended Books:")
80
+ with st.spinner("Finding 7 similar books..."):
81
+ time.sleep(0.6) # Optional: makes spinner visible
82
+ recommendations = recommend(book_name)
83
+
84
+ if recommendations:
85
+ # Force image height to 180px
86
+ st.markdown(
87
+ """
88
+ <style>
89
+ .book-img img {
90
+ height: 180px !important;
91
+ width: auto !important;
92
+ object-fit: contain;
93
+ border-radius: 8px;
94
+ box-shadow: 0 2px 6px rgba(0,0,0,0.1);
95
+ }
96
+ </style>
97
+ """,
98
+ unsafe_allow_html=True,
99
+ )
100
+
101
+ # 7 columns
102
+ cols = st.columns(7, gap="medium")
103
+ for i, (title, img_url) in enumerate(recommendations):
104
+ with cols[i]:
105
+ st.markdown(
106
+ f'<div class="book-img"><img src="{img_url}"></div>',
107
+ unsafe_allow_html=True,
108
+ )
109
+ st.caption(title, unsafe_allow_html=True)
110
+ else:
111
+ st.info("No recommendations found.")
code.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:67cd0b1879c077f3c69a5892ec3ae21e31023cab9d03902ab71d68596d92d573
3
+ size 42839711
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ streamlit==1.50.0
2
+ joblib
3
+ numpy
4
+ pandas
5
+ scikit-learn