SiddarthaRachakonda
commited on
Commit
•
d2fe0f0
1
Parent(s):
f49a532
modified rag system
Browse files- .gitignore +13 -1
- app/callbacks.py +2 -2
- app/chains.py +18 -9
- app/code_data/langchain_repo +1 -0
- app/data_indexing.py +18 -9
- app/main.py +10 -3
- app/prompts.py +15 -3
.gitignore
CHANGED
@@ -1,3 +1,15 @@
|
|
1 |
env.sh
|
2 |
|
3 |
-
test_request.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
env.sh
|
2 |
|
3 |
+
test_request.py
|
4 |
+
|
5 |
+
.DS_Store
|
6 |
+
|
7 |
+
__pycache__
|
8 |
+
|
9 |
+
sources.txt
|
10 |
+
|
11 |
+
.venv
|
12 |
+
|
13 |
+
data_indexing.ipynb
|
14 |
+
|
15 |
+
app/code_data/
|
app/callbacks.py
CHANGED
@@ -15,8 +15,8 @@ class LogResponseCallback(BaseCallbackHandler):
|
|
15 |
"""Run when llm ends running."""
|
16 |
# TODO: The function on_llm_end is going to be called when the LLM stops sending
|
17 |
# the response. Use the crud.add_message function to capture that response.
|
18 |
-
print(outputs)
|
19 |
-
print(outputs.generations[0][0].text)
|
20 |
crud.add_message(self.db, schemas.MessageBase(message=outputs.generations[0][0].text, type="assistant"), self.user_request.username)
|
21 |
|
22 |
def on_llm_start(
|
|
|
15 |
"""Run when llm ends running."""
|
16 |
# TODO: The function on_llm_end is going to be called when the LLM stops sending
|
17 |
# the response. Use the crud.add_message function to capture that response.
|
18 |
+
# print(outputs)
|
19 |
+
# print(outputs.generations[0][0].text)
|
20 |
crud.add_message(self.db, schemas.MessageBase(message=outputs.generations[0][0].text, type="assistant"), self.user_request.username)
|
21 |
|
22 |
def on_llm_start(
|
app/chains.py
CHANGED
@@ -6,7 +6,9 @@ from app.prompts import (
|
|
6 |
raw_prompt,
|
7 |
raw_prompt_formatted,
|
8 |
history_prompt_formatted,
|
|
|
9 |
format_context,
|
|
|
10 |
tokenizer
|
11 |
)
|
12 |
from app.data_indexing import DataIndexer
|
@@ -30,22 +32,29 @@ formatted_chain = (raw_prompt_formatted | llm).with_types(input_type=schemas.Use
|
|
30 |
history_chain = (history_prompt_formatted | llm).with_types(input_type=schemas.HistoryInput)
|
31 |
|
32 |
# TODO: Let's construct the standalone_chain by piping standalone_prompt_formatted with the LLM
|
33 |
-
standalone_chain =
|
34 |
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
|
42 |
# TODO: use input_to_rag_chain, rag_prompt_formatted,
|
43 |
# HistoryInput and the LLM to build the rag_chain.
|
44 |
-
rag_chain =
|
45 |
|
46 |
# TODO: Implement the filtered_rag_chain. It should be the
|
47 |
# same as the rag_chain but with hybrid_search = True.
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
|
51 |
|
|
|
6 |
raw_prompt,
|
7 |
raw_prompt_formatted,
|
8 |
history_prompt_formatted,
|
9 |
+
standalone_prompt_formatted,
|
10 |
format_context,
|
11 |
+
rag_prompt_formatted,
|
12 |
tokenizer
|
13 |
)
|
14 |
from app.data_indexing import DataIndexer
|
|
|
32 |
history_chain = (history_prompt_formatted | llm).with_types(input_type=schemas.HistoryInput)
|
33 |
|
34 |
# TODO: Let's construct the standalone_chain by piping standalone_prompt_formatted with the LLM
|
35 |
+
standalone_chain = (standalone_prompt_formatted | llm).with_types(input_type=schemas.HistoryInput)
|
36 |
|
37 |
+
input_1 = RunnablePassthrough.assign(new_question=standalone_chain)
|
38 |
+
input_2 = {
|
39 |
+
'context': lambda x: format_context(data_indexer.search(x['new_question'])),
|
40 |
+
'standalone_question': lambda x: x['new_question']
|
41 |
+
}
|
42 |
+
input_to_rag_chain = input_1 | input_2
|
43 |
|
44 |
# TODO: use input_to_rag_chain, rag_prompt_formatted,
|
45 |
# HistoryInput and the LLM to build the rag_chain.
|
46 |
+
rag_chain = (input_to_rag_chain | rag_prompt_formatted | llm).with_types(input_type=schemas.HistoryInput)
|
47 |
|
48 |
# TODO: Implement the filtered_rag_chain. It should be the
|
49 |
# same as the rag_chain but with hybrid_search = True.
|
50 |
+
|
51 |
+
input_1 = RunnablePassthrough.assign(new_question=standalone_chain)
|
52 |
+
input_2 = {
|
53 |
+
'context': lambda x: format_context(data_indexer.search(x['new_question'], hybrid_search=True)),
|
54 |
+
'standalone_question': lambda x: x['new_question']
|
55 |
+
}
|
56 |
+
filtered_input_to_rag_chain = input_1 | input_2
|
57 |
+
filtered_rag_chain = (filtered_input_to_rag_chain | rag_prompt_formatted | llm).with_types(input_type=schemas.HistoryInput)
|
58 |
|
59 |
|
60 |
|
app/code_data/langchain_repo
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
Subproject commit 82b5b77940e97f65179efa0268031c47d0584a1c
|
app/data_indexing.py
CHANGED
@@ -38,6 +38,7 @@ class DataIndexer:
|
|
38 |
)
|
39 |
|
40 |
self.index = self.pinecone_client.Index(self.index_name)
|
|
|
41 |
# TODO: make sure to build the index.
|
42 |
self.source_index = self.get_source_index()
|
43 |
|
@@ -75,14 +76,19 @@ class DataIndexer:
|
|
75 |
# values = self.embedding_client.feature_extraction([
|
76 |
# doc.page_content for doc in batch
|
77 |
# ])
|
78 |
-
values =
|
|
|
|
|
79 |
|
80 |
# TODO: create a list of unique identifiers for each element in the batch with the uuid package.
|
81 |
-
vector_ids =
|
82 |
|
83 |
# TODO: create a list of dictionaries representing the metadata. Capture the text data
|
84 |
# with the "text" key, and make sure to capture the rest of the doc.metadata.
|
85 |
-
metadatas =
|
|
|
|
|
|
|
86 |
|
87 |
# create a list of dictionaries with keys "id" (the unique identifiers), "values"
|
88 |
# (the vector representation), and "metadata" (the metadata).
|
@@ -94,7 +100,7 @@ class DataIndexer:
|
|
94 |
|
95 |
try:
|
96 |
# TODO: Use the function upsert to upload the data to the database.
|
97 |
-
upsert_response =
|
98 |
print(upsert_response)
|
99 |
except Exception as e:
|
100 |
print(e)
|
@@ -111,17 +117,20 @@ class DataIndexer:
|
|
111 |
# TODO: embed the text_query by using the embedding model
|
112 |
# TODO: choose your embedding model
|
113 |
# vector = self.embedding_client.feature_extraction(text_query)
|
114 |
-
|
115 |
-
vector = None
|
116 |
-
|
117 |
# TODO: use the vector representation of the text_query to
|
118 |
# search the database by using the query function.
|
119 |
-
result =
|
|
|
|
|
|
|
|
|
120 |
|
121 |
docs = []
|
122 |
for res in result["matches"]:
|
123 |
# TODO: From the result's metadata, extract the "text" element.
|
124 |
-
|
|
|
125 |
|
126 |
return docs
|
127 |
|
|
|
38 |
)
|
39 |
|
40 |
self.index = self.pinecone_client.Index(self.index_name)
|
41 |
+
print(self.index.query(namespace=''))
|
42 |
# TODO: make sure to build the index.
|
43 |
self.source_index = self.get_source_index()
|
44 |
|
|
|
76 |
# values = self.embedding_client.feature_extraction([
|
77 |
# doc.page_content for doc in batch
|
78 |
# ])
|
79 |
+
values = self.embedding_client.embed_documents([
|
80 |
+
doc.page_content for doc in batch
|
81 |
+
])
|
82 |
|
83 |
# TODO: create a list of unique identifiers for each element in the batch with the uuid package.
|
84 |
+
vector_ids = [str(uuid.uuid4()) for _ in batch]
|
85 |
|
86 |
# TODO: create a list of dictionaries representing the metadata. Capture the text data
|
87 |
# with the "text" key, and make sure to capture the rest of the doc.metadata.
|
88 |
+
metadatas = [{
|
89 |
+
'text': doc.page_content,
|
90 |
+
**doc.metadata
|
91 |
+
} for doc in batch]
|
92 |
|
93 |
# create a list of dictionaries with keys "id" (the unique identifiers), "values"
|
94 |
# (the vector representation), and "metadata" (the metadata).
|
|
|
100 |
|
101 |
try:
|
102 |
# TODO: Use the function upsert to upload the data to the database.
|
103 |
+
upsert_response = self.index.upsert(vectors=vectors)
|
104 |
print(upsert_response)
|
105 |
except Exception as e:
|
106 |
print(e)
|
|
|
117 |
# TODO: embed the text_query by using the embedding model
|
118 |
# TODO: choose your embedding model
|
119 |
# vector = self.embedding_client.feature_extraction(text_query)
|
120 |
+
vector = self.embedding_client.embed_query(text_query)
|
|
|
|
|
121 |
# TODO: use the vector representation of the text_query to
|
122 |
# search the database by using the query function.
|
123 |
+
result = self.index.query(vector,
|
124 |
+
top_k=top_k,
|
125 |
+
filter=filter, # type: ignore
|
126 |
+
include_values=True,
|
127 |
+
include_metadata=True)
|
128 |
|
129 |
docs = []
|
130 |
for res in result["matches"]:
|
131 |
# TODO: From the result's metadata, extract the "text" element.
|
132 |
+
# print(res.metadata)
|
133 |
+
docs.append(res.metadata['text'])
|
134 |
|
135 |
return docs
|
136 |
|
app/main.py
CHANGED
@@ -6,7 +6,7 @@ from langserve.serialization import WellKnownLCSerializer
|
|
6 |
from typing import List
|
7 |
from sqlalchemy.orm import Session
|
8 |
|
9 |
-
from app.chains import simple_chain, formatted_chain, history_chain
|
10 |
import app.crud as crud
|
11 |
import app.models as models
|
12 |
import app.schemas as schemas
|
@@ -64,7 +64,7 @@ async def history_stream(request: Request, db: Session = Depends(get_db)):
|
|
64 |
chat_history_str = format_chat_history(chat_history)
|
65 |
crud.add_message(db, schemas.MessageBase(message=user_request.question, type="user"), user_name)
|
66 |
history_input = schemas.HistoryInput(chat_history=chat_history_str, question=user_request.question)
|
67 |
-
print(history_input)
|
68 |
return EventSourceResponse(generate_stream(history_input, history_chain, [LogResponseCallback(user_request, db)]))
|
69 |
|
70 |
|
@@ -77,7 +77,14 @@ async def rag_stream(request: Request, db: Session = Depends(get_db)):
|
|
77 |
# - We add as part of the user history the current question by using add_message.
|
78 |
# - We create an instance of HistoryInput by using format_chat_history.
|
79 |
# - We use the history input within the rag chain.
|
80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
|
82 |
|
83 |
@app.post("/filtered_rag/stream")
|
|
|
6 |
from typing import List
|
7 |
from sqlalchemy.orm import Session
|
8 |
|
9 |
+
from app.chains import simple_chain, formatted_chain, history_chain, rag_chain
|
10 |
import app.crud as crud
|
11 |
import app.models as models
|
12 |
import app.schemas as schemas
|
|
|
64 |
chat_history_str = format_chat_history(chat_history)
|
65 |
crud.add_message(db, schemas.MessageBase(message=user_request.question, type="user"), user_name)
|
66 |
history_input = schemas.HistoryInput(chat_history=chat_history_str, question=user_request.question)
|
67 |
+
# print(history_input)
|
68 |
return EventSourceResponse(generate_stream(history_input, history_chain, [LogResponseCallback(user_request, db)]))
|
69 |
|
70 |
|
|
|
77 |
# - We add as part of the user history the current question by using add_message.
|
78 |
# - We create an instance of HistoryInput by using format_chat_history.
|
79 |
# - We use the history input within the rag chain.
|
80 |
+
data = await request.json()
|
81 |
+
user_request = schemas.UserRequest(**data['input'])
|
82 |
+
user_name = user_request.username
|
83 |
+
chat_history = crud.get_user_chat_history(db, user_name)
|
84 |
+
chat_history_str = format_chat_history(chat_history)
|
85 |
+
crud.add_message(db, schemas.MessageBase(message=user_request.question, type="user"), user_name)
|
86 |
+
history_input = schemas.HistoryInput(chat_history=chat_history_str, question=user_request.question)
|
87 |
+
return EventSourceResponse(generate_stream(history_input, rag_chain, [LogResponseCallback(user_request, db)]))
|
88 |
|
89 |
|
90 |
@app.post("/filtered_rag/stream")
|
app/prompts.py
CHANGED
@@ -30,7 +30,10 @@ def format_context(docs: List[str]):
|
|
30 |
# so we need to concatenate that list into a text that can fit into
|
31 |
# the rag_prompt_formatted. Implement format_context that takes a
|
32 |
# like of strings and returns the context as one string.
|
33 |
-
|
|
|
|
|
|
|
34 |
|
35 |
raw_prompt = "{question}"
|
36 |
|
@@ -44,11 +47,20 @@ helpful answer:"""
|
|
44 |
|
45 |
# TODO: Create the standalone_prompt prompt that will capture the question and the chat history
|
46 |
# to generate a standalone question. It needs a {chat_history} placeholder and a {question} placeholder,
|
47 |
-
standalone_prompt: str =
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
|
49 |
# TODO: Create the rag_prompt that will capture the context and the standalone question to generate
|
50 |
# a final answer to the question.
|
51 |
-
rag_prompt: str =
|
|
|
|
|
|
|
52 |
|
53 |
# TODO: create raw_prompt_formatted by using format_prompt
|
54 |
raw_prompt_formatted = format_prompt(raw_prompt)
|
|
|
30 |
# so we need to concatenate that list into a text that can fit into
|
31 |
# the rag_prompt_formatted. Implement format_context that takes a
|
32 |
# like of strings and returns the context as one string.
|
33 |
+
context = ""
|
34 |
+
for doc in docs:
|
35 |
+
context += f"{doc}\n"
|
36 |
+
return context
|
37 |
|
38 |
raw_prompt = "{question}"
|
39 |
|
|
|
47 |
|
48 |
# TODO: Create the standalone_prompt prompt that will capture the question and the chat history
|
49 |
# to generate a standalone question. It needs a {chat_history} placeholder and a {question} placeholder,
|
50 |
+
standalone_prompt: str = """Given the following conversation and a follow up question, rephrase the
|
51 |
+
follow up question to be a standalone question, in its original language.
|
52 |
+
Chat History:
|
53 |
+
{chat_history}
|
54 |
+
Follow Up Input: {question}
|
55 |
+
Standalone question:
|
56 |
+
"""
|
57 |
|
58 |
# TODO: Create the rag_prompt that will capture the context and the standalone question to generate
|
59 |
# a final answer to the question.
|
60 |
+
rag_prompt: str = """Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.
|
61 |
+
{context}
|
62 |
+
Question: {question}
|
63 |
+
Helpful Answer:"""
|
64 |
|
65 |
# TODO: create raw_prompt_formatted by using format_prompt
|
66 |
raw_prompt_formatted = format_prompt(raw_prompt)
|