|
|
import faiss |
|
|
import pickle |
|
|
import os |
|
|
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline |
|
|
from langchain.llms import HuggingFacePipeline |
|
|
from langchain.vectorstores import FAISS as LangChainFAISS |
|
|
from langchain.docstore import InMemoryDocstore |
|
|
from langchain.schema import Document |
|
|
from langchain.chains import RetrievalQA |
|
|
from langchain.embeddings import HuggingFaceEmbeddings |
|
|
import gradio as gr |
|
|
|
|
|
|
|
|
vector_path = "vector_store_faiss_chroma/faiss_index.index" |
|
|
metadata_path = "vector_store_faiss_chroma/metadata.pkl" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
model_path = "tiiuae/falcon-rw-1b" |
|
|
|
|
|
|
|
|
faiss_index = faiss.read_index(f"{vector_path}") |
|
|
|
|
|
|
|
|
with open(f"{metadata_path}", "rb") as f: |
|
|
metadata = pickle.load(f) |
|
|
|
|
|
|
|
|
docs = [Document(page_content=doc["page_content"]) for doc in metadata] |
|
|
|
|
|
|
|
|
docstore = InMemoryDocstore({str(i): docs[i] for i in range(len(docs))}) |
|
|
id_map = {i: str(i) for i in range(len(docs))} |
|
|
|
|
|
|
|
|
tokenizer = AutoTokenizer.from_pretrained(model_path) |
|
|
model = AutoModelForCausalLM.from_pretrained(model_path) |
|
|
|
|
|
|
|
|
text_generator_pipeline = pipeline( |
|
|
model=model, |
|
|
tokenizer=tokenizer, |
|
|
task="text-generation", |
|
|
return_full_text=False, |
|
|
max_new_tokens=128, |
|
|
temperature=0.2 |
|
|
) |
|
|
|
|
|
llm = HuggingFacePipeline(pipeline=text_generator_pipeline) |
|
|
|
|
|
|
|
|
embed_fn = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2") |
|
|
|
|
|
|
|
|
vectorstore_faiss = LangChainFAISS( |
|
|
index=faiss_index, |
|
|
docstore=docstore, |
|
|
index_to_docstore_id=id_map, |
|
|
embedding_function=embed_fn |
|
|
) |
|
|
|
|
|
|
|
|
retriever = vectorstore_faiss.as_retriever(search_kwargs={"k": 2}) |
|
|
|
|
|
|
|
|
qa_chain = RetrievalQA.from_chain_type( |
|
|
llm=llm, |
|
|
chain_type="stuff", |
|
|
retriever=retriever, |
|
|
return_source_documents=True |
|
|
) |
|
|
|
|
|
|
|
|
def ask_rag(query): |
|
|
result = qa_chain({"query": query}) |
|
|
answer = result["result"] |
|
|
|
|
|
|
|
|
sources = result.get("source_documents", []) |
|
|
source_texts = "\n\n".join([f"πΉ Source {i+1}:\n{doc.page_content[:300]}..." for i, doc in enumerate(sources[:2])]) |
|
|
|
|
|
return f"π Answer:\n{answer}\n\nπ Sources:\n{source_texts}" |
|
|
|
|
|
|
|
|
gr.Interface( |
|
|
fn=ask_rag, |
|
|
inputs=gr.Textbox(lines=2, placeholder="Ask me about UCT admissions, housing, fees..."), |
|
|
outputs="text", |
|
|
title="π University of Cape Town Course Advisor Chatbot", |
|
|
description=""" |
|
|
Ask any academic-related question about the University of Cape Town β admissions, programs, housing, fees, or wellness services. |
|
|
|
|
|
This chatbot uses a Retrieval-Augmented Generation (RAG) pipeline powered by: |
|
|
- FAISS for semantic search |
|
|
- Falcon-E 1B Instruct for natural language answers |
|
|
- LangChain for orchestration |
|
|
|
|
|
π οΈ Developed by **Serge Tsimba**, Data Science Consultant at **Amdari**/Canada. |
|
|
|
|
|
π Available 24/7 β Start by asking: "How can international students apply to UCT?" |
|
|
|
|
|
""", |
|
|
allow_flagging="never" |
|
|
).launch() |