Spaces:
Sleeping
Sleeping
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +49 -23
src/streamlit_app.py
CHANGED
|
@@ -43,8 +43,8 @@ def get_ai_client():
|
|
| 43 |
# HELPER FUNCTIONS
|
| 44 |
# =============================================================================
|
| 45 |
@st.cache_data(ttl=300) # Cache for 5 minutes
|
| 46 |
-
def
|
| 47 |
-
"""Fetch
|
| 48 |
api_token, _ = get_api_credentials()
|
| 49 |
|
| 50 |
if not api_token:
|
|
@@ -64,7 +64,7 @@ def get_netflix_content():
|
|
| 64 |
while True:
|
| 65 |
offset = (page - 1) * page_size
|
| 66 |
response = requests.get(
|
| 67 |
-
f"{NOCODB_URL}/
|
| 68 |
headers=headers
|
| 69 |
)
|
| 70 |
|
|
@@ -94,14 +94,17 @@ def get_netflix_content():
|
|
| 94 |
return []
|
| 95 |
|
| 96 |
def filter_content(content_list, filters):
|
| 97 |
-
"""Apply filters to
|
| 98 |
filtered = []
|
| 99 |
|
| 100 |
for content in content_list:
|
| 101 |
matches_all_filters = True
|
| 102 |
|
| 103 |
-
#
|
| 104 |
-
|
|
|
|
|
|
|
|
|
|
| 105 |
|
| 106 |
# Type filter - only apply if not "All"
|
| 107 |
if filters['content_type']:
|
|
@@ -303,14 +306,14 @@ def find_similar_content(content_list, selected_content, n_clusters=20, n_recomm
|
|
| 303 |
def main():
|
| 304 |
# Page config
|
| 305 |
st.set_page_config(
|
| 306 |
-
page_title="
|
| 307 |
page_icon="π¬",
|
| 308 |
layout="wide"
|
| 309 |
)
|
| 310 |
|
| 311 |
# Header
|
| 312 |
-
st.title("π¬
|
| 313 |
-
st.write("Explore
|
| 314 |
|
| 315 |
# Check API credentials
|
| 316 |
api_token, together_key = get_api_credentials()
|
|
@@ -335,11 +338,11 @@ def main():
|
|
| 335 |
st.stop()
|
| 336 |
|
| 337 |
# Load all content first
|
| 338 |
-
with st.spinner("Loading
|
| 339 |
-
all_content =
|
| 340 |
|
| 341 |
if not all_content:
|
| 342 |
-
st.error("Could not load
|
| 343 |
st.stop()
|
| 344 |
|
| 345 |
# Extract unique values for filters
|
|
@@ -350,6 +353,7 @@ def main():
|
|
| 350 |
for genre in c.get('listed_in', '').split(',')
|
| 351 |
if genre.strip()
|
| 352 |
)))
|
|
|
|
| 353 |
|
| 354 |
# Extract unique directors and cast members
|
| 355 |
all_directors = extract_unique_names(all_content, 'director')
|
|
@@ -359,7 +363,21 @@ def main():
|
|
| 359 |
st.sidebar.header("π Filter Content")
|
| 360 |
|
| 361 |
with st.sidebar.form("filter_form"):
|
| 362 |
-
st.subheader("
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 363 |
|
| 364 |
content_type = st.selectbox(
|
| 365 |
"Content Type",
|
|
@@ -435,6 +453,7 @@ def main():
|
|
| 435 |
|
| 436 |
# Create filter dictionary
|
| 437 |
filters = {
|
|
|
|
| 438 |
'content_type': content_type if content_type != "All" else None,
|
| 439 |
'ratings': selected_ratings,
|
| 440 |
'genres': selected_genres,
|
|
@@ -486,6 +505,7 @@ def main():
|
|
| 486 |
detail_col1, detail_col2 = st.columns(2)
|
| 487 |
|
| 488 |
with detail_col1:
|
|
|
|
| 489 |
st.write(f"**π Type:** {content.get('type', 'N/A')}")
|
| 490 |
st.write(f"**β Rating:** {content.get('rating', 'N/A')}")
|
| 491 |
st.write(f"**β±οΈ Duration:** {content.get('duration', 'N/A')}")
|
|
@@ -524,7 +544,7 @@ def main():
|
|
| 524 |
with col2:
|
| 525 |
# AI Chat Section
|
| 526 |
st.subheader("π€ Ask AI Assistant")
|
| 527 |
-
st.write("Ask questions about the
|
| 528 |
|
| 529 |
# Model selection for Together AI
|
| 530 |
model_choice = st.selectbox(
|
|
@@ -600,21 +620,27 @@ def main():
|
|
| 600 |
total_items = len(all_content)
|
| 601 |
filtered_items = len(st.session_state.filtered_content)
|
| 602 |
|
| 603 |
-
|
|
|
|
| 604 |
|
| 605 |
-
|
| 606 |
-
|
|
|
|
| 607 |
|
| 608 |
-
with
|
| 609 |
st.metric("Filtered Results", filtered_items)
|
| 610 |
|
| 611 |
-
with
|
| 612 |
movies = sum(1 for c in st.session_state.filtered_content if c.get('type') == 'Movie')
|
| 613 |
-
st.metric("Movies", movies)
|
| 614 |
-
|
| 615 |
-
with stat_col4:
|
| 616 |
shows = sum(1 for c in st.session_state.filtered_content if c.get('type') == 'TV Show')
|
| 617 |
-
st.metric("
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 618 |
|
| 619 |
if __name__ == "__main__":
|
| 620 |
main()
|
|
|
|
| 43 |
# HELPER FUNCTIONS
|
| 44 |
# =============================================================================
|
| 45 |
@st.cache_data(ttl=300) # Cache for 5 minutes
|
| 46 |
+
def get_streaming_content():
|
| 47 |
+
"""Fetch streaming content from NocoDB with pagination"""
|
| 48 |
api_token, _ = get_api_credentials()
|
| 49 |
|
| 50 |
if not api_token:
|
|
|
|
| 64 |
while True:
|
| 65 |
offset = (page - 1) * page_size
|
| 66 |
response = requests.get(
|
| 67 |
+
f"{NOCODB_URL}/cleaned_combined_streaming?limit={page_size}&offset={offset}",
|
| 68 |
headers=headers
|
| 69 |
)
|
| 70 |
|
|
|
|
| 94 |
return []
|
| 95 |
|
| 96 |
def filter_content(content_list, filters):
|
| 97 |
+
"""Apply filters to streaming content list"""
|
| 98 |
filtered = []
|
| 99 |
|
| 100 |
for content in content_list:
|
| 101 |
matches_all_filters = True
|
| 102 |
|
| 103 |
+
# Streaming service filter
|
| 104 |
+
if filters['streaming_services']:
|
| 105 |
+
if content.get('streaming_service') not in filters['streaming_services']:
|
| 106 |
+
matches_all_filters = False
|
| 107 |
+
continue
|
| 108 |
|
| 109 |
# Type filter - only apply if not "All"
|
| 110 |
if filters['content_type']:
|
|
|
|
| 306 |
def main():
|
| 307 |
# Page config
|
| 308 |
st.set_page_config(
|
| 309 |
+
page_title="Streaming Content Explorer",
|
| 310 |
page_icon="π¬",
|
| 311 |
layout="wide"
|
| 312 |
)
|
| 313 |
|
| 314 |
# Header
|
| 315 |
+
st.title("π¬ Streaming Content Explorer")
|
| 316 |
+
st.write("Explore movies and TV shows across multiple streaming platforms!")
|
| 317 |
|
| 318 |
# Check API credentials
|
| 319 |
api_token, together_key = get_api_credentials()
|
|
|
|
| 338 |
st.stop()
|
| 339 |
|
| 340 |
# Load all content first
|
| 341 |
+
with st.spinner("Loading streaming content..."):
|
| 342 |
+
all_content = get_streaming_content()
|
| 343 |
|
| 344 |
if not all_content:
|
| 345 |
+
st.error("Could not load streaming content. Please check your NocoDB connection.")
|
| 346 |
st.stop()
|
| 347 |
|
| 348 |
# Extract unique values for filters
|
|
|
|
| 353 |
for genre in c.get('listed_in', '').split(',')
|
| 354 |
if genre.strip()
|
| 355 |
)))
|
| 356 |
+
all_streaming_services = sorted(list(set([c.get('streaming_service') for c in all_content if c.get('streaming_service')])))
|
| 357 |
|
| 358 |
# Extract unique directors and cast members
|
| 359 |
all_directors = extract_unique_names(all_content, 'director')
|
|
|
|
| 363 |
st.sidebar.header("π Filter Content")
|
| 364 |
|
| 365 |
with st.sidebar.form("filter_form"):
|
| 366 |
+
st.subheader("Streaming Services")
|
| 367 |
+
|
| 368 |
+
# Streaming service selection (required)
|
| 369 |
+
selected_services = st.multiselect(
|
| 370 |
+
"Select Your Streaming Services",
|
| 371 |
+
options=all_streaming_services,
|
| 372 |
+
default=all_streaming_services[:1], # Default to first service
|
| 373 |
+
help="Select the streaming services you have access to",
|
| 374 |
+
key="streaming_services"
|
| 375 |
+
)
|
| 376 |
+
|
| 377 |
+
if not selected_services:
|
| 378 |
+
st.warning("Please select at least one streaming service")
|
| 379 |
+
|
| 380 |
+
st.subheader("Content Filters")
|
| 381 |
|
| 382 |
content_type = st.selectbox(
|
| 383 |
"Content Type",
|
|
|
|
| 453 |
|
| 454 |
# Create filter dictionary
|
| 455 |
filters = {
|
| 456 |
+
'streaming_services': selected_services,
|
| 457 |
'content_type': content_type if content_type != "All" else None,
|
| 458 |
'ratings': selected_ratings,
|
| 459 |
'genres': selected_genres,
|
|
|
|
| 505 |
detail_col1, detail_col2 = st.columns(2)
|
| 506 |
|
| 507 |
with detail_col1:
|
| 508 |
+
st.write(f"**πΊ Available on:** {content.get('streaming_service', 'N/A')}")
|
| 509 |
st.write(f"**π Type:** {content.get('type', 'N/A')}")
|
| 510 |
st.write(f"**β Rating:** {content.get('rating', 'N/A')}")
|
| 511 |
st.write(f"**β±οΈ Duration:** {content.get('duration', 'N/A')}")
|
|
|
|
| 544 |
with col2:
|
| 545 |
# AI Chat Section
|
| 546 |
st.subheader("π€ Ask AI Assistant")
|
| 547 |
+
st.write("Ask questions about the streaming content!")
|
| 548 |
|
| 549 |
# Model selection for Together AI
|
| 550 |
model_choice = st.selectbox(
|
|
|
|
| 620 |
total_items = len(all_content)
|
| 621 |
filtered_items = len(st.session_state.filtered_content)
|
| 622 |
|
| 623 |
+
# Create columns for stats
|
| 624 |
+
stat_cols = st.columns(len(selected_services) + 3)
|
| 625 |
|
| 626 |
+
# Basic stats
|
| 627 |
+
with stat_cols[0]:
|
| 628 |
+
st.metric("Total Available", total_items)
|
| 629 |
|
| 630 |
+
with stat_cols[1]:
|
| 631 |
st.metric("Filtered Results", filtered_items)
|
| 632 |
|
| 633 |
+
with stat_cols[2]:
|
| 634 |
movies = sum(1 for c in st.session_state.filtered_content if c.get('type') == 'Movie')
|
|
|
|
|
|
|
|
|
|
| 635 |
shows = sum(1 for c in st.session_state.filtered_content if c.get('type') == 'TV Show')
|
| 636 |
+
st.metric("Movies / Shows", f"{movies} / {shows}")
|
| 637 |
+
|
| 638 |
+
# Streaming service breakdown
|
| 639 |
+
for i, service in enumerate(selected_services, 3):
|
| 640 |
+
if i < len(stat_cols):
|
| 641 |
+
service_count = sum(1 for c in st.session_state.filtered_content if c.get('streaming_service') == service)
|
| 642 |
+
with stat_cols[i]:
|
| 643 |
+
st.metric(service, service_count)
|
| 644 |
|
| 645 |
if __name__ == "__main__":
|
| 646 |
main()
|