DeepMostInnovations commited on
Commit
8504055
·
verified ·
1 Parent(s): d5947d7

Upload Hindi embeddings model and all associated files

Browse files
Files changed (2) hide show
  1. hindi-rag-system.py +181 -10
  2. hindi-rag-system.py.amltmp +181 -10
hindi-rag-system.py CHANGED
@@ -16,6 +16,12 @@ from langchain.vectorstores import FAISS as LangchainFAISS
16
  from langchain.docstore.document import Document
17
  from langchain.embeddings.base import Embeddings
18
  from typing import List, Dict, Any, Optional, Callable
 
 
 
 
 
 
19
 
20
  # Tokenizer wrapper class - same as in original code
21
  class SentencePieceTokenizerWrapper:
@@ -702,6 +708,107 @@ def perform_similarity_search(vector_store, query, k=6):
702
  print(f"Searching for: {query}")
703
  return vector_store.similarity_search_with_score(query, k=k)
704
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
705
  # Main RAG functions
706
  def index_text_files(model, tokenizer, data_dir, output_dir, device="cuda", chunk_size=500):
707
  """
@@ -795,7 +902,7 @@ def query_text_corpus(model, tokenizer, vector_store_path, query, k=6, device="c
795
 
796
  processed_results.append((combined_doc, score))
797
 
798
- return processed_results
799
 
800
  def main():
801
  parser = argparse.ArgumentParser(description="Hindi RAG System with LangChain and FAISS")
@@ -821,27 +928,54 @@ def main():
821
  help="Run in interactive mode for querying")
822
  parser.add_argument("--reindex", action="store_true",
823
  help="Force reindexing even if index exists")
 
 
 
 
824
  args = parser.parse_args()
825
 
826
- # Load model and tokenizer
827
- model, tokenizer, config = load_model_and_tokenizer(args.model_dir, args.tokenizer_dir)
828
 
829
- # Move model to device
830
- model = model.to(args.device)
831
 
832
  # Create vector store path
833
  vector_store_path = os.path.join(args.output_dir, "faiss_index")
834
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
835
  if args.index or args.reindex:
836
  # Index text files
837
- index_text_files(model, tokenizer, args.data_dir, args.output_dir, args.device, args.chunk_size)
 
 
838
  print(f"Indexing complete. Vector store saved to {vector_store_path}")
 
 
 
 
839
 
840
  if args.query:
841
  # Query the corpus
842
- results = query_text_corpus(model, tokenizer, vector_store_path, args.query, args.top_k, args.device)
 
 
843
 
844
- # Print results
845
  print("\nSearch Results:")
846
  for i, (doc, score) in enumerate(results):
847
  print(f"\nResult {i+1} (Score: {score:.4f}):")
@@ -850,10 +984,27 @@ def main():
850
  # Extract and print only relevant sentences
851
  relevant_text = extract_relevant_sentences(doc.page_content, args.query)
852
  print(f"Content: {relevant_text}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
853
 
854
  if args.interactive:
855
  print("\nInteractive mode. Enter queries (or type 'quit' to exit).")
856
 
 
 
 
857
  while True:
858
  print("\nEnter query:")
859
  query = input()
@@ -865,9 +1016,11 @@ def main():
865
  break
866
 
867
  # Query the corpus
868
- results = query_text_corpus(model, tokenizer, vector_store_path, query, args.top_k, args.device)
 
 
869
 
870
- # Print results
871
  print("\nSearch Results:")
872
  for i, (doc, score) in enumerate(results):
873
  print(f"\nResult {i+1} (Score: {score:.4f}):")
@@ -876,6 +1029,24 @@ def main():
876
  # Extract and print only relevant sentences
877
  relevant_text = extract_relevant_sentences(doc.page_content, query)
878
  print(f"Content: {relevant_text}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
879
 
880
  if __name__ == "__main__":
881
  main()
 
16
  from langchain.docstore.document import Document
17
  from langchain.embeddings.base import Embeddings
18
  from typing import List, Dict, Any, Optional, Callable
19
+ from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
20
+ import gc
21
+ import warnings
22
+
23
+ # Ignore specific HuggingFace warnings
24
+ warnings.filterwarnings("ignore", category=UserWarning, message=".*The model doesn't have tied token embeddings.*")
25
 
26
  # Tokenizer wrapper class - same as in original code
27
  class SentencePieceTokenizerWrapper:
 
708
  print(f"Searching for: {query}")
709
  return vector_store.similarity_search_with_score(query, k=k)
710
 
711
+ # Llama model loading function
712
+ def load_llama_model(model_name="unsloth/Llama-3.2-1B-Instruct", device="cuda"):
713
+ """
714
+ Load and prepare Llama model for text generation
715
+ """
716
+ print(f"Loading LLM: {model_name}")
717
+
718
+ # Check if CUDA is available
719
+ if device == "cuda" and not torch.cuda.is_available():
720
+ print("CUDA not available, falling back to CPU")
721
+ device = "cpu"
722
+
723
+ # Quantization config for 4-bit precision to save memory
724
+ quantization = BitsAndBytesConfig(
725
+ load_in_4bit=True,
726
+ bnb_4bit_compute_dtype=torch.float16,
727
+ bnb_4bit_quant_type="nf4",
728
+ bnb_4bit_use_double_quant=True,
729
+ ) if device == "cuda" else None
730
+
731
+ # Standard HuggingFace loading
732
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
733
+ if device == "cuda":
734
+ model = AutoModelForCausalLM.from_pretrained(
735
+ model_name,
736
+ device_map="auto",
737
+ quantization_config=quantization
738
+ )
739
+ else:
740
+ model = AutoModelForCausalLM.from_pretrained(model_name)
741
+ model = model.to(device)
742
+
743
+ print("Successfully loaded model")
744
+
745
+ return model, tokenizer
746
+
747
+ def setup_qa_system(model, tokenizer, vector_store):
748
+ """
749
+ Set up a direct QA system using the model and retriever
750
+ """
751
+ # Create retriever
752
+ retriever = vector_store.as_retriever(
753
+ search_type="similarity",
754
+ search_kwargs={"k": 3}
755
+ )
756
+
757
+ # Create a function to generate answers
758
+ def generate_answer(query):
759
+ # Retrieve documents
760
+ try:
761
+ docs = retriever.invoke(query)
762
+ except:
763
+ # Fallback to older method if invoke isn't available
764
+ docs = retriever.get_relevant_documents(query)
765
+
766
+ # Extract the content
767
+ context = "\n\n".join([doc.page_content for doc in docs])
768
+
769
+ # Create prompt
770
+ prompt = f"""
771
+ आपको निम्नलिखित संदर्भ से जानकारी के आधार पर एक प्रश्न का उत्तर देना है।
772
+ यदि आप उत्तर नहीं जानते हैं, तो बस "मुझे नहीं पता" कहें।
773
+
774
+ संदर्भ:
775
+ {context}
776
+
777
+ प्रश्न: {query}
778
+
779
+ उत्तर:
780
+ """
781
+
782
+ # Generate text
783
+ inputs = tokenizer(prompt, return_tensors="pt")
784
+
785
+ # Move to the same device as the model
786
+ for k, v in inputs.items():
787
+ if hasattr(v, "to") and callable(v.to):
788
+ inputs[k] = v.to(model.device)
789
+
790
+ with torch.no_grad():
791
+ try:
792
+ outputs = model.generate(
793
+ inputs.input_ids,
794
+ max_new_tokens=512,
795
+ temperature=0.7,
796
+ top_p=0.9,
797
+ do_sample=True
798
+ )
799
+ except Exception as e:
800
+ return f"Error generating response: {str(e)}"
801
+
802
+ # Decode the generated text
803
+ full_response = tokenizer.decode(outputs[0], skip_special_tokens=True)
804
+
805
+ # Extract just the answer part (after the prompt)
806
+ answer = full_response.split("उत्तर:")[-1].strip()
807
+
808
+ return answer
809
+
810
+ return generate_answer
811
+
812
  # Main RAG functions
813
  def index_text_files(model, tokenizer, data_dir, output_dir, device="cuda", chunk_size=500):
814
  """
 
902
 
903
  processed_results.append((combined_doc, score))
904
 
905
+ return processed_results, vector_store
906
 
907
  def main():
908
  parser = argparse.ArgumentParser(description="Hindi RAG System with LangChain and FAISS")
 
928
  help="Run in interactive mode for querying")
929
  parser.add_argument("--reindex", action="store_true",
930
  help="Force reindexing even if index exists")
931
+ parser.add_argument("--qa", action="store_true",
932
+ help="Use LLM for question answering instead of just retrieval")
933
+ parser.add_argument("--llm_name", type=str, default="unsloth/Llama-3.2-1B-Instruct",
934
+ help="HuggingFace model name for the LLM")
935
  args = parser.parse_args()
936
 
937
+ # Load embedding model and tokenizer
938
+ embed_model, embed_tokenizer, config = load_model_and_tokenizer(args.model_dir, args.tokenizer_dir)
939
 
940
+ # Move embedding model to device
941
+ embed_model = embed_model.to(args.device)
942
 
943
  # Create vector store path
944
  vector_store_path = os.path.join(args.output_dir, "faiss_index")
945
 
946
+ # Load LLM if QA is enabled
947
+ llm_model = None
948
+ llm_tokenizer = None
949
+ qa_generator = None
950
+
951
+ if args.qa:
952
+ try:
953
+ # Load LLM
954
+ llm_model, llm_tokenizer = load_llama_model(args.llm_name, args.device)
955
+ print("LLM loaded successfully for QA")
956
+ except Exception as e:
957
+ print(f"Error loading LLM: {e}")
958
+ print("Falling back to retrieval-only mode")
959
+ args.qa = False
960
+
961
  if args.index or args.reindex:
962
  # Index text files
963
+ vector_store, _ = index_text_files(
964
+ embed_model, embed_tokenizer, args.data_dir, args.output_dir, args.device, args.chunk_size
965
+ )
966
  print(f"Indexing complete. Vector store saved to {vector_store_path}")
967
+
968
+ # Set up QA chain if enabled
969
+ if args.qa and llm_model is not None and llm_tokenizer is not None:
970
+ qa_generator = setup_qa_system(llm_model, llm_tokenizer, vector_store)
971
 
972
  if args.query:
973
  # Query the corpus
974
+ results, vector_store = query_text_corpus(
975
+ embed_model, embed_tokenizer, vector_store_path, args.query, args.top_k, args.device
976
+ )
977
 
978
+ # Print retrieval results
979
  print("\nSearch Results:")
980
  for i, (doc, score) in enumerate(results):
981
  print(f"\nResult {i+1} (Score: {score:.4f}):")
 
984
  # Extract and print only relevant sentences
985
  relevant_text = extract_relevant_sentences(doc.page_content, args.query)
986
  print(f"Content: {relevant_text}")
987
+
988
+ # If QA is enabled, also answer the question using the LLM
989
+ if args.qa and llm_model is not None and llm_tokenizer is not None:
990
+ if qa_generator is None:
991
+ qa_generator = setup_qa_system(llm_model, llm_tokenizer, vector_store)
992
+
993
+ # Get answer from QA chain
994
+ print("\nGenerating answer using LLM...")
995
+ try:
996
+ answer = qa_generator(args.query)
997
+ print("\nLLM Answer:")
998
+ print(answer)
999
+ except Exception as e:
1000
+ print(f"Error generating answer: {e}")
1001
 
1002
  if args.interactive:
1003
  print("\nInteractive mode. Enter queries (or type 'quit' to exit).")
1004
 
1005
+ # For the first query, load vector store
1006
+ vector_store = None
1007
+
1008
  while True:
1009
  print("\nEnter query:")
1010
  query = input()
 
1016
  break
1017
 
1018
  # Query the corpus
1019
+ results, vector_store = query_text_corpus(
1020
+ embed_model, embed_tokenizer, vector_store_path, query, args.top_k, args.device
1021
+ )
1022
 
1023
+ # Print retrieval results
1024
  print("\nSearch Results:")
1025
  for i, (doc, score) in enumerate(results):
1026
  print(f"\nResult {i+1} (Score: {score:.4f}):")
 
1029
  # Extract and print only relevant sentences
1030
  relevant_text = extract_relevant_sentences(doc.page_content, query)
1031
  print(f"Content: {relevant_text}")
1032
+
1033
+ # If QA is enabled, also answer the question using the LLM
1034
+ if args.qa and llm_model is not None and llm_tokenizer is not None:
1035
+ if qa_generator is None:
1036
+ qa_generator = setup_qa_system(llm_model, llm_tokenizer, vector_store)
1037
+
1038
+ print("\nGenerating answer using LLM...")
1039
+ try:
1040
+ answer = qa_generator(query)
1041
+ print("\nLLM Answer:")
1042
+ print(answer)
1043
+ except Exception as e:
1044
+ print(f"Error generating answer: {e}")
1045
+
1046
+ # Clean up GPU memory
1047
+ if args.device == "cuda":
1048
+ gc.collect()
1049
+ torch.cuda.empty_cache()
1050
 
1051
  if __name__ == "__main__":
1052
  main()
hindi-rag-system.py.amltmp CHANGED
@@ -16,6 +16,12 @@ from langchain.vectorstores import FAISS as LangchainFAISS
16
  from langchain.docstore.document import Document
17
  from langchain.embeddings.base import Embeddings
18
  from typing import List, Dict, Any, Optional, Callable
 
 
 
 
 
 
19
 
20
  # Tokenizer wrapper class - same as in original code
21
  class SentencePieceTokenizerWrapper:
@@ -702,6 +708,107 @@ def perform_similarity_search(vector_store, query, k=6):
702
  print(f"Searching for: {query}")
703
  return vector_store.similarity_search_with_score(query, k=k)
704
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
705
  # Main RAG functions
706
  def index_text_files(model, tokenizer, data_dir, output_dir, device="cuda", chunk_size=500):
707
  """
@@ -795,7 +902,7 @@ def query_text_corpus(model, tokenizer, vector_store_path, query, k=6, device="c
795
 
796
  processed_results.append((combined_doc, score))
797
 
798
- return processed_results
799
 
800
  def main():
801
  parser = argparse.ArgumentParser(description="Hindi RAG System with LangChain and FAISS")
@@ -821,27 +928,54 @@ def main():
821
  help="Run in interactive mode for querying")
822
  parser.add_argument("--reindex", action="store_true",
823
  help="Force reindexing even if index exists")
 
 
 
 
824
  args = parser.parse_args()
825
 
826
- # Load model and tokenizer
827
- model, tokenizer, config = load_model_and_tokenizer(args.model_dir, args.tokenizer_dir)
828
 
829
- # Move model to device
830
- model = model.to(args.device)
831
 
832
  # Create vector store path
833
  vector_store_path = os.path.join(args.output_dir, "faiss_index")
834
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
835
  if args.index or args.reindex:
836
  # Index text files
837
- index_text_files(model, tokenizer, args.data_dir, args.output_dir, args.device, args.chunk_size)
 
 
838
  print(f"Indexing complete. Vector store saved to {vector_store_path}")
 
 
 
 
839
 
840
  if args.query:
841
  # Query the corpus
842
- results = query_text_corpus(model, tokenizer, vector_store_path, args.query, args.top_k, args.device)
 
 
843
 
844
- # Print results
845
  print("\nSearch Results:")
846
  for i, (doc, score) in enumerate(results):
847
  print(f"\nResult {i+1} (Score: {score:.4f}):")
@@ -850,10 +984,27 @@ def main():
850
  # Extract and print only relevant sentences
851
  relevant_text = extract_relevant_sentences(doc.page_content, args.query)
852
  print(f"Content: {relevant_text}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
853
 
854
  if args.interactive:
855
  print("\nInteractive mode. Enter queries (or type 'quit' to exit).")
856
 
 
 
 
857
  while True:
858
  print("\nEnter query:")
859
  query = input()
@@ -865,9 +1016,11 @@ def main():
865
  break
866
 
867
  # Query the corpus
868
- results = query_text_corpus(model, tokenizer, vector_store_path, query, args.top_k, args.device)
 
 
869
 
870
- # Print results
871
  print("\nSearch Results:")
872
  for i, (doc, score) in enumerate(results):
873
  print(f"\nResult {i+1} (Score: {score:.4f}):")
@@ -876,6 +1029,24 @@ def main():
876
  # Extract and print only relevant sentences
877
  relevant_text = extract_relevant_sentences(doc.page_content, query)
878
  print(f"Content: {relevant_text}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
879
 
880
  if __name__ == "__main__":
881
  main()
 
16
  from langchain.docstore.document import Document
17
  from langchain.embeddings.base import Embeddings
18
  from typing import List, Dict, Any, Optional, Callable
19
+ from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
20
+ import gc
21
+ import warnings
22
+
23
+ # Ignore specific HuggingFace warnings
24
+ warnings.filterwarnings("ignore", category=UserWarning, message=".*The model doesn't have tied token embeddings.*")
25
 
26
  # Tokenizer wrapper class - same as in original code
27
  class SentencePieceTokenizerWrapper:
 
708
  print(f"Searching for: {query}")
709
  return vector_store.similarity_search_with_score(query, k=k)
710
 
711
+ # Llama model loading function
712
+ def load_llama_model(model_name="unsloth/Llama-3.2-1B-Instruct", device="cuda"):
713
+ """
714
+ Load and prepare Llama model for text generation
715
+ """
716
+ print(f"Loading LLM: {model_name}")
717
+
718
+ # Check if CUDA is available
719
+ if device == "cuda" and not torch.cuda.is_available():
720
+ print("CUDA not available, falling back to CPU")
721
+ device = "cpu"
722
+
723
+ # Quantization config for 4-bit precision to save memory
724
+ quantization = BitsAndBytesConfig(
725
+ load_in_4bit=True,
726
+ bnb_4bit_compute_dtype=torch.float16,
727
+ bnb_4bit_quant_type="nf4",
728
+ bnb_4bit_use_double_quant=True,
729
+ ) if device == "cuda" else None
730
+
731
+ # Standard HuggingFace loading
732
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
733
+ if device == "cuda":
734
+ model = AutoModelForCausalLM.from_pretrained(
735
+ model_name,
736
+ device_map="auto",
737
+ quantization_config=quantization
738
+ )
739
+ else:
740
+ model = AutoModelForCausalLM.from_pretrained(model_name)
741
+ model = model.to(device)
742
+
743
+ print("Successfully loaded model")
744
+
745
+ return model, tokenizer
746
+
747
+ def setup_qa_system(model, tokenizer, vector_store):
748
+ """
749
+ Set up a direct QA system using the model and retriever
750
+ """
751
+ # Create retriever
752
+ retriever = vector_store.as_retriever(
753
+ search_type="similarity",
754
+ search_kwargs={"k": 3}
755
+ )
756
+
757
+ # Create a function to generate answers
758
+ def generate_answer(query):
759
+ # Retrieve documents
760
+ try:
761
+ docs = retriever.invoke(query)
762
+ except:
763
+ # Fallback to older method if invoke isn't available
764
+ docs = retriever.get_relevant_documents(query)
765
+
766
+ # Extract the content
767
+ context = "\n\n".join([doc.page_content for doc in docs])
768
+
769
+ # Create prompt
770
+ prompt = f"""
771
+ आपको निम्नलिखित संदर्भ से जानकारी के आधार पर एक प्रश्न का उत्तर देना है।
772
+ यदि आप उत्तर नहीं जानते हैं, तो बस "मुझे नहीं पता" कहें।
773
+
774
+ संदर्भ:
775
+ {context}
776
+
777
+ प्रश्न: {query}
778
+
779
+ उत्तर:
780
+ """
781
+
782
+ # Generate text
783
+ inputs = tokenizer(prompt, return_tensors="pt")
784
+
785
+ # Move to the same device as the model
786
+ for k, v in inputs.items():
787
+ if hasattr(v, "to") and callable(v.to):
788
+ inputs[k] = v.to(model.device)
789
+
790
+ with torch.no_grad():
791
+ try:
792
+ outputs = model.generate(
793
+ inputs.input_ids,
794
+ max_new_tokens=512,
795
+ temperature=0.7,
796
+ top_p=0.9,
797
+ do_sample=True
798
+ )
799
+ except Exception as e:
800
+ return f"Error generating response: {str(e)}"
801
+
802
+ # Decode the generated text
803
+ full_response = tokenizer.decode(outputs[0], skip_special_tokens=True)
804
+
805
+ # Extract just the answer part (after the prompt)
806
+ answer = full_response.split("उत्तर:")[-1].strip()
807
+
808
+ return answer
809
+
810
+ return generate_answer
811
+
812
  # Main RAG functions
813
  def index_text_files(model, tokenizer, data_dir, output_dir, device="cuda", chunk_size=500):
814
  """
 
902
 
903
  processed_results.append((combined_doc, score))
904
 
905
+ return processed_results, vector_store
906
 
907
  def main():
908
  parser = argparse.ArgumentParser(description="Hindi RAG System with LangChain and FAISS")
 
928
  help="Run in interactive mode for querying")
929
  parser.add_argument("--reindex", action="store_true",
930
  help="Force reindexing even if index exists")
931
+ parser.add_argument("--qa", action="store_true",
932
+ help="Use LLM for question answering instead of just retrieval")
933
+ parser.add_argument("--llm_name", type=str, default="unsloth/Llama-3.2-1B-Instruct",
934
+ help="HuggingFace model name for the LLM")
935
  args = parser.parse_args()
936
 
937
+ # Load embedding model and tokenizer
938
+ embed_model, embed_tokenizer, config = load_model_and_tokenizer(args.model_dir, args.tokenizer_dir)
939
 
940
+ # Move embedding model to device
941
+ embed_model = embed_model.to(args.device)
942
 
943
  # Create vector store path
944
  vector_store_path = os.path.join(args.output_dir, "faiss_index")
945
 
946
+ # Load LLM if QA is enabled
947
+ llm_model = None
948
+ llm_tokenizer = None
949
+ qa_generator = None
950
+
951
+ if args.qa:
952
+ try:
953
+ # Load LLM
954
+ llm_model, llm_tokenizer = load_llama_model(args.llm_name, args.device)
955
+ print("LLM loaded successfully for QA")
956
+ except Exception as e:
957
+ print(f"Error loading LLM: {e}")
958
+ print("Falling back to retrieval-only mode")
959
+ args.qa = False
960
+
961
  if args.index or args.reindex:
962
  # Index text files
963
+ vector_store, _ = index_text_files(
964
+ embed_model, embed_tokenizer, args.data_dir, args.output_dir, args.device, args.chunk_size
965
+ )
966
  print(f"Indexing complete. Vector store saved to {vector_store_path}")
967
+
968
+ # Set up QA chain if enabled
969
+ if args.qa and llm_model is not None and llm_tokenizer is not None:
970
+ qa_generator = setup_qa_system(llm_model, llm_tokenizer, vector_store)
971
 
972
  if args.query:
973
  # Query the corpus
974
+ results, vector_store = query_text_corpus(
975
+ embed_model, embed_tokenizer, vector_store_path, args.query, args.top_k, args.device
976
+ )
977
 
978
+ # Print retrieval results
979
  print("\nSearch Results:")
980
  for i, (doc, score) in enumerate(results):
981
  print(f"\nResult {i+1} (Score: {score:.4f}):")
 
984
  # Extract and print only relevant sentences
985
  relevant_text = extract_relevant_sentences(doc.page_content, args.query)
986
  print(f"Content: {relevant_text}")
987
+
988
+ # If QA is enabled, also answer the question using the LLM
989
+ if args.qa and llm_model is not None and llm_tokenizer is not None:
990
+ if qa_generator is None:
991
+ qa_generator = setup_qa_system(llm_model, llm_tokenizer, vector_store)
992
+
993
+ # Get answer from QA chain
994
+ print("\nGenerating answer using LLM...")
995
+ try:
996
+ answer = qa_generator(args.query)
997
+ print("\nLLM Answer:")
998
+ print(answer)
999
+ except Exception as e:
1000
+ print(f"Error generating answer: {e}")
1001
 
1002
  if args.interactive:
1003
  print("\nInteractive mode. Enter queries (or type 'quit' to exit).")
1004
 
1005
+ # For the first query, load vector store
1006
+ vector_store = None
1007
+
1008
  while True:
1009
  print("\nEnter query:")
1010
  query = input()
 
1016
  break
1017
 
1018
  # Query the corpus
1019
+ results, vector_store = query_text_corpus(
1020
+ embed_model, embed_tokenizer, vector_store_path, query, args.top_k, args.device
1021
+ )
1022
 
1023
+ # Print retrieval results
1024
  print("\nSearch Results:")
1025
  for i, (doc, score) in enumerate(results):
1026
  print(f"\nResult {i+1} (Score: {score:.4f}):")
 
1029
  # Extract and print only relevant sentences
1030
  relevant_text = extract_relevant_sentences(doc.page_content, query)
1031
  print(f"Content: {relevant_text}")
1032
+
1033
+ # If QA is enabled, also answer the question using the LLM
1034
+ if args.qa and llm_model is not None and llm_tokenizer is not None:
1035
+ if qa_generator is None:
1036
+ qa_generator = setup_qa_system(llm_model, llm_tokenizer, vector_store)
1037
+
1038
+ print("\nGenerating answer using LLM...")
1039
+ try:
1040
+ answer = qa_generator(query)
1041
+ print("\nLLM Answer:")
1042
+ print(answer)
1043
+ except Exception as e:
1044
+ print(f"Error generating answer: {e}")
1045
+
1046
+ # Clean up GPU memory
1047
+ if args.device == "cuda":
1048
+ gc.collect()
1049
+ torch.cuda.empty_cache()
1050
 
1051
  if __name__ == "__main__":
1052
  main()