| import os |
| import warnings |
| import pickle |
| from together import Together |
| import faiss |
| from sentence_transformers import SentenceTransformer |
| from PyPDF2 import PdfReader |
| import glob |
|
|
| warnings.filterwarnings("ignore") |
|
|
| |
| TOGETHER_API_KEY = "81da53aa3044c7ebead342fb048f016a4e593a86928a783a6fdcc1e3883054e4" |
| client = Together(api_key=TOGETHER_API_KEY) |
|
|
| |
| embedding_model = SentenceTransformer( |
| "sentence-transformers/all-MiniLM-L6-v2", |
| use_auth_token=os.environ.get("HUGGINGFACE_HUB_TOKEN"), |
| ) |
|
|
| |
| documents = [] |
| filenames = [] |
| index = None |
|
|
| def load_index(): |
| """Load the FAISS index and document metadata.""" |
| global index, documents, filenames |
| |
| if not os.path.exists("knowledge_base/faiss_index.bin") or not os.path.exists("knowledge_base/metadata.pkl"): |
| raise ValueError("Index files not found. Please run preprocess.py first!") |
| |
| print("Loading index and metadata...") |
| index = faiss.read_index("knowledge_base/faiss_index.bin") |
| |
| with open("knowledge_base/metadata.pkl", "rb") as f: |
| metadata = pickle.load(f) |
| documents = metadata["documents"] |
| filenames = metadata["filenames"] |
| |
| print("Index and metadata loaded successfully!") |
|
|
| def answer_question(query: str) -> str: |
| """ |
| Answer a question using the RAG system. |
| |
| Args: |
| query (str): The user's question |
| |
| Returns: |
| str: The generated answer |
| """ |
| global index |
| |
| |
| if index is None: |
| load_index() |
| |
| |
| query_embedding = embedding_model.encode([query]) |
| faiss.normalize_L2(query_embedding) |
| |
| |
| scores, indices = index.search(query_embedding, min(3, len(documents))) |
| |
| |
| context_parts = [] |
| relevant_docs = [] |
| |
| for score, idx in zip(scores[0], indices[0]): |
| if idx < len(documents): |
| doc_info = { |
| "content": documents[idx], |
| "filename": filenames[idx], |
| "score": float(score), |
| } |
| relevant_docs.append(doc_info) |
| context_parts.append(f"[{doc_info['filename']}]\n{doc_info['content']}") |
| |
| if not relevant_docs: |
| return "I couldn't find any relevant information to answer your question." |
| |
| |
| context = "\n\n".join(context_parts) |
| |
| |
| llm_prompt = f"""Answer the question based on the provided context documents. |
| |
| Context: |
| {context} |
| |
| Question: {query} |
| |
| Instructions: |
| - Answer based only on the information in the context |
| - If the context doesn't contain enough information, say so |
| - Mention which document(s) you're referencing |
| - Start with According to [document name] |
| - Add brackets to the document name |
| |
| Answer:""" |
| |
| try: |
| |
| response = client.chat.completions.create( |
| model="meta-llama/Llama-3.3-70B-Instruct-Turbo", |
| messages=[{"role": "user", "content": llm_prompt}], |
| max_tokens=500, |
| temperature=0.7, |
| ) |
| answer = response.choices[0].message.content |
| |
| |
| sources_list = [doc["filename"] for doc in relevant_docs] |
| sources_text = sources_list[0] |
| full_answer = f"{answer}\n\n📄 Source Used: {sources_text}" |
| |
| return full_answer |
| |
| except Exception as e: |
| return f"Error generating answer: {str(e)}" |
|
|