Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +105 -67
src/streamlit_app.py
CHANGED
|
@@ -103,7 +103,7 @@ def filter_content(content_list, filters):
|
|
| 103 |
continue
|
| 104 |
|
| 105 |
# Genre filter
|
| 106 |
-
if filters['genres'] and not any(genre in content.get('listed_in', '') for genre in filters['genres']):
|
| 107 |
continue
|
| 108 |
|
| 109 |
# Release year filter
|
|
@@ -123,6 +123,14 @@ def filter_content(content_list, filters):
|
|
| 123 |
continue
|
| 124 |
except (ValueError, IndexError):
|
| 125 |
continue
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
|
| 127 |
filtered.append(content)
|
| 128 |
|
|
@@ -240,52 +248,74 @@ def main():
|
|
| 240 |
|
| 241 |
# Sidebar filters
|
| 242 |
st.sidebar.header("π Filter Content")
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
"
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
"Ratings",
|
| 252 |
-
options=all_ratings,
|
| 253 |
-
default=[]
|
| 254 |
-
)
|
| 255 |
-
|
| 256 |
-
selected_genres = st.sidebar.multiselect(
|
| 257 |
-
"Genres",
|
| 258 |
-
options=all_genres,
|
| 259 |
-
default=[]
|
| 260 |
-
)
|
| 261 |
-
|
| 262 |
-
# Year range slider
|
| 263 |
-
years = [int(c.get('release_year', 0)) for c in all_content if c.get('release_year')]
|
| 264 |
-
min_year, max_year = min(years), max(years)
|
| 265 |
-
year_range = st.sidebar.slider(
|
| 266 |
-
"Release Year",
|
| 267 |
-
min_value=min_year,
|
| 268 |
-
max_value=max_year,
|
| 269 |
-
value=(min_year, max_year)
|
| 270 |
-
)
|
| 271 |
-
|
| 272 |
-
# Duration range slider (for movies only)
|
| 273 |
-
movie_durations = [
|
| 274 |
-
int(c.get('duration', '0 min').split()[0])
|
| 275 |
-
for c in all_content
|
| 276 |
-
if c.get('type') == 'Movie' and 'min' in c.get('duration', '')
|
| 277 |
-
]
|
| 278 |
-
if movie_durations:
|
| 279 |
-
min_duration, max_duration = min(movie_durations), max(movie_durations)
|
| 280 |
-
duration_range = st.sidebar.slider(
|
| 281 |
-
"Movie Duration (minutes)",
|
| 282 |
-
min_value=min_duration,
|
| 283 |
-
max_value=max_duration,
|
| 284 |
-
value=(min_duration, max_duration),
|
| 285 |
-
help="This filter only applies to movies"
|
| 286 |
)
|
| 287 |
-
|
| 288 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
|
| 290 |
# Create filter dictionary
|
| 291 |
filters = {
|
|
@@ -293,22 +323,30 @@ def main():
|
|
| 293 |
'ratings': selected_ratings,
|
| 294 |
'genres': selected_genres,
|
| 295 |
'year_range': year_range,
|
| 296 |
-
'duration_range': duration_range
|
|
|
|
|
|
|
| 297 |
}
|
| 298 |
|
| 299 |
-
#
|
| 300 |
-
|
| 301 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 302 |
# Main content area
|
| 303 |
col1, col2 = st.columns([2, 1])
|
| 304 |
|
| 305 |
with col1:
|
| 306 |
# Content listings
|
| 307 |
-
st.subheader(f"π Found {len(filtered_content)} Titles")
|
| 308 |
|
| 309 |
-
if filtered_content:
|
| 310 |
# Show first 10 items
|
| 311 |
-
for i, content in enumerate(filtered_content[:10]):
|
| 312 |
with st.expander(f"{content.get('title', 'N/A')} ({content.get('release_year', 'N/A')})"):
|
| 313 |
# Content details in columns
|
| 314 |
detail_col1, detail_col2 = st.columns(2)
|
|
@@ -322,7 +360,7 @@ def main():
|
|
| 322 |
st.write(f"**π¬ Genre:** {content.get('listed_in', 'N/A')}")
|
| 323 |
# Fix cast handling to prevent NoneType error
|
| 324 |
cast = content.get('cast')
|
| 325 |
-
cast_display = cast[:100] + "..." if cast else "N/A"
|
| 326 |
st.write(f"**π₯ Cast:** {cast_display}")
|
| 327 |
st.write(f"**π Director:** {content.get('director', 'N/A')}")
|
| 328 |
|
|
@@ -330,8 +368,8 @@ def main():
|
|
| 330 |
st.write(f"**π Description:**")
|
| 331 |
st.write(content.get('description', 'N/A'))
|
| 332 |
|
| 333 |
-
if len(filtered_content) > 10:
|
| 334 |
-
st.info(f"Showing first 10 of {len(filtered_content)} titles. Adjust filters to narrow results.")
|
| 335 |
else:
|
| 336 |
st.info("No content matches your current filters. Try adjusting the criteria.")
|
| 337 |
|
|
@@ -371,7 +409,7 @@ def main():
|
|
| 371 |
if user_question:
|
| 372 |
with st.spinner("AI is analyzing the content..."):
|
| 373 |
# Create context from current filtered data
|
| 374 |
-
context = create_content_context(filtered_content)
|
| 375 |
|
| 376 |
try:
|
| 377 |
# Get AI response
|
|
@@ -383,7 +421,7 @@ def main():
|
|
| 383 |
# Show debug info
|
| 384 |
with st.expander("Debug Info"):
|
| 385 |
st.write(f"Model used: {model_choice}")
|
| 386 |
-
st.write(f"Content items analyzed: {len(filtered_content)}")
|
| 387 |
st.write(f"Context: {context[:150]}...")
|
| 388 |
|
| 389 |
except Exception as e:
|
|
@@ -391,18 +429,18 @@ def main():
|
|
| 391 |
|
| 392 |
# Fallback response with data analysis
|
| 393 |
st.info("**Fallback Analysis:**")
|
| 394 |
-
if filtered_content:
|
| 395 |
-
movies = sum(1 for c in filtered_content if c.get('type') == 'Movie')
|
| 396 |
-
shows = sum(1 for c in filtered_content if c.get('type') == 'TV Show')
|
| 397 |
-
st.write(f"β’ Found {len(filtered_content)} titles ({movies} movies, {shows} TV shows)")
|
| 398 |
|
| 399 |
# Show top genres
|
| 400 |
-
genres = [g.strip() for c in filtered_content for g in c.get('listed_in', '').split(',')]
|
| 401 |
genre_counts = pd.Series(genres).value_counts()
|
| 402 |
st.write(f"β’ Top genres: {', '.join(genre_counts.head(3).index)}")
|
| 403 |
|
| 404 |
# Show year range
|
| 405 |
-
years = [int(c.get('release_year', 0)) for c in filtered_content if c.get('release_year')]
|
| 406 |
if years:
|
| 407 |
st.write(f"β’ Release years: {min(years)} - {max(years)}")
|
| 408 |
else:
|
|
@@ -412,7 +450,7 @@ def main():
|
|
| 412 |
st.markdown("---")
|
| 413 |
if all_content:
|
| 414 |
total_items = len(all_content)
|
| 415 |
-
filtered_items = len(filtered_content)
|
| 416 |
|
| 417 |
stat_col1, stat_col2, stat_col3, stat_col4 = st.columns(4)
|
| 418 |
|
|
@@ -423,11 +461,11 @@ def main():
|
|
| 423 |
st.metric("Filtered Results", filtered_items)
|
| 424 |
|
| 425 |
with stat_col3:
|
| 426 |
-
movies = sum(1 for c in filtered_content if c.get('type') == 'Movie')
|
| 427 |
st.metric("Movies", movies)
|
| 428 |
|
| 429 |
with stat_col4:
|
| 430 |
-
shows = sum(1 for c in filtered_content if c.get('type') == 'TV Show')
|
| 431 |
st.metric("TV Shows", shows)
|
| 432 |
|
| 433 |
if __name__ == "__main__":
|
|
|
|
| 103 |
continue
|
| 104 |
|
| 105 |
# Genre filter
|
| 106 |
+
if filters['genres'] and not any(genre.strip() in content.get('listed_in', '') for genre in filters['genres']):
|
| 107 |
continue
|
| 108 |
|
| 109 |
# Release year filter
|
|
|
|
| 123 |
continue
|
| 124 |
except (ValueError, IndexError):
|
| 125 |
continue
|
| 126 |
+
|
| 127 |
+
# Director filter (optional)
|
| 128 |
+
if filters['director'] and filters['director'].lower() not in content.get('director', '').lower():
|
| 129 |
+
continue
|
| 130 |
+
|
| 131 |
+
# Cast filter (optional)
|
| 132 |
+
if filters['cast'] and filters['cast'].lower() not in content.get('cast', '').lower():
|
| 133 |
+
continue
|
| 134 |
|
| 135 |
filtered.append(content)
|
| 136 |
|
|
|
|
| 248 |
|
| 249 |
# Sidebar filters
|
| 250 |
st.sidebar.header("π Filter Content")
|
| 251 |
+
|
| 252 |
+
with st.sidebar.form("filter_form"):
|
| 253 |
+
st.subheader("Required Filters")
|
| 254 |
+
|
| 255 |
+
content_type = st.selectbox(
|
| 256 |
+
"Content Type",
|
| 257 |
+
options=["All", "Movie", "TV Show"],
|
| 258 |
+
index=0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 259 |
)
|
| 260 |
+
|
| 261 |
+
selected_ratings = st.multiselect(
|
| 262 |
+
"Ratings",
|
| 263 |
+
options=all_ratings,
|
| 264 |
+
default=[]
|
| 265 |
+
)
|
| 266 |
+
|
| 267 |
+
selected_genres = st.multiselect(
|
| 268 |
+
"Genres",
|
| 269 |
+
options=all_genres,
|
| 270 |
+
default=[]
|
| 271 |
+
)
|
| 272 |
+
|
| 273 |
+
# Year range slider
|
| 274 |
+
years = [int(c.get('release_year', 0)) for c in all_content if c.get('release_year')]
|
| 275 |
+
min_year, max_year = min(years), max(years)
|
| 276 |
+
year_range = st.slider(
|
| 277 |
+
"Release Year",
|
| 278 |
+
min_value=min_year,
|
| 279 |
+
max_value=max_year,
|
| 280 |
+
value=(min_year, max_year)
|
| 281 |
+
)
|
| 282 |
+
|
| 283 |
+
# Duration range slider (for movies only)
|
| 284 |
+
movie_durations = [
|
| 285 |
+
int(c.get('duration', '0 min').split()[0])
|
| 286 |
+
for c in all_content
|
| 287 |
+
if c.get('type') == 'Movie' and 'min' in c.get('duration', '')
|
| 288 |
+
]
|
| 289 |
+
if movie_durations:
|
| 290 |
+
min_duration, max_duration = min(movie_durations), max(movie_durations)
|
| 291 |
+
duration_range = st.slider(
|
| 292 |
+
"Movie Duration (minutes)",
|
| 293 |
+
min_value=min_duration,
|
| 294 |
+
max_value=max_duration,
|
| 295 |
+
value=(min_duration, max_duration),
|
| 296 |
+
help="This filter only applies to movies"
|
| 297 |
+
)
|
| 298 |
+
else:
|
| 299 |
+
duration_range = (0, 1000) # Fallback values
|
| 300 |
+
|
| 301 |
+
st.subheader("Optional Filters")
|
| 302 |
+
|
| 303 |
+
# Director filter
|
| 304 |
+
director_filter = st.text_input(
|
| 305 |
+
"Director Name",
|
| 306 |
+
placeholder="Enter director name...",
|
| 307 |
+
help="Filter by director name (case-insensitive, partial match)"
|
| 308 |
+
)
|
| 309 |
+
|
| 310 |
+
# Cast filter
|
| 311 |
+
cast_filter = st.text_input(
|
| 312 |
+
"Cast Member",
|
| 313 |
+
placeholder="Enter cast member name...",
|
| 314 |
+
help="Filter by cast member name (case-insensitive, partial match)"
|
| 315 |
+
)
|
| 316 |
+
|
| 317 |
+
# Submit button
|
| 318 |
+
apply_filters = st.form_submit_button("π Apply Filters", type="primary")
|
| 319 |
|
| 320 |
# Create filter dictionary
|
| 321 |
filters = {
|
|
|
|
| 323 |
'ratings': selected_ratings,
|
| 324 |
'genres': selected_genres,
|
| 325 |
'year_range': year_range,
|
| 326 |
+
'duration_range': duration_range,
|
| 327 |
+
'director': director_filter,
|
| 328 |
+
'cast': cast_filter
|
| 329 |
}
|
| 330 |
|
| 331 |
+
# Only apply filters when the button is clicked
|
| 332 |
+
if apply_filters:
|
| 333 |
+
filtered_content = filter_content(all_content, filters)
|
| 334 |
+
st.session_state.filtered_content = filtered_content
|
| 335 |
+
else:
|
| 336 |
+
# Initialize filtered content if not exists
|
| 337 |
+
if 'filtered_content' not in st.session_state:
|
| 338 |
+
st.session_state.filtered_content = all_content
|
| 339 |
+
|
| 340 |
# Main content area
|
| 341 |
col1, col2 = st.columns([2, 1])
|
| 342 |
|
| 343 |
with col1:
|
| 344 |
# Content listings
|
| 345 |
+
st.subheader(f"π Found {len(st.session_state.filtered_content)} Titles")
|
| 346 |
|
| 347 |
+
if st.session_state.filtered_content:
|
| 348 |
# Show first 10 items
|
| 349 |
+
for i, content in enumerate(st.session_state.filtered_content[:10]):
|
| 350 |
with st.expander(f"{content.get('title', 'N/A')} ({content.get('release_year', 'N/A')})"):
|
| 351 |
# Content details in columns
|
| 352 |
detail_col1, detail_col2 = st.columns(2)
|
|
|
|
| 360 |
st.write(f"**π¬ Genre:** {content.get('listed_in', 'N/A')}")
|
| 361 |
# Fix cast handling to prevent NoneType error
|
| 362 |
cast = content.get('cast')
|
| 363 |
+
cast_display = cast[:100] + "..." if cast and len(cast) > 100 else cast if cast else "N/A"
|
| 364 |
st.write(f"**π₯ Cast:** {cast_display}")
|
| 365 |
st.write(f"**π Director:** {content.get('director', 'N/A')}")
|
| 366 |
|
|
|
|
| 368 |
st.write(f"**π Description:**")
|
| 369 |
st.write(content.get('description', 'N/A'))
|
| 370 |
|
| 371 |
+
if len(st.session_state.filtered_content) > 10:
|
| 372 |
+
st.info(f"Showing first 10 of {len(st.session_state.filtered_content)} titles. Adjust filters to narrow results.")
|
| 373 |
else:
|
| 374 |
st.info("No content matches your current filters. Try adjusting the criteria.")
|
| 375 |
|
|
|
|
| 409 |
if user_question:
|
| 410 |
with st.spinner("AI is analyzing the content..."):
|
| 411 |
# Create context from current filtered data
|
| 412 |
+
context = create_content_context(st.session_state.filtered_content)
|
| 413 |
|
| 414 |
try:
|
| 415 |
# Get AI response
|
|
|
|
| 421 |
# Show debug info
|
| 422 |
with st.expander("Debug Info"):
|
| 423 |
st.write(f"Model used: {model_choice}")
|
| 424 |
+
st.write(f"Content items analyzed: {len(st.session_state.filtered_content)}")
|
| 425 |
st.write(f"Context: {context[:150]}...")
|
| 426 |
|
| 427 |
except Exception as e:
|
|
|
|
| 429 |
|
| 430 |
# Fallback response with data analysis
|
| 431 |
st.info("**Fallback Analysis:**")
|
| 432 |
+
if st.session_state.filtered_content:
|
| 433 |
+
movies = sum(1 for c in st.session_state.filtered_content if c.get('type') == 'Movie')
|
| 434 |
+
shows = sum(1 for c in st.session_state.filtered_content if c.get('type') == 'TV Show')
|
| 435 |
+
st.write(f"β’ Found {len(st.session_state.filtered_content)} titles ({movies} movies, {shows} TV shows)")
|
| 436 |
|
| 437 |
# Show top genres
|
| 438 |
+
genres = [g.strip() for c in st.session_state.filtered_content for g in c.get('listed_in', '').split(',')]
|
| 439 |
genre_counts = pd.Series(genres).value_counts()
|
| 440 |
st.write(f"β’ Top genres: {', '.join(genre_counts.head(3).index)}")
|
| 441 |
|
| 442 |
# Show year range
|
| 443 |
+
years = [int(c.get('release_year', 0)) for c in st.session_state.filtered_content if c.get('release_year')]
|
| 444 |
if years:
|
| 445 |
st.write(f"β’ Release years: {min(years)} - {max(years)}")
|
| 446 |
else:
|
|
|
|
| 450 |
st.markdown("---")
|
| 451 |
if all_content:
|
| 452 |
total_items = len(all_content)
|
| 453 |
+
filtered_items = len(st.session_state.filtered_content)
|
| 454 |
|
| 455 |
stat_col1, stat_col2, stat_col3, stat_col4 = st.columns(4)
|
| 456 |
|
|
|
|
| 461 |
st.metric("Filtered Results", filtered_items)
|
| 462 |
|
| 463 |
with stat_col3:
|
| 464 |
+
movies = sum(1 for c in st.session_state.filtered_content if c.get('type') == 'Movie')
|
| 465 |
st.metric("Movies", movies)
|
| 466 |
|
| 467 |
with stat_col4:
|
| 468 |
+
shows = sum(1 for c in st.session_state.filtered_content if c.get('type') == 'TV Show')
|
| 469 |
st.metric("TV Shows", shows)
|
| 470 |
|
| 471 |
if __name__ == "__main__":
|