DeepVen commited on
Commit
ed62434
1 Parent(s): 5aef1e5

Upload 8 files

Browse files

switch to langchain

Files changed (2) hide show
  1. Index.py +85 -211
  2. requirements.txt +4 -6
Index.py CHANGED
@@ -1,63 +1,80 @@
1
  from fastapi import FastAPI
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
- # from transformers import pipeline
4
- from txtai.embeddings import Embeddings
5
- from txtai.pipeline import Extractor
6
  from langchain.document_loaders import WebBaseLoader
7
  from langchain.text_splitter import RecursiveCharacterTextSplitter
8
 
9
- from langchain import HuggingFaceHub
10
- from langchain.prompts import PromptTemplate
11
- from langchain.chains import LLMChain
12
- from txtai.embeddings import Embeddings
13
- from txtai.pipeline import Extractor
14
 
15
- import pandas as pd
16
- import sqlite3
17
- import os
18
 
19
  # NOTE - we configure docs_url to serve the interactive Docs at the root path
20
  # of the app. This way, we can use the docs as a landing page for the app on Spaces.
21
  app = FastAPI(docs_url="/")
22
- # app = FastAPI()
23
 
24
- # pipe = pipeline("text2text-generation", model="google/flan-t5-small")
 
 
 
 
 
 
 
25
 
 
26
 
27
- # @app.get("/generate")
28
- # def generate(text: str):
29
- # """
30
- # Using the text2text-generation pipeline from `transformers`, generate text
31
- # from the given input text. The model used is `google/flan-t5-small`, which
32
- # can be found [here](https://huggingface.co/google/flan-t5-small).
33
- # """
34
- # output = pipe(text)
35
- # return {"output": output[0]["generated_text"]}
36
 
 
 
 
37
 
38
- def load_embeddings(
39
- domain: str = "",
40
- db_present: bool = True,
41
- path: str = "sentence-transformers/all-MiniLM-L6-v2",
42
- index_name: str = "index",
43
- ):
44
- # Create embeddings model with content support
45
- embeddings = Embeddings({"path": path, "content": True})
46
 
47
- # if Vector DB is not present
48
- if not db_present:
49
- return embeddings
50
- else:
51
- if domain == "":
52
- embeddings.load(index_name) # change this later
53
- else:
54
- print(3)
55
- embeddings.load(f"{index_name}/{domain}")
56
- return embeddings
57
 
58
 
59
- def _check_if_db_exists(db_path: str) -> bool:
60
- return os.path.exists(db_path)
 
 
 
 
 
 
 
 
 
61
 
62
 
63
  def _text_splitter(doc):
@@ -68,189 +85,46 @@ def _text_splitter(doc):
68
  )
69
  return text_splitter.transform_documents(doc)
70
 
71
-
72
  def _load_docs(path: str):
73
  load_doc = WebBaseLoader(path).load()
74
  doc = _text_splitter(load_doc)
75
  return doc
76
 
77
 
78
- def _stream(dataset, limit, index: int = 0):
79
- for row in dataset:
80
- yield (index, row.page_content, None)
81
- index += 1
82
-
83
- if index >= limit:
84
- break
85
-
86
-
87
- def _max_index_id(path):
88
- db = sqlite3.connect(path)
89
-
90
- table = "sections"
91
- df = pd.read_sql_query(f"select * from {table}", db)
92
- return {"max_index": df["indexid"].max()}
93
-
94
-
95
- def _upsert_docs(doc, embeddings, vector_doc_path: str, db_present: bool):
96
- print(vector_doc_path)
97
- if db_present:
98
- print(1)
99
- max_index = _max_index_id(f"{vector_doc_path}/documents")
100
- print(max_index)
101
- embeddings.upsert(_stream(doc, 500, max_index["max_index"]))
102
- print("Embeddings done!!")
103
- embeddings.save(vector_doc_path)
104
- print("Embeddings done - 1!!")
105
- else:
106
- print(2)
107
- embeddings.index(_stream(doc, 500, 0))
108
- embeddings.save(vector_doc_path)
109
- max_index = _max_index_id(f"{vector_doc_path}/documents")
110
- print(max_index)
111
- # check
112
- # max_index = _max_index_id(f"{vector_doc_path}/documents")
113
- # print(max_index)
114
- return max_index
115
-
116
-
117
- # def prompt(question):
118
- # return f"""Answer the following question using only the context below. Say 'no answer' when the question can't be answered.
119
- # Question: {question}
120
- # Context: """
121
-
122
-
123
- # def search(query, question=None):
124
- # # Default question to query if empty
125
- # if not question:
126
- # question = query
127
-
128
- # return extractor([("answer", query, prompt(question), False)])[0][1]
129
-
130
-
131
- # @app.get("/rag")
132
- # def rag(question: str):
133
- # # question = "what is the document about?"
134
- # answer = search(question)
135
- # # print(question, answer)
136
- # return {answer}
137
-
138
-
139
- # @app.get("/index")
140
- # def get_url_file_path(url_path: str):
141
- # embeddings = load_embeddings()
142
- # doc = _load_docs(url_path)
143
- # embeddings, max_index = _upsert_docs(doc, embeddings)
144
- # return max_index
145
-
146
-
147
- @app.get("/index/{domain}/")
148
- def get_domain_file_path(domain: str, file_path: str):
149
- print(domain, file_path)
150
- print(os.getcwd())
151
- bool_value = _check_if_db_exists(db_path=f"{os.getcwd()}/index/{domain}/documents")
152
- print(bool_value)
153
- if bool_value:
154
- embeddings = load_embeddings(domain=domain, db_present=bool_value)
155
- print(embeddings)
156
- doc = _load_docs(file_path)
157
- max_index = _upsert_docs(
158
- doc=doc,
159
- embeddings=embeddings,
160
- vector_doc_path=f"{os.getcwd()}/index/{domain}",
161
- db_present=bool_value,
162
- )
163
- # print("-------")
164
- else:
165
- embeddings = load_embeddings(domain=domain, db_present=bool_value)
166
- doc = _load_docs(file_path)
167
- max_index = _upsert_docs(
168
- doc=doc,
169
- embeddings=embeddings,
170
- vector_doc_path=f"{os.getcwd()}/index/{domain}",
171
- db_present=bool_value,
172
- )
173
- # print("Final - output : ", max_index)
174
- return "Executed Successfully!!"
175
-
176
-
177
- def _check_if_db_exists(db_path: str) -> bool:
178
- return os.path.exists(db_path)
179
-
180
-
181
- def _load_embeddings_from_db(
182
- db_present: bool,
183
- domain: str,
184
- #path: str = "sentence-transformers/all-MiniLM-L6-v2",
185
- path: str = "sentence-transformers/nli-mpnet-base-v2",
186
- ):
187
- # Create embeddings model with content support
188
- embeddings = Embeddings({"path": path, "content": True})
189
- # if Vector DB is not present
190
- if not db_present:
191
- print("db not present")
192
- return embeddings
193
- else:
194
- if domain == "":
195
- print("domain empty")
196
- embeddings.load("index") # change this later
197
- else:
198
- print(3)
199
- embeddings.load(f"{os.getcwd()}/index/{domain}")
200
- return embeddings
201
 
202
 
203
  def _prompt(question):
204
- return f"""Answer the following question using only the context below. Say 'Could not find answer within the context' when the question can't be answered.
205
  Question: {question}
206
  Context: """
207
 
208
 
209
- def _search(query, extractor, question=None):
210
- # Default question to query if empty
211
- if not question:
212
- question = query
213
-
214
- # template = f"""Answer the following question using only the context below. Say 'no answer' when the question can't be answered.
215
- # Question: {question}
216
- # Context: """
217
 
218
- # prompt = PromptTemplate(template=template, input_variables=["question"])
219
- # llm_chain = LLMChain(prompt=prompt, llm=extractor)
 
 
 
 
220
 
221
- # return {"question": question, "answer": llm_chain.run(question)}
222
- print(extractor([("answer", query, _prompt(question), True)]))
223
- return extractor([("answer", query, _prompt(question), False)])[0][1]
 
224
 
225
 
226
- @app.get("/rag")
227
- def rag(domain: str, question: str):
228
- print()
229
- db_exists = _check_if_db_exists(db_path=f"{os.getcwd()}/index/{domain}/documents")
230
- print(db_exists)
231
-
232
- bool_value = _check_if_db_exists(db_path=f"{os.getcwd()}/index/{domain}/documents")
233
- print(bool_value)
234
-
235
-
236
- # if db_exists:
237
- embeddings = _load_embeddings_from_db(db_exists, domain)
238
- # Create extractor instance
239
- #extractor = Extractor(embeddings, "google/flan-t5-base")
240
- #extractor = Extractor(embeddings, "TheBloke/Llama-2-7B-GGUF")
241
- print("before calling extractor")
242
- #extractor = Extractor(embeddings, "distilbert-base-cased-distilled-squad")
243
- extractor = Extractor(embeddings, "google/flan-t5-base")
244
- # llm = HuggingFaceHub(
245
- # repo_id="google/flan-t5-xxl",
246
- # model_kwargs={"temperature": 1, "max_length": 1000000},
247
- # )
248
- # else:
249
- print("before doing Q&A")
250
- answer = _search(question, extractor)
251
-
252
- text = _prompt(question)
253
- text += "\n" + " ".join(x["text"] for x in embeddings.search(question))
254
- print("context \n")
255
- print(text)
256
- return {"question": question, "answer": answer, "context": text}
 
1
  from fastapi import FastAPI
2
+ import os
3
+
4
+
5
+ import phoenix as px
6
+ from phoenix.trace.langchain import OpenInferenceTracer, LangChainInstrumentor
7
+
8
+
9
+ from langchain.embeddings import HuggingFaceEmbeddings #for using HugginFace models
10
+ from langchain.chains.question_answering import load_qa_chain
11
+ from langchain import HuggingFaceHub
12
+
13
+ from langchain.chains import RetrievalQA
14
+ from langchain.callbacks import StdOutCallbackHandler
15
+
16
+ #from langchain.retrievers import KNNRetriever
17
+ from langchain.storage import LocalFileStore
18
+ from langchain.embeddings import CacheBackedEmbeddings
19
+ from langchain.vectorstores import FAISS
20
+
21
 
 
 
 
22
  from langchain.document_loaders import WebBaseLoader
23
  from langchain.text_splitter import RecursiveCharacterTextSplitter
24
 
25
+ # from langchain import HuggingFaceHub
26
+ # from langchain.prompts import PromptTemplate
27
+ # from langchain.chains import LLMChain
28
+ # from txtai.embeddings import Embeddings
29
+ # from txtai.pipeline import Extractor
30
 
31
+ # import pandas as pd
32
+ # import sqlite3
33
+ # import os
34
 
35
  # NOTE - we configure docs_url to serve the interactive Docs at the root path
36
  # of the app. This way, we can use the docs as a landing page for the app on Spaces.
37
  app = FastAPI(docs_url="/")
 
38
 
39
+ #phoenix setup
40
+ session = px.launch_app()
41
+ # If no exporter is specified, the tracer will export to the locally running Phoenix server
42
+ tracer = OpenInferenceTracer()
43
+ # If no tracer is specified, a tracer is constructed for you
44
+ LangChainInstrumentor(tracer).instrument()
45
+ print(session.url)
46
+
47
 
48
+ os.environ["HUGGINGFACEHUB_API_TOKEN"] = "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"
49
 
50
+ # embedding cache
51
+ store = LocalFileStore("./cache/")
 
 
 
 
 
 
 
52
 
53
+ # define embedder
54
+ core_embeddings_model = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")
55
+ embedder = CacheBackedEmbeddings.from_bytes_store(core_embeddings_model, store)
56
 
57
+ # define llm
58
+ llm=HuggingFaceHub(repo_id="google/flan-t5-xxl", model_kwargs={"temperature":1, "max_length":1000000})
59
+ #llm=HuggingFaceHub(repo_id="gpt2", model_kwargs={"temperature":1, "max_length":1000000})
60
+ handler = StdOutCallbackHandler()
 
 
 
 
61
 
62
+ # set global variable
63
+ vectorstore
64
+ retriever
 
 
 
 
 
 
 
65
 
66
 
67
+ def initialize_vectorstore():
68
+
69
+ webpage_loader = WebBaseLoader("https://www.tredence.com/case-studies/tredence-helped-a-global-retailer-providing-holistic-campaign-analytics-by-using-the-power-of-gcp").load()
70
+ webpage_chunks = text_splitter.transform_documents(webpage_loader)
71
+
72
+ # store embeddings in vector store
73
+ vectorstore = FAISS.from_documents(webpage_chunks, embedder)
74
+ print("vector store initialized with sample doc")
75
+
76
+ # instantiate a retriever
77
+ retriever = vectorstore.as_retriever()
78
 
79
 
80
  def _text_splitter(doc):
 
85
  )
86
  return text_splitter.transform_documents(doc)
87
 
 
88
  def _load_docs(path: str):
89
  load_doc = WebBaseLoader(path).load()
90
  doc = _text_splitter(load_doc)
91
  return doc
92
 
93
 
94
+ @app.get("/index/")
95
+ def get_domain_file_path(file_path: str):
96
+ print(file_path)
97
+
98
+ webpage_loader = _load_docs(file_path)
99
+
100
+ webpage_chunks = _text_splitter(webpage_loader)
101
+
102
+ # store embeddings in vector store
103
+ vectorstore.add_documents(webpage_chunks)
104
+
105
+ return "document loaded to vector store successfully!!"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
 
108
  def _prompt(question):
109
+ return f"""Answer following question using only the context below. Say 'Could not find answer with provided context' when question can't be answered.
110
  Question: {question}
111
  Context: """
112
 
113
 
114
+ @app.get("/rag")
115
+ def rag( question: str):
 
 
 
 
 
 
116
 
117
+ chain = RetrievalQA.from_chain_type(
118
+ llm=llm,
119
+ retriever=retriever,
120
+ callbacks=[handler],
121
+ return_source_documents=True
122
+ )
123
 
124
+ #response = chain("how tredence brought good insight?")
125
+ response = chain(_prompt(question))
126
+
127
+ return {"question": question, "answer": response['result']}
128
 
129
 
130
+ initialize_vectorstore()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -4,10 +4,8 @@ uvicorn[standard]==0.17.*
4
  sentencepiece==0.1.*
5
  torch==1.12.*
6
  transformers==4.*
7
- txtai==6.0.*
8
  langchain==0.0.301
9
- langsmith==0.0.40
10
- bs4==0.0.1
11
- pandas==2.1.1
12
- SQLAlchemy==2.0.21
13
- llama-cpp-python
 
4
  sentencepiece==0.1.*
5
  torch==1.12.*
6
  transformers==4.*
 
7
  langchain==0.0.301
8
+ arize-phoenix
9
+ huggingface_hub
10
+ sentence-transformers
11
+ faiss-cpu