deathbladegod020 commited on
Commit
90df448
·
1 Parent(s): d896e62

Initial commit

Browse files
Files changed (4) hide show
  1. app.py +132 -0
  2. books_summary.csv +0 -0
  3. requirements.txt +6 -0
  4. semantic_embeddings.npy +3 -0
app.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ from sklearn.feature_extraction.text import TfidfVectorizer
3
+ from sklearn.metrics.pairwise import cosine_similarity
4
+ from sklearn.neighbors import NearestNeighbors
5
+ from sentence_transformers import SentenceTransformer
6
+ import numpy as np
7
+ import streamlit as st
8
+ import os
9
+ from rapidfuzz import process
10
+ import re
11
+
12
+ def load_data(filepath):
13
+ """Load and deduplicate the dataset."""
14
+ data = pd.read_csv(filepath)
15
+ data = data.drop_duplicates(subset=['book_name'], keep='first').reset_index(drop=True)
16
+ return data
17
+
18
+ def preprocess_data(data):
19
+ """Preprocess the dataset by cleaning text fields."""
20
+ data['book_name'] = data['book_name'].fillna('').str.lower()
21
+ data['summaries'] = data['summaries'].fillna('').str.lower()
22
+ data['categories'] = data['categories'].fillna('').str.lower()
23
+ data['combined_text'] = (
24
+ data['book_name'] + ' ' +
25
+ data['summaries'] * 2 + ' ' +
26
+ data['categories']
27
+ )
28
+ return data
29
+
30
+ def feature_engineering(data):
31
+ """Generate features using TF-IDF and SentenceTransformer embeddings."""
32
+ # TF-IDF Vectorization
33
+ vectorizer = TfidfVectorizer(stop_words='english')
34
+ tfidf_matrix = vectorizer.fit_transform(data['combined_text'])
35
+
36
+ # SentenceTransformer embeddings
37
+ model = SentenceTransformer('paraphrase-MiniLM-L3-v2')
38
+ embeddings_file = "semantic_embeddings.npy"
39
+ if not os.path.exists(embeddings_file):
40
+ data['semantic_embeddings'] = data['combined_text'].apply(lambda x: model.encode(x))
41
+ np.save(embeddings_file, np.vstack(data['semantic_embeddings']))
42
+ else:
43
+ semantic_embeddings = np.load(embeddings_file)
44
+ data['semantic_embeddings'] = [embedding for embedding in semantic_embeddings]
45
+
46
+ # Fit NearestNeighbors model
47
+ nn_model = NearestNeighbors(metric='cosine', algorithm='auto')
48
+ nn_model.fit(np.vstack(data['semantic_embeddings']))
49
+
50
+ return vectorizer, tfidf_matrix, model, nn_model
51
+
52
+ def calculate_similarity(input_title, data, vectorizer, tfidf_matrix, model, nn_model, n_recommendations=5, min_similarity=0.3):
53
+ """Calculate similarities and generate recommendations."""
54
+ try:
55
+ # Compute TF-IDF similarity
56
+ input_vector = vectorizer.transform([input_title.lower()])
57
+ cosine_similarities = cosine_similarity(input_vector, tfidf_matrix).flatten()
58
+ min_similarity = max(0.1, cosine_similarities.mean() - cosine_similarities.std())
59
+
60
+ # Compute semantic similarity using NearestNeighbors
61
+ input_embedding = model.encode(input_title.lower())
62
+ distances, indices = nn_model.kneighbors([input_embedding], n_neighbors=len(data))
63
+
64
+ # Combine similarities
65
+ recommended_books = []
66
+ seen_titles = set()
67
+
68
+ for idx, dist in zip(indices[0], distances[0]):
69
+ book_title = data['book_name'].iloc[idx]
70
+ round_sim_value = round(1 - dist, 2) # Convert distance to similarity
71
+ if book_title not in seen_titles and round_sim_value >= min_similarity and str(book_title).lower() != str(input_title).lower():
72
+ recommended_books.append((book_title, round_sim_value))
73
+ seen_titles.add(book_title)
74
+ if len(recommended_books) == n_recommendations:
75
+ break
76
+
77
+ # If no meaningful recommendations, return fallback message
78
+ if not any(score >= min_similarity for _, score in recommended_books):
79
+ return [("No meaningful recommendations found.", 0.0)]
80
+
81
+ return recommended_books
82
+ except Exception as e:
83
+ return [(f"An error occurred: {str(e)}", 0.0)]
84
+
85
+ def validate_input(input_title, data, threshold=70):
86
+ """Validate input title using fuzzy matching against dataset titles."""
87
+ titles = data['book_name'].tolist()
88
+ closest_match, score, _ = process.extractOne(input_title, titles)
89
+ if score >= threshold:
90
+ return closest_match
91
+ return None
92
+
93
+ def deploy_ui(data, vectorizer, tfidf_matrix, model, nn_model):
94
+ """Streamlit-based UI for interacting with the recommendation system."""
95
+ st.title("Content-Based Book Recommender")
96
+ st.write("Enter a book title to get up to 5 similar recommendations.")
97
+ book_title = st.text_input("Enter a book title")
98
+
99
+ if st.button("Submit"):
100
+ # Input validation
101
+ if len(book_title.strip()) < 3:
102
+ st.write("Input is too short. Please enter a meaningful book title.")
103
+ return
104
+
105
+ # Fuzzy matching for known titles
106
+ closest_title = validate_input(book_title, data)
107
+ if closest_title:
108
+ st.write(f"Did you mean: {closest_title}?")
109
+ book_title = closest_title
110
+
111
+ # Generate recommendations
112
+ recommendations = calculate_similarity(book_title, data, vectorizer, tfidf_matrix, model, nn_model, min_similarity=0.3)
113
+ if "error" in recommendations[0][0]:
114
+ st.write("Error occured. Please try again later")
115
+
116
+ elif recommendations is None or len(recommendations) == 0 or recommendations[0][0] == "No meaningful recommendations found.":
117
+ st.write("No meaningful recommendations found for the input. Please try again with a different title.")
118
+ else:
119
+ st.write("Recommended Books:")
120
+ idx = 1
121
+ for book, score in recommendations:
122
+ cleaned_book = re.sub(r"[^A-Za-z0-9]+$", "", book)
123
+ st.write(f"{idx}: {cleaned_book}")
124
+ idx += 1
125
+
126
+
127
+ if __name__ == "__main__":
128
+ filepath = "books_summary.csv"
129
+ data = load_data(filepath)
130
+ data = preprocess_data(data)
131
+ vectorizer, tfidf_matrix, model, nn_model = feature_engineering(data)
132
+ deploy_ui(data, vectorizer, tfidf_matrix, model, nn_model)
books_summary.csv ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ streamlit
2
+ pandas
3
+ scikit-learn
4
+ sentence-transformers
5
+ numpy
6
+ rapidfuzz
semantic_embeddings.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fca7d1a53c7299e5278cdbb7fe42495072d0eb5d96676431ece0d6b68ebf4043
3
+ size 1890944