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") |