handex commited on
Commit
8b49811
·
verified ·
1 Parent(s): 5363f0f

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +55 -42
src/streamlit_app.py CHANGED
@@ -9,45 +9,38 @@ from sklearn.metrics.pairwise import cosine_similarity
9
  # File paths for model persistence
10
  VECTORIZER_PATH = 'src/article_vectorizer.joblib'
11
  TFIDF_MATRIX_PATH = 'src/article_matrix.joblib'
 
12
 
13
  # Number of recommendations to display
14
  NUM_RECOMMENDATIONS = 5
15
 
16
- # --- Mock Data Setup (Replace with your actual data loading if necessary) ---
17
  @st.cache_data
18
  def load_and_prepare_data():
19
- """Creates a mock DataFrame for demonstration."""
20
- data = {
21
- "Title": [
22
- "Introduction to Machine Learning",
23
- "Deep Learning: Neural Networks Explained",
24
- "Python for Data Science and Analysis",
25
- "The Ethical Future of Artificial Intelligence",
26
- "Understanding Vector Space Models in NLP",
27
- "Essential Data Cleaning Techniques",
28
- "Advanced Time Series Forecasting",
29
- "Web Scraping with Python and BeautifulSoup",
30
- "Cloud Computing Fundamentals",
31
- "Agile Software Development Methodologies"
32
- ],
33
- "Article": [
34
- "Machine learning is a field of computer science that uses statistical techniques to give computer systems the ability to 'learn' with data, without being explicitly programmed. It is a subset of AI and heavily relies on linear algebra.",
35
- "Deep learning is a subset of ML that uses neural networks with three or more layers to analyze complex data structures. It is currently the state-of-the-art for image recognition and natural language processing tasks. Understanding the architecture is key.",
36
- "Python is a high-level, interpreted programming language widely used in data science, especially due to libraries like Pandas, NumPy, and Scikit-learn. Its simplicity makes data manipulation and analysis easy.",
37
- "The future of artificial intelligence involves complex models, ethical guidelines, and responsible integration into all sectors. Researchers predict significant advancements in natural language processing and computer vision.",
38
- "Vectors are fundamental objects in linear algebra and are crucial for representing words in a TF-IDF or Word2Vec model. Understanding vector math is key to similarity calculations and NLP.",
39
- "Cleaning data is the most time-consuming part of any data science project. Techniques involve handling missing values, outliers, and inconsistencies to prepare data for robust modeling.",
40
- "Time series forecasting involves predicting future values based on historically observed values. Methods include ARIMA, Prophet, and advanced deep learning models like LSTMs for complex patterns.",
41
- "Web scraping is the process of extracting data from websites. Python libraries like Requests and BeautifulSoup are commonly used to parse HTML and gather structured information efficiently.",
42
- "Cloud computing offers on-demand availability of computer system resources, especially data storage and computing power, without direct active management by the user. Major providers are AWS, Azure, and Google Cloud.",
43
- "Agile is an iterative approach to project management and software development that helps teams deliver value faster and with fewer headaches. It involves concepts like Scrum and Kanban."
44
- ]
45
- }
46
- df = pd.DataFrame(data)
47
- # 1. DEFENSIVE FIX: Ensure the index is a clean, contiguous 0-based positional index
48
  df = df.reset_index(drop=True)
49
- # Ensure all text is string type
50
  df['Article'] = df['Article'].astype(str)
 
51
  return df
52
 
53
  # --- Model Fitting/Loading Logic ---
@@ -58,13 +51,18 @@ def fit_or_load_models(df):
58
  Fits the TF-IDF model and calculates Cosine Similarity,
59
  or loads them from disk if available.
60
  """
 
 
 
 
 
61
  if os.path.exists(VECTORIZER_PATH) and os.path.exists(TFIDF_MATRIX_PATH):
62
  try:
63
  # Load existing models
64
  tfidf = joblib.load(VECTORIZER_PATH)
65
  tfidf_matrix = joblib.load(TFIDF_MATRIX_PATH)
66
 
67
- # Recalculate cosine similarity just in case the data changed or for the current run
68
  cosine_sim = cosine_similarity(tfidf_matrix)
69
  st.success("Models loaded successfully from disk.")
70
  return tfidf, tfidf_matrix, cosine_sim
@@ -112,9 +110,9 @@ def get_recommendations(article_index, cosine_sim_matrix, df, num_recommendation
112
  # Get the indices of the top N recommended articles (these are positional indices)
113
  top_n_indices = [i[0] for i in top_n_recommendations]
114
 
115
- # Get the titles
116
- # Since df now has a clean 0-based index, .iloc should be safe here.
117
- recommended_titles = df["Title"].iloc[top_n_indices].tolist()
118
 
119
  # Get the similarity scores for display (rounded)
120
  recommended_scores = [round(i[1] * 100, 2) for i in top_n_recommendations]
@@ -130,11 +128,22 @@ def app():
130
  st.title("📄 Content-Based Article Recommender")
131
  st.markdown("This system uses TF-IDF vectorization and Cosine Similarity to recommend articles based on content matching.")
132
 
133
- # 1. Load Data and Models
134
  df = load_and_prepare_data()
135
- # The returned values are already cached, so this is fast on subsequent runs
 
 
 
 
 
 
136
  tfidf, tfidf_matrix, cosine_sim = fit_or_load_models(df)
137
 
 
 
 
 
 
138
  # --- Sidebar for Selection ---
139
 
140
  # Create a list of titles for the selectbox
@@ -148,14 +157,14 @@ def app():
148
 
149
  # Find the index of the selected article
150
  if selected_title:
151
- # 2. DEFENSIVE FIX: Use .tolist().index() to guarantee a 0-based positional index
152
- # This index is required for looking up the row in cosine_sim (0 to N-1)
153
  try:
154
  selected_index = df['Title'].tolist().index(selected_title)
155
  except ValueError:
156
  st.error("Error finding article index. Check data consistency.")
157
  return
158
  else:
 
159
  st.error("No article selected.")
160
  return
161
 
@@ -163,10 +172,10 @@ def app():
163
 
164
  st.header(f"Recommendations for: **{selected_title}**")
165
 
166
- # 2. Get Recommendations
167
  recommendations_list = get_recommendations(selected_index, cosine_sim, df)
168
 
169
- # 3. Display Results
170
  if recommendations_list:
171
  st.subheader(f"Top {NUM_RECOMMENDATIONS} Most Similar Articles:")
172
 
@@ -191,7 +200,11 @@ def app():
191
  2. **Similarity:** Cosine Similarity measures the angle between vectors to determine content similarity.
192
  3. **Result:** Articles with the smallest angle (highest score) are recommended.
193
  """)
 
 
 
 
 
194
 
195
  if __name__ == "__main__":
196
- # Ensure Streamlit is run via the command line interface
197
  app()
 
9
  # File paths for model persistence
10
  VECTORIZER_PATH = 'src/article_vectorizer.joblib'
11
  TFIDF_MATRIX_PATH = 'src/article_matrix.joblib'
12
+ DATA_FILE_PATH = 'src/articles.csv'
13
 
14
  # Number of recommendations to display
15
  NUM_RECOMMENDATIONS = 5
16
 
17
+ # --- Data Loading and Preparation (Removed mock data dependency) ---
18
  @st.cache_data
19
  def load_and_prepare_data():
20
+ """
21
+ Loads data ONLY from articles.csv and prepares the DataFrame.
22
+ If the file is not found or reading fails, it returns an empty DataFrame.
23
+ """
24
+ df = pd.DataFrame() # Initialize an empty DataFrame
25
+
26
+ if os.path.exists(DATA_FILE_PATH):
27
+ try:
28
+ df = pd.read_csv(DATA_FILE_PATH)
29
+ st.success(f"Data loaded successfully from {DATA_FILE_PATH}.")
30
+ except Exception as e:
31
+ st.error(f"Error reading {DATA_FILE_PATH}. Please check file integrity and format (CSV). Error: {e}")
32
+ else:
33
+ st.error(f"CRITICAL ERROR: {DATA_FILE_PATH} not found. Please upload the file to your application directory.")
34
+
35
+ if df.empty or 'Article' not in df.columns or 'Title' not in df.columns:
36
+ # If loading failed or columns are missing, return empty or incomplete DataFrame
37
+ return pd.DataFrame()
38
+
39
+ # 1. Ensure the index is a clean, contiguous 0-based positional index
 
 
 
 
 
 
 
 
 
40
  df = df.reset_index(drop=True)
41
+ # Ensure the article column is string type
42
  df['Article'] = df['Article'].astype(str)
43
+
44
  return df
45
 
46
  # --- Model Fitting/Loading Logic ---
 
51
  Fits the TF-IDF model and calculates Cosine Similarity,
52
  or loads them from disk if available.
53
  """
54
+ # Check if the necessary columns exist before proceeding
55
+ if df.empty or 'Article' not in df.columns or 'Title' not in df.columns:
56
+ # This check should be redundant if load_and_prepare_data works, but good for defense
57
+ return None, None, None
58
+
59
  if os.path.exists(VECTORIZER_PATH) and os.path.exists(TFIDF_MATRIX_PATH):
60
  try:
61
  # Load existing models
62
  tfidf = joblib.load(VECTORIZER_PATH)
63
  tfidf_matrix = joblib.load(TFIDF_MATRIX_PATH)
64
 
65
+ # Recalculate cosine similarity (This is fast on the loaded matrix)
66
  cosine_sim = cosine_similarity(tfidf_matrix)
67
  st.success("Models loaded successfully from disk.")
68
  return tfidf, tfidf_matrix, cosine_sim
 
110
  # Get the indices of the top N recommended articles (these are positional indices)
111
  top_n_indices = [i[0] for i in top_n_recommendations]
112
 
113
+ # --- CRITICAL FIX: Use list indexing instead of DataFrame .iloc to guarantee positional lookup ---
114
+ title_list = df["Title"].tolist()
115
+ recommended_titles = [title_list[i] for i in top_n_indices]
116
 
117
  # Get the similarity scores for display (rounded)
118
  recommended_scores = [round(i[1] * 100, 2) for i in top_n_recommendations]
 
128
  st.title("📄 Content-Based Article Recommender")
129
  st.markdown("This system uses TF-IDF vectorization and Cosine Similarity to recommend articles based on content matching.")
130
 
131
+ # 1. Load Data
132
  df = load_and_prepare_data()
133
+
134
+ # Check if data loading was successful and essential columns exist
135
+ if df.empty or 'Article' not in df.columns or 'Title' not in df.columns:
136
+ st.error("Application cannot start: Please ensure 'articles.csv' is uploaded and contains 'Title' and 'Article' columns.")
137
+ return
138
+
139
+ # 2. Load/Fit Models
140
  tfidf, tfidf_matrix, cosine_sim = fit_or_load_models(df)
141
 
142
+ # Check if models were loaded/calculated successfully
143
+ if cosine_sim is None:
144
+ st.error("Application cannot start: Model calculation failed.")
145
+ return
146
+
147
  # --- Sidebar for Selection ---
148
 
149
  # Create a list of titles for the selectbox
 
157
 
158
  # Find the index of the selected article
159
  if selected_title:
160
+ # Use .tolist().index() to guarantee a 0-based positional index
 
161
  try:
162
  selected_index = df['Title'].tolist().index(selected_title)
163
  except ValueError:
164
  st.error("Error finding article index. Check data consistency.")
165
  return
166
  else:
167
+ # Should not happen if article_titles is non-empty
168
  st.error("No article selected.")
169
  return
170
 
 
172
 
173
  st.header(f"Recommendations for: **{selected_title}**")
174
 
175
+ # 3. Get Recommendations
176
  recommendations_list = get_recommendations(selected_index, cosine_sim, df)
177
 
178
+ # 4. Display Results
179
  if recommendations_list:
180
  st.subheader(f"Top {NUM_RECOMMENDATIONS} Most Similar Articles:")
181
 
 
200
  2. **Similarity:** Cosine Similarity measures the angle between vectors to determine content similarity.
201
  3. **Result:** Articles with the smallest angle (highest score) are recommended.
202
  """)
203
+
204
+ # Add a section to show the current article's content
205
+ st.subheader("Current Article Content:")
206
+ article_content = df.iloc[selected_index]['Article']
207
+ st.markdown(f"*{article_content}*")
208
 
209
  if __name__ == "__main__":
 
210
  app()