Maurizio Dipierro commited on
Commit
cd65ba5
·
1 Parent(s): 38b9656

origin working

Browse files
Files changed (5) hide show
  1. app.py +4 -3
  2. document_handler.py +0 -2
  3. main.py +12 -5
  4. query_executor.py +82 -44
  5. vectorstore_handler.py +5 -6
app.py CHANGED
@@ -1,10 +1,12 @@
1
  import gradio as gr
2
  from huggingface_hub import InferenceClient
3
  from main import main
 
 
4
  """
5
  For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
6
  """
7
- client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
8
 
9
 
10
  def respond(
@@ -24,8 +26,7 @@ def respond(
24
  messages.append({"role": "assistant", "content": val[1]})
25
 
26
  messages.append({"role": "user", "content": message})
27
-
28
- response = main(' '.join(message))
29
 
30
  return response
31
 
 
1
  import gradio as gr
2
  from huggingface_hub import InferenceClient
3
  from main import main
4
+ from langchain_core.messages import BaseMessage
5
+
6
  """
7
  For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
8
  """
9
+ #client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
10
 
11
 
12
  def respond(
 
26
  messages.append({"role": "assistant", "content": val[1]})
27
 
28
  messages.append({"role": "user", "content": message})
29
+ response = main(messages,message)
 
30
 
31
  return response
32
 
document_handler.py CHANGED
@@ -2,8 +2,6 @@ import os
2
  import pickle
3
  from langchain_community.document_loaders.sitemap import SitemapLoader
4
 
5
- docs_file_path = 'sitemap_docs.pkl'
6
-
7
  def save_documents_to_disk(docs, file_path):
8
  """Save the documents to a file using pickle."""
9
  with open(file_path, 'wb') as file:
 
2
  import pickle
3
  from langchain_community.document_loaders.sitemap import SitemapLoader
4
 
 
 
5
  def save_documents_to_disk(docs, file_path):
6
  """Save the documents to a file using pickle."""
7
  with open(file_path, 'wb') as file:
main.py CHANGED
@@ -2,7 +2,8 @@ import argparse
2
  import logging
3
  from document_handler import load_documents_from_disk, load_documents_from_sitemap, save_documents_to_disk
4
  from vectorstore_handler import load_or_create_vectorstore, get_embeddings
5
- from query_executor import execute_query
 
6
 
7
  # Configure logging
8
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[
@@ -10,11 +11,16 @@ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(
10
  logging.StreamHandler()
11
  ])
12
 
13
- def main(query):
 
 
 
14
  # Path to save the documents
15
  sitemap_url = "https://www.originws.it/page-sitemap.xml"
16
- docs_file_path = 'sitemap_docs.pkl'
 
17
 
 
18
  # Try to load documents from disk
19
  docs = load_documents_from_disk(docs_file_path)
20
 
@@ -29,12 +35,13 @@ def main(query):
29
 
30
  # Get embeddings and load/create the vectorstore
31
  embeddings = get_embeddings()
32
- vectorstore = load_or_create_vectorstore(docs, embeddings)
33
 
34
  # Now that the vectorstore is ready, let's query it
35
  question = query
36
  logging.info(f"Executing query: {question}")
37
- response = execute_query(question, vectorstore)
 
38
 
39
  # Log the response
40
  logging.info(f"Query response: {response}")
 
2
  import logging
3
  from document_handler import load_documents_from_disk, load_documents_from_sitemap, save_documents_to_disk
4
  from vectorstore_handler import load_or_create_vectorstore, get_embeddings
5
+ from query_executor import QuestionAnsweringAssistant
6
+ import re
7
 
8
  # Configure logging
9
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[
 
11
  logging.StreamHandler()
12
  ])
13
 
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ def main(messages,query):
18
  # Path to save the documents
19
  sitemap_url = "https://www.originws.it/page-sitemap.xml"
20
+ sitemap_str = re.sub(r'[^a-zA-Z0-9]', '_', sitemap_url)
21
+ docs_file_path = sitemap_str+'.pkl'
22
 
23
+ qaa = QuestionAnsweringAssistant(logger)
24
  # Try to load documents from disk
25
  docs = load_documents_from_disk(docs_file_path)
26
 
 
35
 
36
  # Get embeddings and load/create the vectorstore
37
  embeddings = get_embeddings()
38
+ vectorstore = load_or_create_vectorstore(docs, embeddings, sitemap_str)
39
 
40
  # Now that the vectorstore is ready, let's query it
41
  question = query
42
  logging.info(f"Executing query: {question}")
43
+ condensed = qaa.condense_query(messages,question)
44
+ response = qaa.execute_query(condensed, vectorstore)
45
 
46
  # Log the response
47
  logging.info(f"Query response: {response}")
query_executor.py CHANGED
@@ -1,51 +1,89 @@
 
1
  from langchain_openai import ChatOpenAI
2
  from langchain_core.output_parsers import StrOutputParser
3
  from langchain_core.prompts import ChatPromptTemplate
4
  from langchain_core.runnables import RunnablePassthrough
5
  from langchain_anthropic import ChatAnthropic
6
 
 
 
 
 
7
 
8
- RAG_TEMPLATE = """
9
- You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise but friendly.
10
- If the question is about yourself, answer you're the digital assistant coach of OriginWS.
11
-
12
- <context>
13
- {context}
14
- </context>
15
-
16
- Answer the following question:
17
-
18
- {question}"""
19
-
20
- def format_docs(docs):
21
- """Format documents into a single string."""
22
- return "\n\n".join(doc.page_content for doc in docs)
23
-
24
- def execute_query(question, vectorstore):
25
- """Run the query against the vectorstore and return a response."""
26
- print(f"Searching for: {question}")
27
- docs = vectorstore.similarity_search(question, k=10)
28
- print(f"Found {len(docs)} relevant documents for the query.")
29
-
30
- # Set up the LLM and prompt handling
31
- llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
32
-
33
- #llm = ChatAnthropic(model="claude-3-5-sonnet-20241022",temperature=0,max_tokens=1024,timeout=None,max_retries=2,
34
- # api_key="...",
35
- # base_url="...",
36
- # other params...
37
- #)
38
- # Define the RAG prompt template
39
- rag_prompt = ChatPromptTemplate.from_template(RAG_TEMPLATE)
40
-
41
- # Create the chain
42
- chain = (
43
- RunnablePassthrough.assign(context=lambda input: format_docs(input["context"]))
44
- | rag_prompt
45
- | llm
46
- | StrOutputParser()
47
- )
48
-
49
- # Run the chain with the query
50
- response = chain.invoke({"context": docs, "question": question})
51
- return response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
  from langchain_openai import ChatOpenAI
3
  from langchain_core.output_parsers import StrOutputParser
4
  from langchain_core.prompts import ChatPromptTemplate
5
  from langchain_core.runnables import RunnablePassthrough
6
  from langchain_anthropic import ChatAnthropic
7
 
8
+ class QuestionAnsweringAssistant:
9
+ RAG_TEMPLATE = """
10
+ You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise but friendly.
11
+ If the question is about yourself, answer you're the digital assistant coach of OriginWS.
12
 
13
+ <context>
14
+ {context}
15
+ </context>
16
+
17
+ Answer the following question:
18
+
19
+ {question}"""
20
+
21
+ CONDENSE_PROMPT = """
22
+ Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question, in its original language.
23
+
24
+ Here's some example:
25
+
26
+ user: jungle up... di cosa si tratta?
27
+ assistant: Jungle Up è una nuova tipologia di allenamento. Combina tecniche di allenamento ispirate ai movimenti animali.
28
+ user: è possibile iscriversi?
29
+
30
+ Follow Up Input: è possibile iscriversi?
31
+
32
+ Standalone question: è possibile iscriversi al corso Jungle Up?
33
+ ----
34
+ Chat History:
35
+
36
+ {chat_history}
37
+
38
+ Follow Up Input: {question}
39
+
40
+ Standalone question:
41
+ """
42
+
43
+ def __init__(self, logger: logging.Logger, model_name="gpt-4o-mini", temperature=0):
44
+ self.logger = logger
45
+ self.llm = ChatOpenAI(model=model_name, temperature=temperature)
46
+ self.logger.info("QuestionAnsweringAssistant initialized with model: %s", model_name)
47
+
48
+ def format_docs(self, docs):
49
+ """Format documents into a single string."""
50
+ formatted_docs = "\n\n".join(doc.page_content for doc in docs)
51
+ self.logger.debug("Formatted documents for context: %s", formatted_docs)
52
+ return formatted_docs
53
+
54
+ def condense_query(self, messages, message):
55
+ """Rephrase the follow-up question to be a standalone question."""
56
+ self.logger.debug("Condensing query. History: %s, Current message: %s", messages, message)
57
+
58
+ # Format the chat history for the prompt
59
+ chat_history = "\n".join([f"{msg['role']}: {msg['content']}" for msg in messages])
60
+
61
+ # Use the prompt to rephrase the last user message
62
+ prompt_input = self.CONDENSE_PROMPT.format(chat_history=chat_history, question=message)
63
+ self.logger.info("Prompt condense: %s", prompt_input)
64
+ response = self.llm.invoke(prompt_input)
65
+
66
+ #self.logger.info("Condensed query response: %s", response)
67
+ return response.content
68
+
69
+ def execute_query(self, question, vectorstore):
70
+ """Run the query against the vectorstore and return a response."""
71
+ self.logger.info("Searching for condensed question: %s", question)
72
+ docs = vectorstore.similarity_search(question, k=10)
73
+ self.logger.info("Found %d relevant documents for the query.", len(docs))
74
+
75
+ # Define the RAG prompt template
76
+ rag_prompt = ChatPromptTemplate.from_template(self.RAG_TEMPLATE)
77
+
78
+ # Create the chain
79
+ chain = (
80
+ RunnablePassthrough.assign(context=lambda input: self.format_docs(input["context"]))
81
+ | rag_prompt
82
+ | self.llm
83
+ | StrOutputParser()
84
+ )
85
+
86
+ # Run the chain with the query
87
+ response = chain.invoke({"context": docs, "question": question})
88
+ #self.logger.info("Query executed successfully. Response: %s", response)
89
+ return response
vectorstore_handler.py CHANGED
@@ -3,17 +3,16 @@ from langchain_text_splitters import RecursiveCharacterTextSplitter
3
  from langchain_openai import OpenAIEmbeddings
4
  from langchain_chroma import Chroma
5
 
6
- chroma_db_dir = 'chroma_vectorstore'
7
 
8
  def get_embeddings():
9
  """Initialize and return OpenAI embeddings."""
10
  return OpenAIEmbeddings(model="text-embedding-3-large")
11
 
12
- def load_or_create_vectorstore(docs, embeddings):
13
  """Load or create a Chroma vectorstore."""
14
- if os.path.exists(chroma_db_dir):
15
  print("Loading existing Chroma vector store from disk...")
16
- return Chroma(persist_directory=chroma_db_dir, embedding_function=embeddings)
17
 
18
  # Split documents if vectorstore doesn't exist
19
  text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
@@ -22,6 +21,6 @@ def load_or_create_vectorstore(docs, embeddings):
22
 
23
  # Create new vectorstore
24
  print("Creating new Chroma vector store...")
25
- vectorstore = Chroma.from_documents(documents=all_splits, embedding=embeddings, persist_directory=chroma_db_dir)
26
- print(f"Vectorstore created and saved to {chroma_db_dir}")
27
  return vectorstore
 
3
  from langchain_openai import OpenAIEmbeddings
4
  from langchain_chroma import Chroma
5
 
 
6
 
7
  def get_embeddings():
8
  """Initialize and return OpenAI embeddings."""
9
  return OpenAIEmbeddings(model="text-embedding-3-large")
10
 
11
+ def load_or_create_vectorstore(docs, embeddings,path):
12
  """Load or create a Chroma vectorstore."""
13
+ if os.path.exists(path):
14
  print("Loading existing Chroma vector store from disk...")
15
+ return Chroma(persist_directory=path, embedding_function=embeddings)
16
 
17
  # Split documents if vectorstore doesn't exist
18
  text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=0)
 
21
 
22
  # Create new vectorstore
23
  print("Creating new Chroma vector store...")
24
+ vectorstore = Chroma.from_documents(documents=all_splits, embedding=embeddings, persist_directory=path)
25
+ print(f"Vectorstore created and saved to {path}")
26
  return vectorstore