Update utils.py
Browse files
utils.py
CHANGED
@@ -278,62 +278,94 @@ def document_storage_chroma(splits):
|
|
278 |
#HF embeddings--------------------------------------
|
279 |
#Chroma.from_documents(documents = splits, embedding = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2", model_kwargs={"device": "cpu"}, encode_kwargs={'normalize_embeddings': False}), persist_directory = PATH_WORK + CHROMA_DIR)
|
280 |
return vectorstore, retriever
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
281 |
|
|
|
|
|
282 |
|
283 |
-
|
284 |
-
|
285 |
-
def document_storage_mongodb(splits):
|
286 |
-
MongoDBAtlasVectorSearch.from_documents(documents = splits,
|
287 |
-
embedding = OpenAIEmbeddings(disallowed_special = ()),
|
288 |
-
collection = MONGODB_COLLECTION,
|
289 |
-
index_name = MONGODB_INDEX_NAME)
|
290 |
-
############################################
|
291 |
-
#dokumente in chroma db vektorisiert ablegen können - die Db vorbereiten daüfur
|
292 |
-
def document_retrieval_chroma(llm, prompt):
|
293 |
-
#OpenAI embeddings -------------------------------
|
294 |
-
embeddings = OpenAIEmbeddings()
|
295 |
|
296 |
-
#
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
|
302 |
-
#
|
303 |
-
|
304 |
-
return db
|
305 |
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
#embeddings = HuggingFaceInstructEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2", model_kwargs={"device": "cpu"})
|
316 |
-
#etwas weniger rechenaufwendig:
|
317 |
-
#embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2", model_kwargs={"device": "cpu"}, encode_kwargs={'normalize_embeddings': False})
|
318 |
-
#oder einfach ohne Langchain:
|
319 |
-
#embeddings = SentenceTransformerEmbeddings(model_name="all-MiniLM-L6-v2")
|
320 |
-
|
321 |
-
#ChromaDb um die embedings zu speichern
|
322 |
-
db = Chroma(embedding_function = embeddings, persist_directory = PATH_WORK + CHROMA_DIR)
|
323 |
-
print ("Chroma DB bereit ...................")
|
324 |
-
|
325 |
-
return db
|
326 |
-
|
327 |
-
###########################################
|
328 |
-
#dokumente in mongo db vektorisiert ablegen können - die Db vorbereiten daüfür
|
329 |
-
def document_retrieval_mongodb(llm, prompt):
|
330 |
-
db = MongoDBAtlasVectorSearch.from_connection_string(MONGODB_URI,
|
331 |
-
MONGODB_DB_NAME + "." + MONGODB_COLLECTION_NAME,
|
332 |
-
OpenAIEmbeddings(disallowed_special = ()),
|
333 |
-
index_name = MONGODB_INDEX_NAME)
|
334 |
-
return db
|
335 |
-
"""
|
336 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
337 |
|
338 |
|
339 |
###############################################
|
@@ -1120,7 +1152,7 @@ class GraphState(TypedDict):
|
|
1120 |
#Methoden, um den Graph und die Zustände umzusetzen
|
1121 |
### Nodes ###
|
1122 |
# die Knoten des Graphen definieren, die der Reihe noch (bzw. je nach Outcome des Vorgänger Knotens) durchlaufen werden
|
1123 |
-
def retrieve(state):
|
1124 |
"""
|
1125 |
Retrieve documents
|
1126 |
Args:
|
|
|
278 |
#HF embeddings--------------------------------------
|
279 |
#Chroma.from_documents(documents = splits, embedding = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2", model_kwargs={"device": "cpu"}, encode_kwargs={'normalize_embeddings': False}), persist_directory = PATH_WORK + CHROMA_DIR)
|
280 |
return vectorstore, retriever
|
281 |
+
|
282 |
+
#Dokumente, die vom Retriever rausgesucht wurden auf Relevanz untersuchen
|
283 |
+
def grade_documents_direct(state):
|
284 |
+
print("---CHECK RELEVANCE---")
|
285 |
+
# Data model
|
286 |
+
class grade(BaseModel):
|
287 |
+
"""Binary score for relevance check."""
|
288 |
+
binary_score: str = Field(description="Relevanz Bewertung 'ja' oder 'nein'")
|
289 |
|
290 |
+
# LLM
|
291 |
+
model = ChatOpenAI(temperature=0.3, model="gpt-4-0125-preview", streaming=True)
|
292 |
|
293 |
+
# Tool
|
294 |
+
grade_tool_oai = convert_to_openai_tool(grade)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
295 |
|
296 |
+
# LLM with tool and enforce invocation
|
297 |
+
llm_with_tool = model.bind(
|
298 |
+
tools=[convert_to_openai_tool(grade_tool_oai)],
|
299 |
+
tool_choice={"type": "function", "function": {"name": "grade"}},
|
300 |
+
)
|
301 |
|
302 |
+
# Parser
|
303 |
+
parser_tool = PydanticToolsParser(tools=[grade])
|
|
|
304 |
|
305 |
+
# Prompt
|
306 |
+
prompt = PromptTemplate(
|
307 |
+
template="""Du bist ein Bewerter, der die Relevanz von einem erhaltenen Dokument zu einer Nutzeranfrage bewerten soll. \n
|
308 |
+
Hier ist das erhaltene Dokument: \n\n {context} \n\n
|
309 |
+
Hier ist die Nutzeranfrage: {question} \n
|
310 |
+
Wenn das erhaltene Dokument Keywörter oder semantische Bedeutung in Bezug auf die Nutzeranfrage hat, bewerte es als relevant. \n
|
311 |
+
Gib eine binäre Bewertung von 'ja' oder 'nein' Bewertung, um anzuzeigen ob das Dokuemnt relevant ist zur Nutzeranfrage oder nicht.""",
|
312 |
+
input_variables=["context", "question"],
|
313 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
314 |
|
315 |
+
# Chain
|
316 |
+
chain = prompt | llm_with_tool | parser_tool
|
317 |
+
|
318 |
+
# Score
|
319 |
+
filtered_docs = []
|
320 |
+
anzahl_relevant = 0
|
321 |
+
search = "nein" # Default do not opt for re-questioning to supplement retrieval
|
322 |
+
for d in documents:
|
323 |
+
score = chain.invoke({"question": question, "context": d.page_content})
|
324 |
+
grade = score[0].binary_score
|
325 |
+
if grade == "ja":
|
326 |
+
#search = "nein" # mind. ein relevantes Dokument -> keine Websuche nötig
|
327 |
+
print("---Bewertung: Dokument ist relevant---")
|
328 |
+
anzahl_relevant = anzahl_relevant +1
|
329 |
+
filtered_docs.append(d)
|
330 |
+
else:
|
331 |
+
print("---Bewertung: Dokument irrelevant---")
|
332 |
+
search = "ja" # mind ein Dokument irrelevant -> Frage umformulieren
|
333 |
+
continue
|
334 |
+
#wenn mehrheit der Dokumente relevant -> generieren starten damit
|
335 |
+
if (anzahl_relevant>= len(documents)/2):
|
336 |
+
search = "nein"
|
337 |
+
print("second trial grade_docs:.....................")
|
338 |
+
print(second_trial)
|
339 |
+
return filtered_docs
|
340 |
+
|
341 |
+
|
342 |
+
def transform_query_direct(query):
|
343 |
+
print("---TRANSFORM QUERY---")
|
344 |
+
state_dict = state["keys"]
|
345 |
+
question = state_dict["question"]
|
346 |
+
documents = state_dict["documents"]
|
347 |
+
|
348 |
+
# Create a prompt template with format instructions and the query
|
349 |
+
prompt = PromptTemplate(
|
350 |
+
template="""Du generierst Fragen, die optimiert sind für das Retrieval von Dokumenten. \n
|
351 |
+
Schaue auf den input und versuche die zugrundeliegende Absicht / Bedeutung zu bewerten. \n
|
352 |
+
Hier ist die ursprüngliche Frage:
|
353 |
+
\n ------- \n
|
354 |
+
{question}
|
355 |
+
\n ------- \n
|
356 |
+
Formuliere eine verbesserte Frage: """,
|
357 |
+
input_variables=["question"],
|
358 |
+
)
|
359 |
+
|
360 |
+
# Grader
|
361 |
+
model = ChatOpenAI(temperature=0, model="gpt-4-0125-preview", streaming=True)
|
362 |
+
|
363 |
+
# Prompt
|
364 |
+
chain = prompt | model | StrOutputParser()
|
365 |
+
better_question = chain.invoke({"question": question})
|
366 |
+
second_trial="ja"
|
367 |
+
|
368 |
+
return {"keys": {"documents": documents, "question": better_question, "second_trial" : second_trial}}
|
369 |
|
370 |
|
371 |
###############################################
|
|
|
1152 |
#Methoden, um den Graph und die Zustände umzusetzen
|
1153 |
### Nodes ###
|
1154 |
# die Knoten des Graphen definieren, die der Reihe noch (bzw. je nach Outcome des Vorgänger Knotens) durchlaufen werden
|
1155 |
+
def retrieve(state, retriever):
|
1156 |
"""
|
1157 |
Retrieve documents
|
1158 |
Args:
|