MuhammadAhmad332's picture
Update app.py
792bcd9 verified
import os
import json
import requests
import re
from bs4 import BeautifulSoup
from groq import Groq
import gradio as gr
from dotenv import load_dotenv
from youtube_transcript_api import YouTubeTranscriptApi
load_dotenv()
# -------------------------------
# API KEYS & CLIENT
# -------------------------------
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)
CHAT_FILE = "chat_history.json"
PREF_FILE = "preferences.json"
# -------------------------------
# SAFE LOAD / SAVE
# -------------------------------
def load_json(file, default):
if os.path.exists(file):
try:
with open(file, "r") as f:
return json.load(f)
except:
return default
return default
def save_json(file, data):
with open(file, "w") as f:
json.dump(data, f, indent=4)
conversation_history = load_json(CHAT_FILE, [])
user_preferences = load_json(PREF_FILE, {"style": "Default"})
# -------------------------------
# BRIGHT DATA SCRAPER
# -------------------------------
def brightdata_request(target_url):
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"
}
)
return response.text
def scrape_goodreads(url):
html = brightdata_request(url)
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)
})
return books[:10]
def qa_bot(url, question):
books = scrape_goodreads(url)
if not books:
return "No book data found."
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.
Answer ONLY using the following scraped Goodreads data.
{context}
"""
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
# -------------------------------
# YOUTUBE TRANSCRIPT
# -------------------------------
def extract_video_id(url):
pattern = r"(?:v=|youtu\.be/|live/|embed/|/v/|/e/|^)([a-zA-Z0-9_-]{11})"
match = re.search(pattern, url)
return match.group(1) if match else None
def get_youtube_transcript(url):
video_id = extract_video_id(url)
if not video_id:
return "Invalid YouTube URL."
try:
transcript = YouTubeTranscriptApi.get_transcript(video_id)
full_text = " ".join([entry["text"] for entry in transcript])
return full_text
except:
return "No transcript available for this video."
def youtube_qa(video_url, question):
transcript = get_youtube_transcript(video_url)
if transcript.startswith("No") or transcript.startswith("Invalid"):
return transcript
system_prompt = f"""
You are a helpful assistant.
Answer ONLY using this transcript.
Transcript:
{transcript[:6000]}
"""
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
# -------------------------------
# MEMORY CHAT
# -------------------------------
def chat_with_memory(user_message, preference_text):
global conversation_history, user_preferences
if preference_text and preference_text.strip():
user_preferences["style"] = preference_text
save_json(PREF_FILE, user_preferences)
system_prompt = f"""
You are a helpful AI assistant.
User Preferences:
{user_preferences.get("style", "Default")}
Follow the preferred style in all responses.
Maintain conversational memory.
"""
messages = [{"role": "system", "content": system_prompt}]
messages.extend(conversation_history)
messages.append({"role": "user", "content": user_message})
response = client.chat.completions.create(
model="llama-3.1-8b-instant",
messages=messages
)
assistant_reply = response.choices[0].message.content
conversation_history.append({"role": "user", "content": user_message})
conversation_history.append({"role": "assistant", "content": assistant_reply})
save_json(CHAT_FILE, conversation_history)
return assistant_reply
def clear_memory():
global conversation_history
conversation_history = []
save_json(CHAT_FILE, [])
return []
# -------------------------------
# GRADIO BLOCKS UI
# -------------------------------
with gr.Blocks(title="Full AI Assistant") as demo:
gr.Markdown("# πŸš€ Full AI Assistant (Goodreads + YouTube + Memory Chat)")
# TAB 1 β€” Website Scraper Q&A
with gr.Tab("πŸ“š Goodreads Q&A"):
url_input = gr.Textbox(
label="Enter Goodreads URL",
value="https://www.goodreads.com/list/show/1.Best_Books_Ever"
)
question_input = gr.Textbox(label="Ask your question")
answer_output = gr.Textbox(label="Answer")
submit_btn = gr.Button("Submit")
submit_btn.click(qa_bot, inputs=[url_input, question_input], outputs=answer_output)
# TAB 2 β€” YouTube Transcript Q&A
with gr.Tab("πŸŽ₯ YouTube Q&A"):
video_input = gr.Textbox(label="Enter YouTube URL")
yt_question = gr.Textbox(label="Ask your question")
yt_output = gr.Textbox(label="Answer")
yt_submit_btn = gr.Button("Submit")
yt_submit_btn.click(youtube_qa, inputs=[video_input, yt_question], outputs=yt_output)
# TAB 3 β€” Persistent Memory Chat
with gr.Tab("🧠 Memory Chat"):
chatbot = gr.Chatbot(label="Conversation", value=conversation_history)
preference_input = gr.Textbox(
label="User Preferences (Optional)",
placeholder="e.g. Respond formally, Be concise, Use bullets"
)
user_message = gr.Textbox(label="Your Message")
send_btn = gr.Button("Send")
clear_btn = gr.Button("Clear Memory")
def chat_interface(user_message, preference_text, chat_display):
if not user_message.strip():
return "", chat_display
assistant_reply = chat_with_memory(user_message, preference_text)
chat_display.append({"role": "user", "content": user_message})
chat_display.append({"role": "assistant", "content": assistant_reply})
return "", chat_display
send_btn.click(
chat_interface,
inputs=[user_message, preference_input, chatbot],
outputs=[user_message, chatbot]
)
clear_btn.click(
clear_memory,
outputs=chatbot
)
if __name__ == "__main__":
demo.launch()