import streamlit as st
import os
import time
from langchain_community.document_loaders import WebBaseLoader
try:
from langchain_text_splitters import RecursiveCharacterTextSplitter
except ImportError:
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
from langchain_core.prompts import ChatPromptTemplate
from langchain_groq import ChatGroq
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains import create_retrieval_chain
from dotenv import load_dotenv
load_dotenv()
## Load the Groq API key
groq_api_key = os.environ['GROQ_API_KEY'] # reads the system environment variable into a Python variable.
# If you only need to pass the API key to a function
## st.session_state is like a box where you can store variables that will remember their values while you use the app.
## Normally, when you refresh a Streamlit app, all variables reset.
if "vectors" not in st.session_state:
urls = [
"https://huggingface.co/docs/transformers/index",
"https://huggingface.co/docs/datasets/index",
"https://huggingface.co/docs/tokenizers/index",
"https://huggingface.co/docs/hub/index",
"https://huggingface.co/docs/accelerate/index",
"https://huggingface.co/docs/optimum/index"
]
st.session_state.docs = []
for url in urls:
loader = WebBaseLoader(url)
st.session_state.docs.extend(loader.load())
st.session_state.text_splitter = RecursiveCharacterTextSplitter(chunk_size = 1000, chunk_overlap = 200)
st.session_state.final_documents = st.session_state.text_splitter.split_documents(st.session_state.docs)
st.session_state.embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
st.session_state.vectors = FAISS.from_documents(st.session_state.final_documents, st.session_state.embeddings)
llm = ChatGroq(groq_api_key = groq_api_key, # passing the API key to the function
model_name = "llama-3.1-8b-instant")
prompt = ChatPromptTemplate.from_template(
"""
Answer the question based on the provided context only.
Please provide the most accurate response based on the question
An AI chatbot that answers questions from Hugging Face documentation using RAG & FAISS
', unsafe_allow_html=True) # ----------------- Input Section ----------------- st.markdown("### 🧠 Ask me anything about Hugging Face documentation:") prompt = st.text_input("Type your question here...", placeholder="e.g. What does the pipeline() function in Transformers do?") # ----------------- Chat Response Section ----------------- if prompt: with st.spinner("🔍 Generating answer..."): start = time.process_time() response = retrieval_chain.invoke({"input": prompt}) response_time = round(time.process_time() - start, 2) # Display answer st.markdown("### 🪄 Answer:") st.markdown(f'" "Built with ❤️ using Streamlit, LangChain, Groq API & FAISS" "
", unsafe_allow_html=True ) ## with is just a cleaner, safer way to handle objects that need automatic opening/closing. like automatic closing of files that were opened. ## st.expander("Title") creates a collapsible box in your web app that can be expanded or collapsed by clicking it. ## enumerate() is a Python function that loops over a collection and also gives you the index (count) of each item ## The with keyword tells Streamlit: "Whatever I write in this block should be inside the expander UI." ## The expander hides the document chunks by default (to keep the UI clean).