Spaces:
Sleeping
Sleeping
Download app.py from MuhammadAhmad332/MSDSF25A009-ver1: direct link, hf CLI and curl.
- Browser
- Download file 4.76 kB
-
https://huggingface.co/spaces/MuhammadAhmad332/MSDSF25A009-ver1/resolve/main/app.py
- Command line
-
hf download hf://spaces/MuhammadAhmad332/MSDSF25A009-ver1/app.py
-
curl -L -o app.py https://huggingface.co/spaces/MuhammadAhmad332/MSDSF25A009-ver1/resolve/main/app.py
4.76 kB
| import os | |
| import requests | |
| from bs4 import BeautifulSoup | |
| from groq import Groq | |
| import gradio as gr | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| GROQ_API_KEY = os.getenv("GROQ_API_KEY") | |
| BRIGHT_API_KEY = os.getenv("BRIGHT_API_KEY") | |
| BRIGHT_ZONE = os.getenv("BRIGHT_ZONE") | |
| client = Groq(api_key=GROQ_API_KEY) | |
| # ------------------------------- | |
| # BRIGHT DATA WEB UNLOCKER | |
| # ------------------------------- | |
| def brightdata_request(target_url): | |
| try: | |
| response = requests.post( | |
| "https://api.brightdata.com/request", | |
| headers={ | |
| "Content-Type": "application/json", | |
| "Authorization": f"Bearer {BRIGHT_API_KEY}" | |
| }, | |
| json={ | |
| "zone": BRIGHT_ZONE, | |
| "url": target_url, | |
| "format": "raw" | |
| }, | |
| timeout=60 | |
| ) | |
| response.raise_for_status() | |
| return response.text | |
| except Exception as e: | |
| return f"ERROR: {str(e)}" | |
| # ------------------------------- | |
| # SCRAPER | |
| # ------------------------------- | |
| def scrape_goodreads(url): | |
| html = brightdata_request(url) | |
| if html.startswith("ERROR"): | |
| return [], html | |
| soup = BeautifulSoup(html, "html.parser") | |
| books = [] | |
| rows = soup.find_all("tr") | |
| for row in rows: | |
| title_tag = row.find("a", class_="bookTitle") | |
| author_tag = row.find("a", class_="authorName") | |
| rating_tag = row.find("span", class_="minirating") | |
| if title_tag and author_tag and rating_tag: | |
| books.append({ | |
| "title": title_tag.get_text(strip=True), | |
| "author": author_tag.get_text(strip=True), | |
| "rating": rating_tag.get_text(strip=True) | |
| }) | |
| if not books: | |
| return [], "No books found. Make sure the URL is a Goodreads list page." | |
| return books[:10], None | |
| # ------------------------------- | |
| # AI Q&A | |
| # ------------------------------- | |
| def qa_bot(url, question): | |
| books, error = scrape_goodreads(url) | |
| if error: | |
| return f"β {error}" | |
| context = "\n".join( | |
| [f"{i+1}. {b['title']} by {b['author']} - {b['rating']}" | |
| for i, b in enumerate(books)] | |
| ) | |
| system_prompt = f""" | |
| You are a helpful assistant. | |
| Here is book data scraped from Goodreads: | |
| {context} | |
| Answer questions ONLY using this data. | |
| If the answer is not present, say "The data does not contain that information." | |
| """ | |
| try: | |
| response = client.chat.completions.create( | |
| model="llama-3.1-8b-instant", | |
| messages=[ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": question} | |
| ] | |
| ) | |
| return response.choices[0].message.content | |
| except Exception as e: | |
| return f"β AI Error: {str(e)}" | |
| # ------------------------------- | |
| # UI LOGIC FUNCTIONS | |
| # ------------------------------- | |
| def scrape_and_display(url): | |
| books, error = scrape_goodreads(url) | |
| if error: | |
| return [], error | |
| table_data = [[b["title"], b["author"], b["rating"]] for b in books] | |
| return table_data, "β Successfully scraped top 10 books." | |
| # ------------------------------- | |
| # GRADIO UI | |
| # ------------------------------- | |
| with gr.Blocks(theme=gr.themes.Soft(), title="Goodreads AI Explorer") as demo: | |
| gr.Markdown(""" | |
| # π Goodreads AI Explorer | |
| Scrape book data from a Goodreads list and ask AI questions about it. | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| # β Auto-filled URL textbox | |
| url_input = gr.Textbox( | |
| label="π Goodreads URL", | |
| value="https://www.goodreads.com/list/show/1.Best_Books_Ever", | |
| placeholder="Paste a Goodreads list URL here..." | |
| ) | |
| scrape_btn = gr.Button("π₯ search Books", variant="primary") | |
| status_output = gr.Markdown() | |
| books_table = gr.Dataframe( | |
| headers=["Title", "Author", "Rating"], | |
| datatype=["str", "str", "str"], | |
| interactive=False, | |
| wrap=True | |
| ) | |
| with gr.Column(scale=3): | |
| question_input = gr.Textbox( | |
| label="π¬ Ask a Question", | |
| placeholder="Which book has the highest rating?" | |
| ) | |
| ask_btn = gr.Button("π€ Ask AI", variant="secondary") | |
| answer_output = gr.Markdown() | |
| # Button Actions | |
| scrape_btn.click( | |
| fn=scrape_and_display, | |
| inputs=url_input, | |
| outputs=[books_table, status_output] | |
| ) | |
| ask_btn.click( | |
| fn=qa_bot, | |
| inputs=[url_input, question_input], | |
| outputs=answer_output | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |