Update app.py
Browse files
app.py
CHANGED
|
@@ -1,141 +1,74 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
import requests
|
| 3 |
-
from bs4 import BeautifulSoup
|
| 4 |
-
from typing import List, Dict
|
| 5 |
-
import time
|
| 6 |
|
| 7 |
-
#
|
| 8 |
-
|
| 9 |
-
'Art', 'Biography', 'Business', 'Children', 'Classics', 'Comics', 'Cookbooks', 'Design', 'Drama',
|
| 10 |
-
'Economics', 'Education', 'Fiction', 'Health', 'History', 'Horror', 'Humor', 'Literature', 'Music',
|
| 11 |
-
'Mystery', 'Non-fiction', 'Philosophy', 'Poetry', 'Politics', 'Psychology', 'Religion', 'Romance',
|
| 12 |
-
'Science', 'Science Fiction', 'Self Help', 'Sports', 'Technology', 'Travel', 'True Crime', 'Young Adult',
|
| 13 |
-
'Architecture', 'Adventure', 'Anthropology', 'Art History', 'Astronomy', 'Biology', 'Business & Finance',
|
| 14 |
-
'Chemistry', 'Cultural Studies', 'Current Affairs', 'Education & Teaching', 'Engineering', 'Ethics',
|
| 15 |
-
'Family & Relationships', 'Geography', 'Graphic Novels', 'Health & Fitness', 'History & Archaeology',
|
| 16 |
-
'Home & Garden', 'Law', 'Linguistics', 'Management', 'Mathematics', 'Music Theory', 'Natural Sciences',
|
| 17 |
-
'Philosophy of Science', 'Physics', 'Political Science', 'Sociology', 'Technology & Engineering', 'Theology',
|
| 18 |
-
'Environmental Science', 'Film & Television', 'Food & Drink', 'Games', 'Gardening', 'Genealogy', 'Health Policy',
|
| 19 |
-
'History of Science', 'Humanities', 'Journalism', 'Languages', 'Linguistics', 'Mathematical Logic', 'Mental Health',
|
| 20 |
-
'Museum Studies', 'Mythology', 'Nursing', 'Nutrition', 'Pharmacology', 'Physical Education', 'Physics & Astronomy',
|
| 21 |
-
'Public Health', 'Public Policy', 'Rehabilitation', 'Research Methods', 'Robotics', 'Social Work', 'Statistics',
|
| 22 |
-
'Technology & Innovation', 'The Arts', 'The Environment', 'Urban Studies', 'Veterinary Medicine', 'Women\'s Studies',
|
| 23 |
-
'Zoology', 'Accounting', 'Advertising', 'Architecture & Design', 'Artificial Intelligence', 'Automotive',
|
| 24 |
-
'Biotechnology', 'Business Strategy', 'Climate Change', 'Data Science', 'Digital Marketing', 'Environmental Studies',
|
| 25 |
-
'Entrepreneurship', 'Finance', 'Global Studies', 'Graphic Design', 'Human Resource Management', 'Humanities',
|
| 26 |
-
'Industrial Design', 'International Relations', 'Journalism & Media', 'Law & Legal Studies', 'Literary Theory',
|
| 27 |
-
'Marketing', 'Media Studies', 'Mental Health & Counseling', 'Natural Resources', 'Philosophy & Ethics', 'Public Relations',
|
| 28 |
-
'Real Estate', 'Renewable Energy', 'Software Engineering', 'Supply Chain Management', 'Sustainability', 'Technology', 'Veganism'
|
| 29 |
-
]
|
| 30 |
-
|
| 31 |
-
# OpenLibrary Search API base URL
|
| 32 |
-
OPENLIBRARY_SEARCH_API_URL = "https://openlibrary.org/search.json"
|
| 33 |
|
| 34 |
-
#
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
-
# Function to fetch
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
if response.status_code == 200:
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
# Get Title
|
| 61 |
-
title = book_data.get("title", "N/A")
|
| 62 |
-
|
| 63 |
-
# Get First Published Year
|
| 64 |
-
first_published = book_data.get("first_publish_year", "N/A")
|
| 65 |
|
| 66 |
-
|
| 67 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
|
| 69 |
-
|
| 70 |
-
description = book_data.get("description", "N/A")
|
| 71 |
-
if isinstance(description, dict):
|
| 72 |
-
description = description.get("value", "N/A")
|
| 73 |
-
|
| 74 |
-
# Get Book Cover (using cover API)
|
| 75 |
-
cover_id = book_data.get("covers", [None])[0]
|
| 76 |
-
book_cover = f"https://covers.openlibrary.org/b/id/{cover_id}-M.jpg" if cover_id else "N/A"
|
| 77 |
-
|
| 78 |
-
return {
|
| 79 |
-
'Title': title,
|
| 80 |
-
'First Published Year': first_published,
|
| 81 |
-
'Authors': ", ".join(authors) if authors else "N/A",
|
| 82 |
-
'Description': description,
|
| 83 |
-
'Book Cover': book_cover
|
| 84 |
-
}
|
| 85 |
else:
|
| 86 |
-
st.error(
|
| 87 |
-
|
| 88 |
|
| 89 |
-
#
|
| 90 |
-
|
| 91 |
-
def scrape_book_description(book_key: str) -> str:
|
| 92 |
-
response = requests.get(f"https://openlibrary.org{book_key}")
|
| 93 |
-
if response.status_code == 200:
|
| 94 |
-
soup = BeautifulSoup(response.text, 'html.parser')
|
| 95 |
-
description_div = soup.find("div", class_="read-more__content")
|
| 96 |
-
if description_div:
|
| 97 |
-
paragraphs = description_div.find_all('p')
|
| 98 |
-
return " ".join(paragraph.get_text(strip=True) for paragraph in paragraphs)
|
| 99 |
-
return "N/A"
|
| 100 |
|
| 101 |
-
#
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
)
|
| 116 |
-
|
| 117 |
-
if st.sidebar.button("Fetch Books"):
|
| 118 |
-
if not selected_subjects:
|
| 119 |
-
st.error("Please select at least one subject.")
|
| 120 |
else:
|
| 121 |
-
|
| 122 |
-
start_time = time.time()
|
| 123 |
-
books = fetch_books_by_subject_and_timeframe(selected_subjects, start_year, end_year)
|
| 124 |
-
if books:
|
| 125 |
-
st.success(f"Found {len(books)} books in {time.time() - start_time:.2f} seconds!")
|
| 126 |
-
for book in books:
|
| 127 |
-
book_key = book.get("key", "")
|
| 128 |
-
if book_key:
|
| 129 |
-
book_details = fetch_book_details(book_key)
|
| 130 |
-
if book_details:
|
| 131 |
-
st.subheader(book_details["Title"])
|
| 132 |
-
st.write(f"**First Published Year:** {book_details['First Published Year']}")
|
| 133 |
-
st.write(f"**Authors:** {book_details['Authors']}")
|
| 134 |
-
st.write(f"**Description:** {book_details['Description']}")
|
| 135 |
-
if book_details["Book Cover"] != "N/A":
|
| 136 |
-
st.image(book_details["Book Cover"])
|
| 137 |
-
else:
|
| 138 |
-
st.warning("No books found.")
|
| 139 |
-
|
| 140 |
-
if __name__ == "__main__":
|
| 141 |
-
main()
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
import requests
|
|
|
|
|
|
|
|
|
|
| 3 |
|
| 4 |
+
# Open Library API base URL
|
| 5 |
+
OPEN_LIBRARY_API = "https://openlibrary.org/search.json"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
+
# List of subjects
|
| 8 |
+
subjects_list = [
|
| 9 |
+
"Classic Literature", "Modern Literature", "Postmodern Literature",
|
| 10 |
+
"Romanticism", "Realism", "Naturalism", "Existentialism", "Absurdism",
|
| 11 |
+
"Gothic Fiction", "Science Fiction", "Fantasy Literature", "Historical Fiction",
|
| 12 |
+
"Mystery and Detective Fiction", "Horror Literature", "Adventure Novels",
|
| 13 |
+
"Bildungsroman", "Satire", "Tragedy", "Comedy", "Dystopian Literature",
|
| 14 |
+
"Utopian Literature", "Magical Realism", "Stream of Consciousness",
|
| 15 |
+
"Metafiction", "Allegory", "Mythology", "Folklore", "Fairy Tales",
|
| 16 |
+
"Poetry", "Epic Poetry", "Lyric Poetry", "Sonnet", "Haiku", "Free Verse",
|
| 17 |
+
"Drama", "Tragicomedy", "Theater of the Absurd", "Shakespearean Plays",
|
| 18 |
+
"Greek Tragedy", "Modern Drama", "Surrealism in Literature", "Symbolism",
|
| 19 |
+
"Transcendentalism", "Stoicism", "Epicureanism", "Nihilism",
|
| 20 |
+
"Feminist Literature", "Postcolonial Literature", "Marxist Literary Criticism",
|
| 21 |
+
"Psychoanalytic Criticism", "Formalism", "New Criticism", "Cultural Studies",
|
| 22 |
+
"Comparative Literature", "World Literature", "African Literature",
|
| 23 |
+
"Asian Literature", "Latin American Literature", "European Literature",
|
| 24 |
+
"American Literature", "British Literature", "Russian Literature",
|
| 25 |
+
"French Literature", "German Literature", "Italian Literature",
|
| 26 |
+
"Spanish Literature", "Ancient Literature", "Medieval Literature",
|
| 27 |
+
"Renaissance Literature", "Enlightenment Literature", "Victorian Literature",
|
| 28 |
+
"Modernist Literature", "Postmodernist Literature", "Contemporary Literature"
|
| 29 |
+
]
|
| 30 |
|
| 31 |
+
# Function to fetch books from Open Library API
|
| 32 |
+
def fetch_books(subjects, year_range):
|
| 33 |
+
query = " AND ".join([f"subject:{sub.replace(' ', '+')}" for sub in subjects])
|
| 34 |
+
year_query = f"first_publish_year:[{year_range[0]} TO {year_range[1]}]"
|
| 35 |
+
|
| 36 |
+
api_url = f"{OPEN_LIBRARY_API}?{query} AND {year_query}&limit=20"
|
| 37 |
+
response = requests.get(api_url)
|
| 38 |
+
|
| 39 |
if response.status_code == 200:
|
| 40 |
+
data = response.json()
|
| 41 |
+
books = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
+
for doc in data.get("docs", []):
|
| 44 |
+
book = {
|
| 45 |
+
"Title": doc.get("title", "N/A"),
|
| 46 |
+
"Author": ", ".join(doc.get("author_name", ["N/A"])),
|
| 47 |
+
"First Published Year": doc.get("first_publish_year", "N/A"),
|
| 48 |
+
}
|
| 49 |
+
books.append(book)
|
| 50 |
|
| 51 |
+
return books
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
else:
|
| 53 |
+
st.error("Failed to fetch data from Open Library.")
|
| 54 |
+
return []
|
| 55 |
|
| 56 |
+
# Streamlit App UI
|
| 57 |
+
st.title("📚 Book Finder")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
+
# Multi-select for subjects
|
| 60 |
+
selected_subjects = st.multiselect("Select Literary Subjects", subjects_list, default=["Classic Literature"])
|
| 61 |
+
|
| 62 |
+
# Year range slider
|
| 63 |
+
year_range = st.slider("Select Year Range", min_value=1800, max_value=2025, value=(1900, 2025))
|
| 64 |
+
|
| 65 |
+
# Button to search books
|
| 66 |
+
if st.button("🔍 Search Books"):
|
| 67 |
+
with st.spinner("Fetching books..."):
|
| 68 |
+
books = fetch_books(selected_subjects, year_range)
|
| 69 |
+
|
| 70 |
+
if books:
|
| 71 |
+
st.success(f"📖 Found {len(books)} books!")
|
| 72 |
+
st.table(books)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
else:
|
| 74 |
+
st.warning("No books found for the selected criteria.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|