Spaces:
Sleeping
Sleeping
import pickle | |
import streamlit as st | |
st.set_page_config(layout="wide") | |
from streamlit_modal import Modal | |
import numpy as np | |
import bookdb | |
import ai_services | |
st.header("My Book Buddy π") | |
if "clicked_book" not in st.session_state: | |
st.session_state["clicked_book"] = {} | |
if "closestReadBook" not in st.session_state: | |
st.session_state["closestReadBook"] = None | |
if "suggestedBookText" not in st.session_state: | |
st.session_state["suggestedBookText"] = "" | |
if "upvoted_book_ids" not in st.session_state: | |
st.session_state["upvoted_book_ids"] = [] | |
if "downvoted_book_ids" not in st.session_state: | |
st.session_state["downvoted_book_ids"] = [] | |
if "recommendedBooksData" not in st.session_state: | |
st.session_state["recommendedBooksData"] = None | |
if "topCorrelatedReadersData" not in st.session_state: | |
st.session_state["topCorrelatedReadersData"] = None | |
if "numSimilarUsers" not in st.session_state: | |
st.session_state["numSimilarUsers"] = 0 | |
def update_display(displayData): | |
st.session_state["upvoted_book_ids"] = displayData["upvotedBookIds"] | |
st.session_state["downvoted_book_ids"] = displayData["downvotedBookIds"] | |
st.session_state["numSimilarUsers"] = displayData["numSimilarUsers"] | |
st.session_state["recommendedBooksData"] = displayData["recommendedBooksData"] | |
st.session_state["topCorrelatedReadersData"] = displayData["topCorrelatedReadersData"] | |
st.session_state["bookByRatingData"] = displayData["bookByRatingData"] | |
def on_reset_votes(): | |
st.session_state["upvoted_book_ids"] = [] | |
st.session_state["downvoted_book_ids"] = [] | |
st.session_state["numSimilarUsers"] = 0 | |
st.session_state["recommendedBooksData"] = None | |
st.session_state["topCorrelatedReadersData"] = None | |
st.session_state["bookByRatingData"] = None | |
def on_test_submit_votes(): | |
upvotedBookIds = [104, 103, 102, 110, 113, 124, 129, 135, 141, 142, 155, 161, 165, 176, 181, 974, 4443, 1496, 1003, 2600] # TODO REMOVE | |
downvotedBookIds = [126, 179, 183, 184, 187, 9076, 960, 5895, 777, 6902, 2084, 584] # TODO REMOVE | |
update_display(bookdb.update_user_ratings(upvotedBookIds, downvotedBookIds)) | |
def on_submit_votes(): | |
upvoteBookTitles = st.session_state["multiselect_upvote"] | |
downvoteBookTitles = st.session_state["multiselect_downvote"] | |
if len(upvoteBookTitles) == 0 and len(downvoteBookTitles) == 0: | |
st.warning("Please select at least one book to upvote or downvote") | |
return | |
booksToUpvote = bookdb.get_book_ids_by_title(upvoteBookTitles) | |
booksToDownvote = bookdb.get_book_ids_by_title(downvoteBookTitles) | |
# get the currently voted book ids | |
upvotedBookIds = st.session_state["upvoted_book_ids"] | |
downvotedBookIds = st.session_state["downvoted_book_ids"] | |
if (len(upvotedBookIds) + len(booksToUpvote)) == 0 or (len(downvotedBookIds) + len(booksToDownvote)) == 0: | |
st.warning("You must select at least one book to upvote and one book to downvote") | |
return | |
# append booksToUpvote to upvotedBookIds | |
upvotedBookIds.extend(booksToUpvote) | |
# append booksToDownvote to downvotedBookIds | |
downvotedBookIds.extend(booksToDownvote) | |
# remove any upvoted books from downvotedBookIds if they are in there | |
downvotedBookIds = [x for x in downvotedBookIds if x not in upvotedBookIds] | |
# clear the multiselects | |
st.session_state.multiselect_upvote = [] | |
st.session_state.multiselect_downvote = [] | |
update_display(bookdb.update_user_ratings(upvotedBookIds, downvotedBookIds)) | |
clickedBook = st.session_state["clicked_book"] if "clicked_book" in st.session_state else {} | |
modal = Modal( | |
f"π {clickedBook['title'] if 'title' in clickedBook else ''}", | |
key="book-modal" | |
) | |
def on_update_recommendations(): | |
# iterate through the number of recommendations and check the selected radio button | |
recommendations = st.session_state["recommendedBooksData"] | |
bookIdsToUpvote = [] | |
bookIdsToDownvote = [] | |
for counter in range(len(recommendations)): | |
radioKey = f"update_recommendation_{counter}" | |
radioValue = st.session_state[radioKey] | |
if radioValue == "π": | |
bookIdsToUpvote.append(recommendations[counter]["book_id"]) | |
elif radioValue == "π": | |
bookIdsToDownvote.append(recommendations[counter]["book_id"]) | |
# reset the radio button | |
st.session_state[radioKey] = None | |
if len(bookIdsToUpvote) == 0 and len(bookIdsToDownvote) == 0: | |
st.warning("Please select at least one book to upvote or downvote") | |
return | |
# append booksToUpvote to upvotedBookIds | |
upvotedBookIds = st.session_state["upvoted_book_ids"] | |
downvotedBookIds = st.session_state["downvoted_book_ids"] | |
upvotedBookIds.extend(bookIdsToUpvote) | |
downvotedBookIds.extend(bookIdsToDownvote) | |
# remove any upvoted books from downvotedBookIds if they are in there | |
downvotedBookIds = [x for x in downvotedBookIds if x not in upvotedBookIds] | |
update_display(bookdb.update_user_ratings(upvotedBookIds, downvotedBookIds)) | |
if st.session_state["recommendedBooksData"] is not None: | |
recommendations = st.session_state["recommendedBooksData"] | |
st.subheader("Recommendations") | |
recommendationsCol1, recommendationsCol2, recommendationsCol3 = st.columns(3) | |
for counter in range(len(recommendations)): | |
bookData = recommendations[counter] | |
bookMetadata = bookdb.get_book_metadata_by_id(bookData["book_id"]) | |
# print(bookMetadata) | |
if counter % 3 == 0: | |
container = recommendationsCol1.container(border=True) | |
elif counter % 3 == 1: | |
container = recommendationsCol2.container(border=True) | |
else: | |
container = recommendationsCol3.container(border=True) | |
bookAuthor = bookData["authors"] | |
bookTitle = bookData["title"] | |
bookPubYear = bookData["original_publication_year"] | |
containerCol1, containerCol2, containerCol3 = container.columns([5, 10, 2]) | |
containerCol1.html(f"<img width='100%' src='{bookMetadata['thumbnail']}'>") | |
textContainer = containerCol2.container() | |
titleClicked = textContainer.button(f"{bookTitle}", use_container_width=True) | |
if titleClicked: | |
bookByRatingData = st.session_state["bookByRatingData"] | |
upvotedBookIds = st.session_state["upvoted_book_ids"] | |
targetBookId = bookData["book_id"] | |
closestReadBookData = bookdb.find_closest_read_title(bookByRatingData, upvotedBookIds, targetBookId) | |
targetBookData = bookdb.get_book_data_by_id(targetBookId) | |
st.session_state["closestReadBook"] = closestReadBookData | |
st.session_state["clicked_book"] = bookData | |
st.session_state["suggestedBookText"] = ai_services.get_suggestion_text(closestReadBookData, targetBookData) | |
modal.open() | |
textContainer.markdown(f"*{bookAuthor}*") | |
textContainer.markdown(f"Published: {int(bookPubYear)}") | |
# containerCol2.markdown(textHTMLcontent, unsafe_allow_html=True) | |
# containerCol2.markdown(f"[{bookTitle}](https://streamlit.io)\n\n*{bookAuthor}*\n\nPublished: {int(bookPubYear)}") | |
# radioContainer = containerCol3.container() | |
containerCol3.radio(label="Upvote/Downvote", label_visibility="hidden", options=["π", "π"], key=f"update_recommendation_{counter}", index=None) | |
# radioContainer.button('Why This Book?', type="secondary", key=f"submit_{counter}") | |
st.button('Update Recommendations', type="primary", on_click=on_update_recommendations) | |
st.subheader("Your Ratings") | |
displayCol1, displayCol2 = st.columns(2) | |
if len(st.session_state["upvoted_book_ids"]) > 0: | |
upvotedBookIds = st.session_state["upvoted_book_ids"] | |
displayCol1.markdown(f"Upvoted: {len(upvotedBookIds)} book(s)") | |
for bookId in upvotedBookIds: | |
displayCol1.markdown(f' - {bookId}-{bookdb.get_book_title(bookId)}') | |
if len(st.session_state["downvoted_book_ids"]) > 0: | |
downvotedBookIds = st.session_state["downvoted_book_ids"] | |
displayCol2.markdown(f'Downvoted: {len(downvotedBookIds)} book(s)') | |
for bookId in downvotedBookIds: | |
displayCol2.markdown(f' - {bookId}-{bookdb.get_book_title(bookId)}') | |
st.button('Reset All Ratings', type="secondary", on_click=on_reset_votes) | |
# st.write(f"Similar User Min Percent Shared Books = {round(bookdb.SIMILAR_USER_MIN_PERCENT_SHARED_BOOKS * 100)}%") | |
# st.write(f"Similar User Min Correlation = {bookdb.SIMILAR_USER_MIN_CORRELATION}") | |
# if "numSimilarUsers" in st.session_state: | |
# st.write(f"{st.session_state['numSimilarUsers']} similar users") | |
with st.form(key='upvote_form'): | |
col1, col2 = st.columns(2) | |
allBookTitles = bookdb.get_all_book_titles() | |
myRatedBookTitles = bookdb.get_book_titles(st.session_state["upvoted_book_ids"] + st.session_state["downvoted_book_ids"]) | |
# remove myRatedBookTitles from allBookTitles | |
remainingBookTitles = [x for x in allBookTitles if x not in myRatedBookTitles] | |
col1.multiselect( | |
'Upvote Books π', | |
remainingBookTitles, | |
key='multiselect_upvote' | |
) | |
col2.multiselect( | |
'Downvote Books π', | |
remainingBookTitles, | |
key='multiselect_downvote' | |
) | |
st.form_submit_button(label='Submit', type="primary", on_click=on_submit_votes) | |
st.form_submit_button(label='Test', type="secondary", on_click=on_test_submit_votes) | |
if st.session_state["topCorrelatedReadersData"] is not None: | |
df = st.session_state["topCorrelatedReadersData"] | |
st.subheader("Top Correlated Readers") | |
st.dataframe(df, use_container_width=True) | |
if modal.is_open(): | |
with modal.container(): | |
clickedBook = st.session_state["clicked_book"] | |
clickedBookMetadata = bookdb.get_book_metadata_by_id(clickedBook["book_id"]) | |
clickedBookDescription = clickedBookMetadata["description"] | |
st.html(f"{clickedBookDescription}") | |
aiSuggestContainer = st.container(border=True) | |
closestReadBook = st.session_state["closestReadBook"] | |
suggestedBookText = st.session_state["suggestedBookText"] | |
aiSuggestContainer.html(f"<p style=\"color:#DA70D6;\">π« Because you liked <i><b>{closestReadBook['title']}</b></i> by <b>{closestReadBook['authors']}</b>...</p>") | |
aiSuggestContainer.html(f"<p style=\"color:#DA70D6;\">{suggestedBookText}</p>") | |
buttonCol1, buttonCol2, buttonCol3, buttonCol4 = st.columns(4) | |
clickedBookTitle = clickedBook["title"] | |
clickedBookAuthor = clickedBook["authors"] | |
clickedBookISBN = clickedBook["isbn"] | |
outboundLinkSuffix = f"{clickedBookTitle} {clickedBookAuthor}" | |
buttonCol1.link_button('π Bookshop', f'https://bookshop.org/search?keywords={outboundLinkSuffix}') | |
buttonCol2.link_button('π Biblio', f'https://www.biblio.com/search.php?stage=1&title={outboundLinkSuffix}') | |
buttonCol3.link_button('π§ Libro', f'https://libro.fm/search?utf8=%E2%9C%93&q={outboundLinkSuffix}') | |
buttonCol4.link_button('π¬ Hardcover', f'https://hardcover.app/search?q={outboundLinkSuffix}') | |
st.write("Version 0.1.0") |