Advanced RAG using Llama Index

Advanced RAG using Llama Index

Jan 6, 2024

Jan 6, 2024

Here we will implement concept to improve retrieval that can be useful for contect aware text processing where we would also consider the surrounding context of a sentence to understand valuable insights.

What is Llama-Index ?

LlamaIndex is a data framework for LLM -based applications to ingest, structure, and access private or domain-specific data.

How to use Llama-Index ?

The basic usage is a five step process that takes us from our raw, unstructured data to LLM generated content based on that data.

  1. Load Documents

  2. Parse Documents into Nodes

  3. Build Index

  4. Query the Index

  5. Parse the response

Install required dependencies

!pip install llama-index -qU
!pip install -q openai
!pip install pypdf
!pip install doc2txt
!pip install -qU llama-cpp-python
!pip install transformers
!pip install accelerate

Import required dependencies

import os
import openai
from getpass import getpass
#
import logging
import sys
from pprint import pprint
#
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))
#
from llama_index import(VectorStoreIndex,
                        SimpleDirectoryReader,
                        load_index_from_storage,
                        StorageContext,
                        ServiceContext,
                        Document)

from llama_index.llms import OpenAI,HuggingFaceLLM
from llama_index.prompts import PromptTemplate
from llama_index.text_splitter import SentenceSplitter
from llama_index.embeddings import OpenAIEmbedding,HuggingFaceEmbedding
from llama_index.schema import MetadataMode
from llama_index.postprocessor import MetadataReplacementPostProcessor

What is a Document?

A Document is a container that holds data from various sources such as a PDF, an API output or retrieved data from a database.

documents = SimpleDirectoryReader('./Data/').load_data()
print(len(documents))
pprint(documents)

The PDF has been converted to a list of 12 elements.

documents[0].get_content()

## Response
Face Recognition System Using Python
 This article was published as a part of the Data Science Blogathon.
Introduction
Face recognition is different from face detection. In face detection, we had only detected the location of
human faces, and we recognized the identity of faces in the face recognition task.
In this article, we are going to build a face recognition system using python with the help of face
recognition library .
There are many algorithms available in the market for face recognition. This broad computer vision
challenge is detecting faces from videos and pictures. Many applications can be built on top of recognition
systems. Many big companies are adopting recognition systems for their security and authentication
purposes.
Use Cases of Recognition Systems
Face recognition systems are widely used in the modern era, and many new innovative systems are built on
top of recognition systems.
There are a few used cases :
Finding Missing Person
Identifying accounts on social media
Recognizing Drivers in Cars
School Attendance System
Several methods and algorithms implement facial recognition systems depending on the performance and
accuracy.
Traditional Face Recognition Algorithm
Traditional face recognition algorithms don’t meet modern-day’s facial recognition standards. They were
designed to recognize faces using old conventional algorithms.
OpenCV provides some traditional facial Recognition Algorithms.
Eigenfaces
Scale Invariant Feature Transform (SIFT)
Fisher faces
Local Binary Patterns Histograms (LBPH)

documents[0].metadata

## RESPONSE
{'file_path': 'Data/chinahistory.txt',
 'file_name': 'chinahistory.txt',
 'file_type': 'text/plain',
 'file_size': 977274,
 'creation_date': '2023-12-18',
 'last_modified_date': '2023-12-05',
 'last_accessed_date': '2023-12-18'}

Set up the llm

from llama_index.llms import HuggingFaceLLM
from llama_index.prompts import PromptTemplate
llm = HuggingFaceLLM(
    model_name="HuggingFaceH4/zephyr-7b-beta",
    tokenizer_name="HuggingFaceH4/zephyr-7b-beta",
    #query_wrapper_prompt=PromptTemplate("<|system|>Please check if the following pieces of context has any mention of the keywords provided in the question.If not ten say that you do not know the answer.Please do not make up your own answer.</s>\n<|user|>\nQuestion:{query_str}</s>\n<|assistant|>\n"),
    # query_wrapper_prompt=PromptTemplate(template),
    context_window=4096,
    max_new_tokens=512,
    model_kwargs={'trust_remote_code':True},
    generate_kwargs={"temperature": 0.0},
    device_map="auto",)

Set up the embedding Model

from llama_index.embeddings import resolve_embed_model
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
#embed_model = resolve_embed_model("local:BAAI/bge-large-en-v1.5")
embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-large-en-v1.5")

What are Node objects in LlamaIndex?

A Node object in LlamaIndex represents a “chunk” or a portion of a source Document.

This could be a text chunk, an image, or other types of data. Similar to Documents, Nodes also contain metadata and relationship information with other nodes.

Nodes are considered a first-class citizen in LlamaIndex.

This means you can define Nodes and all its attributes directly.

Alternatively, you can also “parse” source Documents into Nodes using the NodeParser classes. By default, every Node derived from a Document will inherit the same metadata from that Document. For example, a “file_name” field in the Document is propagated to every Node.

The choice between sending the entire Document object to the index or converting the Document into Node objects before indexing depends on your specific use case and the structure of your data.

  1. Sending the entire Document object to the index: This approach is suitable for maintaining the entire document as a single unit. This might be useful when your documents are relatively short or when the context between different parts of the document is important.

  2. Converting the Document into Node objects before indexing: This approach is practical when your documents are long, and you want to break them down into smaller chunks (or nodes) before indexing. This can be beneficial when you want to retrieve specific parts of a document rather than the entire document.

Node parsing and Indexing (Base and Sentence Window Method)

The SentenceWindowNodeParser class is designed to parse documents into nodes (sentences) and capture a window of surrounding sentences for each node.

This can be useful for context-aware text processing, where understanding the surrounding context of a sentence can provide valuable insights.

  • Node: Represents a unit of text, in this case, a sentence.

  • Window: A range of sentences surrounding a particular sentence. For example, if the window size is 3, and the current sentence is the 5th sentence, the window will capture sentences 2 to 8.

  • Metadata: Additional information associated with a node, such as the window of surrounding sentences.

Working Mechanism

When we create an instance of the SentenceWindowNodeParser using the from_defaults method with the custom_sentence_splitter (which splits text based on "\n●", "\n-", or "\n" delimiters) and the specified parameters (window_size=3, include_prev_next_rel=True, include_metadata=True), we are setting up a parser to process documents as follows:

  • Each document’s text will be divided into sentences using the custom splitter.

  • For each sentence, a node is generated.

  • This node will contain metadata capturing the surrounding 3 sentences on each side.

  • Additionally, each node will reference its preceding and succeeding sentences.

  • Calling get_nodes_from_documents with a list of documents will return a list of these nodes, each representing a sentence, enriched with the specified metadata and relationships.

#create senetence window node parser with default settings
from llama_index.node_parser import SentenceWindowNodeParser,SimpleNodeParser
sentence_node_parser = SentenceWindowNodeParser.from_defaults(
    window_size=3,
    window_metadata_key="window",
    original_text_metadata_key="original_text")
#base_node_parser = SentenceSplitter(llm=llm)
base_node_parser = SimpleNodeParser()
#
nodes = sentence_node_parser.get_nodes_from_documents(documents)
base_nodes = base_node_parser.get_nodes_from_documents(documents)
#
print(f"SENTENCE NODES :\n {nodes[10]}")
print(f"BASE NODES :\n {base_nodes[10]}")
SENTENCE NODES :
 Node ID: 8418b939-dc08-42a6-8ee1-821e46f7a2a1
Text: Traditional Face Recognition Algorithm Traditional face
recognition algorithms don’t meet modern-day’s facial recognition
standards.
BASE NODES :
 Node ID: 7a94495b-2f49-4cc4-8fd4-87f5fb0f645e
Text: Now let’s test the model prediction using text in different
languages. def predict(text): x = cv.transform([text]

dict(nodes[10]) # since no indexing performed so embeding is None

#### RESPONSE
{'id_': '8418b939-dc08-42a6-8ee1-821e46f7a2a1',
 'embedding': None,
 'metadata': {'window': 'Many big companies are adopting recognition systems for their security and authentication\npurposes.\n Use Cases of Recognition Systems\nFace recognition systems are widely used in the modern era, and many new innovative systems are built on\ntop of recognition systems.\n There are a few used cases :\nFinding Missing Person\nIdentifying accounts on social media\nRecognizing Drivers in Cars\nSchool Attendance System\nSeveral methods and algorithms implement facial recognition systems depending on the performance and\naccuracy.\n Traditional Face Recognition Algorithm\nTraditional face recognition algorithms don’t meet modern-day’s facial recognition standards.  They were\ndesigned to recognize faces using old conventional algorithms.\n OpenCV provides some traditional facial Recognition Algorithms.\n',
  'original_text': 'Traditional Face Recognition Algorithm\nTraditional face recognition algorithms don’t meet modern-day’s facial recognition standards. ',
  'page_label': '1',
  'file_name': 'face-recognition-system-using-python.pdf',
  'file_path': 'Data/face-recognition-system-using-python.pdf',
  'file_type': 'application/pdf',
  'file_size': 465666,
  'creation_date': '2023-12-21',
  'last_modified_date': '2023-12-21',
  'last_accessed_date': '2023-12-21'},
 'excluded_embed_metadata_keys': ['file_name',
  'file_type',
  'file_size',
  'creation_date',
  'last_modified_date',
  'last_accessed_date',
  'window',
  'original_text'],
 'excluded_llm_metadata_keys': ['file_name',
  'file_type',
  'file_size',
  'creation_date',
  'last_modified_date',
  'last_accessed_date',
  'window',
  'original_text'],
 'relationships': {<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='4538122a-90cd-4af5-b6e9-84b8399da135', node_type=<ObjectType.DOCUMENT: '4'>, metadata={'page_label': '1', 'file_name': 'face-recognition-system-using-python.pdf', 'file_path': 'Data/face-recognition-system-using-python.pdf', 'file_type': 'application/pdf', 'file_size': 465666, 'creation_date': '2023-12-21', 'last_modified_date': '2023-12-21', 'last_accessed_date': '2023-12-21'}, hash='a819d446ca212183fcf6284e3cc010747bf04a25aa39040bff8877fe5e35734d'),
  <NodeRelationship.PREVIOUS: '2'>: RelatedNodeInfo(node_id='942980f2-6328-45a8-94ce-2afe8fba03ba', node_type=<ObjectType.TEXT: '1'>, metadata={'window': 'Many applications can be built on top of recognition\nsystems.  Many big companies are adopting recognition systems for their security and authentication\npurposes.\n Use Cases of Recognition Systems\nFace recognition systems are widely used in the modern era, and many new innovative systems are built on\ntop of recognition systems.\n There are a few used cases :\nFinding Missing Person\nIdentifying accounts on social media\nRecognizing Drivers in Cars\nSchool Attendance System\nSeveral methods and algorithms implement facial recognition systems depending on the performance and\naccuracy.\n Traditional Face Recognition Algorithm\nTraditional face recognition algorithms don’t meet modern-day’s facial recognition standards.  They were\ndesigned to recognize faces using old conventional algorithms.\n', 'original_text': 'There are a few used cases :\nFinding Missing Person\nIdentifying accounts on social media\nRecognizing Drivers in Cars\nSchool Attendance System\nSeveral methods and algorithms implement facial recognition systems depending on the performance and\naccuracy.\n', 'page_label': '1', 'file_name': 'face-recognition-system-using-python.pdf', 'file_path': 'Data/face-recognition-system-using-python.pdf', 'file_type': 'application/pdf', 'file_size': 465666, 'creation_date': '2023-12-21', 'last_modified_date': '2023-12-21', 'last_accessed_date': '2023-12-21'}, hash='c7993150674462ffbf83c9cfbb786980c1f1d5ea27b2313954b4901f55448f59'),
  <NodeRelationship.NEXT: '3'>: RelatedNodeInfo(node_id='18f77456-c93d-478d-a162-e4d01ad8135b', node_type=<ObjectType.TEXT: '1'>, metadata={'window': 'Use Cases of Recognition Systems\nFace recognition systems are widely used in the modern era, and many new innovative systems are built on\ntop of recognition systems.\n There are a few used cases :\nFinding Missing Person\nIdentifying accounts on social media\nRecognizing Drivers in Cars\nSchool Attendance System\nSeveral methods and algorithms implement facial recognition systems depending on the performance and\naccuracy.\n Traditional Face Recognition Algorithm\nTraditional face recognition algorithms don’t meet modern-day’s facial recognition standards.  They were\ndesigned to recognize faces using old conventional algorithms.\n OpenCV provides some traditional facial Recognition Algorithms.\n Eigenfaces\nScale Invariant Feature Transform (SIFT)\nFisher faces\nLocal Binary Patterns Histograms (LBPH)\nCOMPUTER VISION\nIMAGE ANALYSIS\nINTERMEDIATE\nPYTHON', 'original_text': 'They were\ndesigned to recognize faces using old conventional algorithms.\n'}, hash='4c57a3fcceaebf806622383637926ea4e27e153542a4d2ce7a4a82d3df8a72de')},
 'hash': '5f83425f868962e1066c20252056676e299fc51a8af0dbab4bb3c8bcc9130e2f',
 'text': 'Traditional Face Recognition Algorithm\nTraditional face recognition algorithms don’t meet modern-day’s facial recognition standards. ',
 'start_char_idx': 1166,
 'end_char_idx': 1299,
 'text_template': '{metadata_str}\n\n{content}',
 'metadata_template': '{key}: {value}',
 'metadata_seperator': '\n'}
dict(base_nodes[10])

#### Response
{'id_': '7a94495b-2f49-4cc4-8fd4-87f5fb0f645e',
 'embedding': None,
 'metadata': {'page_label': '5',
  'file_name': 'language-detection-using-natural-language-processing.pdf',
  'file_path': 'Data/language-detection-using-natural-language-processing.pdf',
  'file_type': 'application/pdf',
  'file_size': 195783,
  'creation_date': '2023-12-21',
  'last_modified_date': '2023-12-21',
  'last_accessed_date': '2023-12-21'},
 'excluded_embed_metadata_keys': ['file_name',
  'file_type',
  'file_size',
  'creation_date',
  'last_modified_date',
  'last_accessed_date'],
 'excluded_llm_metadata_keys': ['file_name',
  'file_type',
  'file_size',
  'creation_date',
  'last_modified_date',
  'last_accessed_date'],
 'relationships': {<NodeRelationship.SOURCE: '1'>: RelatedNodeInfo(node_id='a4b1f114-415f-439d-b3f4-379c8d71fc43', node_type=<ObjectType.DOCUMENT: '4'>, metadata={'page_label': '5', 'file_name': 'language-detection-using-natural-language-processing.pdf', 'file_path': 'Data/language-detection-using-natural-language-processing.pdf', 'file_type': 'application/pdf', 'file_size': 195783, 'creation_date': '2023-12-21', 'last_modified_date': '2023-12-21', 'last_accessed_date': '2023-12-21'}, hash='f76b1e514907769b0c6b977778cdeb701807c1e74065734e04c9ba3b0fe7b4a7'),
  <NodeRelationship.PREVIOUS: '2'>: RelatedNodeInfo(node_id='10fbf0bb-5c61-4aad-b46f-6eb774620df1', node_type=<ObjectType.TEXT: '1'>, metadata={'page_label': '4', 'file_name': 'language-detection-using-natural-language-processing.pdf', 'file_path': 'Data/language-detection-using-natural-language-processing.pdf', 'file_type': 'application/pdf', 'file_size': 195783, 'creation_date': '2023-12-21', 'last_modified_date': '2023-12-21', 'last_accessed_date': '2023-12-21'}, hash='bfe1b6d4a868679c202ab1cbdfeb8142ab7b58aa2cdeb4ab2e39a544c44054fc'),
  <NodeRelationship.NEXT: '3'>: RelatedNodeInfo(node_id='0fada0d4-4fc5-4624-ba2d-625d01907fe4', node_type=<ObjectType.TEXT: '1'>, metadata={}, hash='e9ab5e4b4d35818ac4f01203c6c756732e8bd302136467c7aab00f698f2c4584')},
 'hash': 'cc3f4c2fb51725dbd2e8386960c5451c056454e3408568321840debe993c6207',
 'text': 'Now let’s test the model prediction using text in different languages.\ndef predict(text): x = cv.transform([text]).toarray() # converting text to bag of words model (Vector) lang =\nmodel.predict(x) # predicting the language lang = le.inverse_transform(lang) # finding the language\ncorresponding the the predicted value print("The langauge is in",lang[0]) # printing the language\nAs you can see, the predictions done by the model are very accurate. You can test using different other\nlanguages.\n\xa0\nFull Code\nimport pandas as pd import numpy as np import re import seaborn as sns import matplotlib.pyplot as plt import\nwarnings warnings.simplefilter("ignore") # Loading the dataset data = pd.read_csv("Language Detection.csv") #\nvalue count for each language data["Language"].value_counts() # separating the independent and dependant',
 'start_char_idx': 0,
 'end_char_idx': 830,
 'text_template': '{metadata_str}\n\n{content}',
 'metadata_template': '{key}: {value}',
 'metadata_seperator': '\n'}
  • The sentence nodes (nodes) as illustrated above captures the relationshsips as well

What is an IndexNode in LlamaIndex?

An IndexNode is a node object used in LlamaIndex.

It represents chunks of the original documents that are stored in an Index. The Index is a data structure that allows for quick retrieval of relevant context for a user query, which is fundamental for retrieval-augmented generation (RAG) use cases.

At its core, the IndexNode inherits properties from a TextNode, meaning it primarily represents textual content.

However, the distinguishing feature of an IndexNode is its index_id attribute. This index_id acts as a unique identifier or reference to another object, allowing the node to point or link to other entities within the system.

This referencing capability adds a layer of connectivity and relational information on top of the textual content.

For example, in the context of recursive retrieval and node references, smaller chunks (represented as IndexNode objects) can point to bigger parent chunks. Smaller chunks are retrieved during query time, but references to bigger chunks are followed.

This allows for more context for synthesis.

What is ServiceContext in LlamaIndex?

The ServiceContext is a bundle of commonly used resources used during the indexing and querying stage in a LlamaIndex pipeline/application.

ctx_sentence = ServiceContext.from_defaults(
    llm=llm,
    embed_model=embed_model,
    node_parser=nodes)
# The above has SentenceWindowNodeParser incorporated
#
ctx_base = ServiceContext.from_defaults(
    llm=llm,
    embed_model=embed_model,
    node_parser=base_nodes)

What is VectorStoreIndex in LlamaIndex ?

A VectorStoreIndex in LlamaIndex is a type of index that uses vector representations of text for efficient retrieval of relevant context.

It is built on top of a VectorStore, which is a data structure that stores vectors and allows for quick nearest neighbor search.

The VectorStoreIndex takes in IndexNode objects, which represent chunks of the original documents.

It uses an embedding model (specified in the ServiceContext) to convert the text content of these nodes into vector representations. These vectors are then stored in the VectorStore.

During query time, the VectorStoreIndex can quickly retrieve the most relevant nodes for a given query.

It does this by converting the query into a vector using the same embedding model, and then performing a nearest neighbor search in the VectorStore.

sentence_index = VectorStoreIndex(
    nodes,
    service_context=ctx_sentence)
base_index = VectorStoreIndex(
    base_nodes,
    service_context=ctx_base)

What is RetrieverQueryEngine in LlamaIndex ?

A RetrieverQueryEngine in LlamaIndex is a type of query engine that uses a retriever to fetch relevant context from an index given a user query.

It is designed to work with retrievers, such as the VectorStoreRetriever created from a VectorStoreIndex.

The RetrieverQueryEngine takes a retriever and a response synthesizer as inputs. The retriever is responsible for fetching relevant IndexNode objects from the index, while the response synthesizer is used to generate a natural language response based on the retrieved nodes and the user query.

What is MetadataReplacementPostProcessor in LlamaIndex ?

MetadataReplacementPostProcessor is used to replace the node content with a field from the node metadata. If the field is not present in the metadata, then the node text remains unchanged. Most useful when used in combination with the SentenceWindowNodeParser.

from llama_index.indices.postprocessor import MetadataReplacementPostProcessor
sentence_query_engine = sentence_index.as_query_engine(
    similarity_top_k=5,
    verbose=True,
    node_postprocessor=[
        MetadataReplacementPostProcessor("window")
        ],
    )

#
base_query_engine = base_index.as_query_engine(
    similarity_top_k=5,
    verbose=True,
    node_postprocessor=[
        MetadataReplacementPostProcessor("window")
        ],
    )

Run Query for SentenceWindow Parser Query engine

query ="Sample code to detect faces in an image using python."
response = sentence_query_engine.query(query)
from IPython.display import display,Markdown
display(Markdown(f"<b>{response}</b>"))

Response Generated

Here’s a sample code to detect faces in an image using Python and the OpenCV library:


# Load the pre-trained face detection model
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# Load the image
img = cv2.imread('image.jpg')
# Convert the image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Detect faces in the grayscale image
faces = face_cascade.detectMultiScale(gray, 1.2, 5)
# Draw a rectangle around each face
for (x, y, w, h) in faces:
    cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)
# Display the image with the detected faces
cv2.imshow('Face Detection', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

In this code, we first load the pre-trained face detection model using the CascadeClassifier function from OpenCV. We then load the image, convert it to grayscale, and pass it to the detectMultiScale function of the face detection model to detect faces. We then draw a rectangle around each face using the rectangle function of OpenCV. Finally, we display the image with the detected faces using the imshow function of OpenCV.

Note: Make sure to replace ‘haarcascade_frontalface_default.xml’ with the path to your pre-trained face detection model.

Run Query for Base Node Parser Query engine

response = base_query_engine.query(query)
#
display(Markdown(f"<b>{response}</b>"))

Response Generated

import cv2
import numpy as np

img = cv2.imread('image.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
faces = face_cascade.detectMultiScale(gray, 1.2, 5)

for (x, y, w, h) in faces:
    cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

This code uses the Haar Cascade algorithm to detect faces in an image. The haarcascade_frontalface_default.xml file contains the trained classifier for face detection. The detectMultiScale() function is used to detect multiple faces in the image with a certain scale factor and minimum neighbor size. The detected faces are then drawn as rectangles on the original image using the rectangle() function. The imshow() function is used to display the image, and the waitKey() function is used to wait for a key press before closing the window. The destroyAllWindows() function is used to destroy all the windows created during the execution of the program.

Save and Reload the VectorStore

# mount on google drive
from google.colab import drive
drive.mount('/content/drive')

Save to Persistent Storage

sentence_index.storage_context.persist(persist_dir="location in Gdrive")
base_index.storage_context.persist(persist_dir="location in Gdrive")

Retrieve from Storage

# rebuild storage
SC_retrieved_sentence = StorageContext.from_defaults(persist_dir="location in Gdrive")
SC_retrieved_base = StorageContext.from_defaults(persist_dir="location in Gdrive")

Load Index

retrieved_sentence_index = load_index_from_storage(
    SC_retrieved_sentence,
    service_context=ctx_sentence)
retrieved_base_index = load_index_from_storage(
    SC_retrieved_base,
    service_context=ctx_base)

Recreate Query Engine

from llama_index.postprocessor import MetadataReplacementPostProcessor
#
sentence_query_engine = retrieved_sentence_index.as_query_engine(similarity_top_k=5,
                                                                 verbose=True,
                                                                 node_postprocessor=[MetadataReplacementPostProcessor("window")],)
base_query_engine = retrieved_base_index.as_query_engine(similarity_top_k=5,
                                                                 verbose=True,
                                                                 )

Initiate Question and Synthesize Response

base_response = base_query_engine.query(query)
#
display(Markdown(f"<b>{base_response}</b>"))


### RESPONSE
import cv2
import numpy as np

img = cv2.imread('image.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
faces = face_cascade.detectMultiScale(gray, 1.2, 5)

for (x, y, w, h) in faces:
    cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
This code uses the Haar Cascade algorithm to detect faces in an image. The haarcascade_frontalface_default.xml file contains the trained classifier for face detection. The detectMultiScale() function is used to detect multiple faces in the image with a certain scale factor and minimum neighbor size. The detected faces are then drawn as rectangles on the original image using the rectangle() function. The imshow() function is used to display the image, and the waitKey() function is used to wait for a key press before closing the window. The destroyAllWindows() function is

sentence_response = sentence_query_engine.query(query)
display(Markdown(f"<b>{sentence_response}</b>"))

### RESPONSE
Here's a sample code to detect faces in an image using Python and the OpenCV library:

import cv2
import numpy as np

# Load the pre-trained face detection model
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

# Load the image
img = cv2.imread('image.jpg')

# Convert the image to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Detect faces in the grayscale image
faces = face_cascade.detectMultiScale(gray, 1.2, 5)

# Draw a rectangle around each face
for (x, y, w, h) in faces:
    cv2.rectangle(img, (x, y), (x+w, y+h), (255, 0, 0), 2)

# Display the image with the detected faces
cv2.imshow('Face Detection', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
In this code, we first load the pre-trained face detection model using the CascadeClassifier function from OpenCV. We then load the image, convert it to grayscale, and pass it to the detectMultiScale function of the face detection model to detect faces. We then draw a rectangle around each face using the rectangle function of OpenCV. Finally, we display the image with the detected faces using the imshow function of OpenCV.

Note: Make sure to replace 'haarcascade_frontalface_default.xml' with the path to your pre-trained face detection model

Conclusion

We have implemented SentenceWindowNodeParser mechanism to improve the Retrieval Coherence.

References

LlamaIndex