5353###############################################################################
5454# initializations
5555###############################################################################
56- DEFAULT_MODEL_NAME = Config .OPENAI_PROMPT_MODEL_NAME
57- pinecone .init (api_key = Credentials .PINECONE_API_KEY , environment = Credentials .PINECONE_ENVIRONMENT )
58- set_llm_cache (InMemoryCache ())
5956logging .basicConfig (level = logging .DEBUG if Config .DEBUG_MODE else logging .INFO )
6057
6158
@@ -78,25 +75,74 @@ def create_documents(self, texts):
7875class HybridSearchRetriever :
7976 """Hybrid Search Retriever (OpenAI + Pinecone)"""
8077
78+ _chat : ChatOpenAI = None
79+ _openai_embeddings : OpenAIEmbeddings = None
80+ _pinecone_index : pinecone .Index = None
81+ _vector_store : Pinecone = None
82+ _text_splitter : TextSplitter = None
83+ _b25_encoder : BM25Encoder = None
84+
85+ def __init__ (self ):
86+ """Constructor"""
87+ pinecone .init (api_key = Credentials .PINECONE_API_KEY , environment = Config .PINECONE_ENVIRONMENT )
88+ set_llm_cache (InMemoryCache ())
89+
8190 # prompting wrapper
82- chat = ChatOpenAI (
83- api_key = Credentials .OPENAI_API_KEY ,
84- organization = Credentials .OPENAI_API_ORGANIZATION ,
85- cache = Config .OPENAI_CHAT_CACHE ,
86- max_retries = Config .OPENAI_CHAT_MAX_RETRIES ,
87- model = Config .OPENAI_CHAT_MODEL_NAME ,
88- temperature = Config .OPENAI_CHAT_TEMPERATURE ,
89- )
91+ @property
92+ def chat (self ) -> ChatOpenAI :
93+ """ChatOpenAI lazy read-only property."""
94+ if self ._chat is None :
95+ self ._chat = ChatOpenAI (
96+ api_key = Credentials .OPENAI_API_KEY ,
97+ organization = Credentials .OPENAI_API_ORGANIZATION ,
98+ cache = Config .OPENAI_CHAT_CACHE ,
99+ max_retries = Config .OPENAI_CHAT_MAX_RETRIES ,
100+ model = Config .OPENAI_CHAT_MODEL_NAME ,
101+ temperature = Config .OPENAI_CHAT_TEMPERATURE ,
102+ )
103+ return self ._chat
90104
91105 # embeddings
92- openai_embeddings = OpenAIEmbeddings (
93- api_key = Credentials .OPENAI_API_KEY , organization = Credentials .OPENAI_API_ORGANIZATION
94- )
95- pinecone_index = pinecone .Index (index_name = Credentials .PINECONE_INDEX_NAME )
96- vector_store = Pinecone (index = pinecone_index , embedding = openai_embeddings , text_key = "lc_id" )
97-
98- text_splitter = TextSplitter ()
99- bm25_encoder = BM25Encoder ().default ()
106+ @property
107+ def openai_embeddings (self ) -> OpenAIEmbeddings :
108+ """OpenAIEmbeddings lazy read-only property."""
109+ if self ._openai_embeddings is None :
110+ self ._openai_embeddings = OpenAIEmbeddings (
111+ api_key = Credentials .OPENAI_API_KEY , organization = Credentials .OPENAI_API_ORGANIZATION
112+ )
113+ return self ._openai_embeddings
114+
115+ @property
116+ def pinecone_index (self ) -> pinecone .Index :
117+ """pinecone.Index lazy read-only property."""
118+ if self ._pinecone_index is None :
119+ self ._pinecone_index = pinecone .Index (index_name = Config .PINECONE_INDEX_NAME )
120+ return self ._pinecone_index
121+
122+ @property
123+ def vector_store (self ) -> Pinecone :
124+ """Pinecone lazy read-only property."""
125+ if self ._vector_store is None :
126+ self ._vector_store = Pinecone (
127+ index = self .pinecone_index ,
128+ embedding = self .openai_embeddings ,
129+ text_key = Config .PINECONE_VECTORSTORE_TEXT_KEY ,
130+ )
131+ return self ._vector_store
132+
133+ @property
134+ def text_splitter (self ) -> TextSplitter :
135+ """TextSplitter lazy read-only property."""
136+ if self ._text_splitter is None :
137+ self ._text_splitter = TextSplitter ()
138+ return self ._text_splitter
139+
140+ @property
141+ def bm25_encoder (self ) -> BM25Encoder :
142+ """BM25Encoder lazy read-only property."""
143+ if self ._b25_encoder is None :
144+ self ._b25_encoder = BM25Encoder ().default ()
145+ return self ._b25_encoder
100146
101147 def cached_chat_request (
102148 self , system_message : Union [str , SystemMessage ], human_message : Union [str , HumanMessage ]
@@ -114,7 +160,9 @@ def cached_chat_request(
114160 retval = self .chat (messages )
115161 return retval
116162
117- def prompt_with_template (self , prompt : PromptTemplate , concept : str , model : str = DEFAULT_MODEL_NAME ) -> str :
163+ def prompt_with_template (
164+ self , prompt : PromptTemplate , concept : str , model : str = Config .OPENAI_PROMPT_MODEL_NAME
165+ ) -> str :
118166 """Prompt with template."""
119167 llm = OpenAI (model = model )
120168 retval = llm (prompt .format (concept = concept ))
@@ -135,17 +183,20 @@ def load(self, filepath: str):
135183 """
136184 try :
137185 logging .debug ("Deleting index..." )
138- pinecone .delete_index (Credentials .PINECONE_INDEX_NAME )
186+ pinecone .delete_index (Config .PINECONE_INDEX_NAME )
139187 except pinecone .exceptions .PineconeException :
140188 logging .debug ("Index does not exist. Continuing..." )
141189
142190 metadata_config = {
143- "indexed" : ["lc_id" , "lc_type" ],
191+ "indexed" : [Config . PINECONE_VECTORSTORE_TEXT_KEY , "lc_type" ],
144192 "context" : ["lc_text" ],
145193 }
146194 logging .debug ("Creating index. This may take a few minutes..." )
147195 pinecone .create_index (
148- Credentials .PINECONE_INDEX_NAME , dimension = 1536 , metric = "dotproduct" , metadata_config = metadata_config
196+ Config .PINECONE_INDEX_NAME ,
197+ dimension = Config .PINECONE_DIMENSIONS ,
198+ metric = Config .PINECONE_METRIC ,
199+ metadata_config = metadata_config ,
149200 )
150201
151202 pdf_files = glob .glob (os .path .join (filepath , "*.pdf" ))
@@ -187,11 +238,13 @@ def rag(self, human_message: Union[str, HumanMessage]):
187238 logging .debug ("Converting human_message to HumanMessage" )
188239 human_message = HumanMessage (content = human_message )
189240
241+ # ---------------------------------------------------------------------
242+ # 1.) Retrieve relevant documents from Pinecone vector database
243+ # ---------------------------------------------------------------------
190244 retriever = PineconeHybridSearchRetriever (
191245 embeddings = self .openai_embeddings , sparse_encoder = self .bm25_encoder , index = self .pinecone_index
192246 )
193247 documents = retriever .get_relevant_documents (query = human_message .content )
194- logging .debug ("Retrieved %i related documents from Pinecone" , len (documents ))
195248
196249 # Extract the text from the documents
197250 document_texts = [doc .page_content for doc in documents ]
@@ -202,13 +255,19 @@ def rag(self, human_message: Union[str, HumanMessage]):
202255 into your responses:\n \n
203256 """
204257 )
205- system_message = f"{ leader } { '. ' .join (document_texts )} "
258+ system_message_content = f"{ leader } { '. ' .join (document_texts )} "
259+ system_message = SystemMessage (content = system_message_content )
260+ # ---------------------------------------------------------------------
261+ # finished with hybrid search setup
262+ # ---------------------------------------------------------------------
206263
207- logging .debug ("System messages contains %i words" , len (system_message .split ()))
208- logging .debug ("Prompt: %s" , system_message )
209- system_message = SystemMessage (content = system_message )
264+ # 2.) get a response from the chat model
210265 response = self .cached_chat_request (system_message = system_message , human_message = human_message )
211266
267+ logging .debug ("------------------------------------------------------" )
268+ logging .debug ("Retrieved %i related documents from Pinecone" , len (documents ))
269+ logging .debug ("System messages contains %i words" , len (system_message .content .split ()))
270+ logging .debug ("Prompt: %s" , system_message .content )
212271 logging .debug ("Response:" )
213272 logging .debug ("------------------------------------------------------" )
214273 return response .content
0 commit comments