53
53
###############################################################################
54
54
# initializations
55
55
###############################################################################
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 ())
59
56
logging .basicConfig (level = logging .DEBUG if Config .DEBUG_MODE else logging .INFO )
60
57
61
58
@@ -78,25 +75,74 @@ def create_documents(self, texts):
78
75
class HybridSearchRetriever :
79
76
"""Hybrid Search Retriever (OpenAI + Pinecone)"""
80
77
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
+
81
90
# 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
90
104
91
105
# 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
100
146
101
147
def cached_chat_request (
102
148
self , system_message : Union [str , SystemMessage ], human_message : Union [str , HumanMessage ]
@@ -114,7 +160,9 @@ def cached_chat_request(
114
160
retval = self .chat (messages )
115
161
return retval
116
162
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 :
118
166
"""Prompt with template."""
119
167
llm = OpenAI (model = model )
120
168
retval = llm (prompt .format (concept = concept ))
@@ -135,17 +183,20 @@ def load(self, filepath: str):
135
183
"""
136
184
try :
137
185
logging .debug ("Deleting index..." )
138
- pinecone .delete_index (Credentials .PINECONE_INDEX_NAME )
186
+ pinecone .delete_index (Config .PINECONE_INDEX_NAME )
139
187
except pinecone .exceptions .PineconeException :
140
188
logging .debug ("Index does not exist. Continuing..." )
141
189
142
190
metadata_config = {
143
- "indexed" : ["lc_id" , "lc_type" ],
191
+ "indexed" : [Config . PINECONE_VECTORSTORE_TEXT_KEY , "lc_type" ],
144
192
"context" : ["lc_text" ],
145
193
}
146
194
logging .debug ("Creating index. This may take a few minutes..." )
147
195
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 ,
149
200
)
150
201
151
202
pdf_files = glob .glob (os .path .join (filepath , "*.pdf" ))
@@ -187,11 +238,13 @@ def rag(self, human_message: Union[str, HumanMessage]):
187
238
logging .debug ("Converting human_message to HumanMessage" )
188
239
human_message = HumanMessage (content = human_message )
189
240
241
+ # ---------------------------------------------------------------------
242
+ # 1.) Retrieve relevant documents from Pinecone vector database
243
+ # ---------------------------------------------------------------------
190
244
retriever = PineconeHybridSearchRetriever (
191
245
embeddings = self .openai_embeddings , sparse_encoder = self .bm25_encoder , index = self .pinecone_index
192
246
)
193
247
documents = retriever .get_relevant_documents (query = human_message .content )
194
- logging .debug ("Retrieved %i related documents from Pinecone" , len (documents ))
195
248
196
249
# Extract the text from the documents
197
250
document_texts = [doc .page_content for doc in documents ]
@@ -202,13 +255,19 @@ def rag(self, human_message: Union[str, HumanMessage]):
202
255
into your responses:\n \n
203
256
"""
204
257
)
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
+ # ---------------------------------------------------------------------
206
263
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
210
265
response = self .cached_chat_request (system_message = system_message , human_message = human_message )
211
266
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 )
212
271
logging .debug ("Response:" )
213
272
logging .debug ("------------------------------------------------------" )
214
273
return response .content
0 commit comments