take the last question as history to understand the question
Browse files
    	
        climateqa/chat.py
    CHANGED
    
    | 
         @@ -101,6 +101,7 @@ async def chat_stream( 
     | 
|
| 101 | 
         
             
                audience_prompt = init_audience(audience)
         
     | 
| 102 | 
         
             
                sources = sources or ["IPCC", "IPBES"]
         
     | 
| 103 | 
         
             
                reports = reports or []
         
     | 
| 
         | 
|
| 104 | 
         | 
| 105 | 
         
             
                # Prepare inputs for agent
         
     | 
| 106 | 
         
             
                inputs = {
         
     | 
| 
         @@ -109,7 +110,8 @@ async def chat_stream( 
     | 
|
| 109 | 
         
             
                    "sources_input": sources,
         
     | 
| 110 | 
         
             
                    "relevant_content_sources_selection": relevant_content_sources_selection,
         
     | 
| 111 | 
         
             
                    "search_only": search_only,
         
     | 
| 112 | 
         
            -
                    "reports": reports
         
     | 
| 
         | 
|
| 113 | 
         
             
                }
         
     | 
| 114 | 
         | 
| 115 | 
         
             
                # Get streaming events from agent
         
     | 
| 
         | 
|
| 101 | 
         
             
                audience_prompt = init_audience(audience)
         
     | 
| 102 | 
         
             
                sources = sources or ["IPCC", "IPBES"]
         
     | 
| 103 | 
         
             
                reports = reports or []
         
     | 
| 104 | 
         
            +
                relevant_history_discussion = history[-2:] if len(history) > 1 else []
         
     | 
| 105 | 
         | 
| 106 | 
         
             
                # Prepare inputs for agent
         
     | 
| 107 | 
         
             
                inputs = {
         
     | 
| 
         | 
|
| 110 | 
         
             
                    "sources_input": sources,
         
     | 
| 111 | 
         
             
                    "relevant_content_sources_selection": relevant_content_sources_selection,
         
     | 
| 112 | 
         
             
                    "search_only": search_only,
         
     | 
| 113 | 
         
            +
                    "reports": reports,
         
     | 
| 114 | 
         
            +
                    "chat_history": relevant_history_discussion,
         
     | 
| 115 | 
         
             
                }
         
     | 
| 116 | 
         | 
| 117 | 
         
             
                # Get streaming events from agent
         
     | 
    	
        climateqa/engine/chains/answer_rag.py
    CHANGED
    
    | 
         @@ -65,6 +65,7 @@ def make_rag_node(llm,with_docs = True): 
     | 
|
| 65 | 
         
             
                async def answer_rag(state,config):
         
     | 
| 66 | 
         
             
                    print("---- Answer RAG ----")
         
     | 
| 67 | 
         
             
                    start_time = time.time()
         
     | 
| 
         | 
|
| 68 | 
         
             
                    print("Sources used : " +  "\n".join([x.metadata["short_name"] + " - page " + str(x.metadata["page_number"])  for x in state["documents"]]))
         
     | 
| 69 | 
         | 
| 70 | 
         
             
                    answer = await rag_chain.ainvoke(state,config)
         
     | 
| 
         @@ -73,9 +74,10 @@ def make_rag_node(llm,with_docs = True): 
     | 
|
| 73 | 
         
             
                    elapsed_time = end_time - start_time
         
     | 
| 74 | 
         
             
                    print("RAG elapsed time: ", elapsed_time)
         
     | 
| 75 | 
         
             
                    print("Answer size : ", len(answer))
         
     | 
| 76 | 
         
            -
                    # print(f"\n\nAnswer:\n{answer}")
         
     | 
| 77 | 
         | 
| 78 | 
         
            -
                     
     | 
| 
         | 
|
| 
         | 
|
| 79 | 
         | 
| 80 | 
         
             
                return answer_rag
         
     | 
| 81 | 
         | 
| 
         | 
|
| 65 | 
         
             
                async def answer_rag(state,config):
         
     | 
| 66 | 
         
             
                    print("---- Answer RAG ----")
         
     | 
| 67 | 
         
             
                    start_time = time.time()
         
     | 
| 68 | 
         
            +
                    chat_history = state.get("chat_history",[])
         
     | 
| 69 | 
         
             
                    print("Sources used : " +  "\n".join([x.metadata["short_name"] + " - page " + str(x.metadata["page_number"])  for x in state["documents"]]))
         
     | 
| 70 | 
         | 
| 71 | 
         
             
                    answer = await rag_chain.ainvoke(state,config)
         
     | 
| 
         | 
|
| 74 | 
         
             
                    elapsed_time = end_time - start_time
         
     | 
| 75 | 
         
             
                    print("RAG elapsed time: ", elapsed_time)
         
     | 
| 76 | 
         
             
                    print("Answer size : ", len(answer))
         
     | 
| 
         | 
|
| 77 | 
         | 
| 78 | 
         
            +
                    chat_history.append({"question":state["query"],"answer":answer})
         
     | 
| 79 | 
         
            +
                    
         
     | 
| 80 | 
         
            +
                    return {"answer":answer,"chat_history": chat_history}
         
     | 
| 81 | 
         | 
| 82 | 
         
             
                return answer_rag
         
     | 
| 83 | 
         | 
    	
        climateqa/engine/chains/standalone_question.py
    ADDED
    
    | 
         @@ -0,0 +1,39 @@ 
     | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
|
| 
         | 
| 
         | 
|
| 1 | 
         
            +
            from langchain.prompts import ChatPromptTemplate
         
     | 
| 2 | 
         
            +
             
     | 
| 3 | 
         
            +
            def make_standalone_question_chain(llm):
         
     | 
| 4 | 
         
            +
                prompt = ChatPromptTemplate.from_messages([
         
     | 
| 5 | 
         
            +
                    ("system", """You are a helpful assistant that transforms user questions into standalone questions 
         
     | 
| 6 | 
         
            +
                    by incorporating context from the chat history if needed. The output should be a self-contained 
         
     | 
| 7 | 
         
            +
                    question that can be understood without any additional context.
         
     | 
| 8 | 
         
            +
                    
         
     | 
| 9 | 
         
            +
                    Examples:
         
     | 
| 10 | 
         
            +
                    Chat History: "Let's talk about renewable energy"
         
     | 
| 11 | 
         
            +
                    User Input: "What about solar?"
         
     | 
| 12 | 
         
            +
                    Output: "What are the key aspects of solar energy as a renewable energy source?"
         
     | 
| 13 | 
         
            +
                    
         
     | 
| 14 | 
         
            +
                    Chat History: "What causes global warming?"
         
     | 
| 15 | 
         
            +
                    User Input: "And what are its effects?"
         
     | 
| 16 | 
         
            +
                    Output: "What are the effects of global warming on the environment and society?"
         
     | 
| 17 | 
         
            +
                    """),
         
     | 
| 18 | 
         
            +
                    ("user", """Chat History: {chat_history}
         
     | 
| 19 | 
         
            +
                    User Question: {question}
         
     | 
| 20 | 
         
            +
                    
         
     | 
| 21 | 
         
            +
                    Transform this into a standalone question:""")
         
     | 
| 22 | 
         
            +
                ])
         
     | 
| 23 | 
         
            +
                
         
     | 
| 24 | 
         
            +
                chain = prompt | llm
         
     | 
| 25 | 
         
            +
                return chain
         
     | 
| 26 | 
         
            +
             
     | 
| 27 | 
         
            +
            def make_standalone_question_node(llm):
         
     | 
| 28 | 
         
            +
                standalone_chain = make_standalone_question_chain(llm)
         
     | 
| 29 | 
         
            +
                
         
     | 
| 30 | 
         
            +
                def transform_to_standalone(state):
         
     | 
| 31 | 
         
            +
                    chat_history = state.get("chat_history", "")
         
     | 
| 32 | 
         
            +
                    output = standalone_chain.invoke({
         
     | 
| 33 | 
         
            +
                        "chat_history": chat_history,
         
     | 
| 34 | 
         
            +
                        "question": state["user_input"]
         
     | 
| 35 | 
         
            +
                    })
         
     | 
| 36 | 
         
            +
                    state["user_input"] = output.content
         
     | 
| 37 | 
         
            +
                    return state
         
     | 
| 38 | 
         
            +
                    
         
     | 
| 39 | 
         
            +
                return transform_to_standalone
         
     | 
    	
        climateqa/engine/graph.py
    CHANGED
    
    | 
         @@ -23,13 +23,14 @@ from .chains.retrieve_documents import make_IPx_retriever_node, make_POC_retriev 
     | 
|
| 23 | 
         
             
            from .chains.answer_rag import make_rag_node
         
     | 
| 24 | 
         
             
            from .chains.graph_retriever import make_graph_retriever_node
         
     | 
| 25 | 
         
             
            from .chains.chitchat_categorization import make_chitchat_intent_categorization_node
         
     | 
| 26 | 
         
            -
             
     | 
| 27 | 
         | 
| 28 | 
         
             
            class GraphState(TypedDict):
         
     | 
| 29 | 
         
             
                """
         
     | 
| 30 | 
         
             
                Represents the state of our graph.
         
     | 
| 31 | 
         
             
                """
         
     | 
| 32 | 
         
             
                user_input : str
         
     | 
| 
         | 
|
| 33 | 
         
             
                language : str
         
     | 
| 34 | 
         
             
                intent : str
         
     | 
| 35 | 
         
             
                search_graphs_chitchat : bool
         
     | 
| 
         @@ -128,6 +129,7 @@ def make_graph_agent(llm, vectorstore_ipcc, vectorstore_graphs, vectorstore_regi 
     | 
|
| 128 | 
         
             
                workflow = StateGraph(GraphState)
         
     | 
| 129 | 
         | 
| 130 | 
         
             
                # Define the node functions
         
     | 
| 
         | 
|
| 131 | 
         
             
                categorize_intent = make_intent_categorization_node(llm)
         
     | 
| 132 | 
         
             
                transform_query = make_query_transform_node(llm)
         
     | 
| 133 | 
         
             
                translate_query = make_translation_node(llm)
         
     | 
| 
         @@ -142,6 +144,7 @@ def make_graph_agent(llm, vectorstore_ipcc, vectorstore_graphs, vectorstore_regi 
     | 
|
| 142 | 
         | 
| 143 | 
         
             
                # Define the nodes
         
     | 
| 144 | 
         
             
                # workflow.add_node("set_defaults", set_defaults)
         
     | 
| 
         | 
|
| 145 | 
         
             
                workflow.add_node("categorize_intent", categorize_intent)
         
     | 
| 146 | 
         
             
                workflow.add_node("answer_climate", dummy)
         
     | 
| 147 | 
         
             
                workflow.add_node("answer_search", answer_search)
         
     | 
| 
         @@ -157,7 +160,7 @@ def make_graph_agent(llm, vectorstore_ipcc, vectorstore_graphs, vectorstore_regi 
     | 
|
| 157 | 
         
             
                workflow.add_node("answer_rag_no_docs", answer_rag_no_docs)
         
     | 
| 158 | 
         | 
| 159 | 
         
             
                # Entry point
         
     | 
| 160 | 
         
            -
                workflow.set_entry_point(" 
     | 
| 161 | 
         | 
| 162 | 
         
             
                # CONDITIONAL EDGES
         
     | 
| 163 | 
         
             
                workflow.add_conditional_edges(
         
     | 
| 
         @@ -190,6 +193,7 @@ def make_graph_agent(llm, vectorstore_ipcc, vectorstore_graphs, vectorstore_regi 
     | 
|
| 190 | 
         
             
                )
         
     | 
| 191 | 
         | 
| 192 | 
         
             
                # Define the edges
         
     | 
| 
         | 
|
| 193 | 
         
             
                workflow.add_edge("translate_query", "transform_query")
         
     | 
| 194 | 
         
             
                workflow.add_edge("transform_query", "retrieve_documents") #TODO put back
         
     | 
| 195 | 
         
             
                # workflow.add_edge("transform_query", "retrieve_local_data")
         
     | 
| 
         @@ -228,6 +232,8 @@ def make_graph_agent_poc(llm, vectorstore_ipcc, vectorstore_graphs, vectorstore_ 
     | 
|
| 228 | 
         
             
                workflow = StateGraph(GraphState)
         
     | 
| 229 | 
         | 
| 230 | 
         
             
                # Define the node functions
         
     | 
| 
         | 
|
| 
         | 
|
| 231 | 
         
             
                categorize_intent = make_intent_categorization_node(llm)
         
     | 
| 232 | 
         
             
                transform_query = make_query_transform_node(llm)
         
     | 
| 233 | 
         
             
                translate_query = make_translation_node(llm)
         
     | 
| 
         @@ -243,6 +249,7 @@ def make_graph_agent_poc(llm, vectorstore_ipcc, vectorstore_graphs, vectorstore_ 
     | 
|
| 243 | 
         | 
| 244 | 
         
             
                # Define the nodes
         
     | 
| 245 | 
         
             
                # workflow.add_node("set_defaults", set_defaults)
         
     | 
| 
         | 
|
| 246 | 
         
             
                workflow.add_node("categorize_intent", categorize_intent)
         
     | 
| 247 | 
         
             
                workflow.add_node("answer_climate", dummy)
         
     | 
| 248 | 
         
             
                workflow.add_node("answer_search", answer_search)
         
     | 
| 
         @@ -260,7 +267,7 @@ def make_graph_agent_poc(llm, vectorstore_ipcc, vectorstore_graphs, vectorstore_ 
     | 
|
| 260 | 
         
             
                workflow.add_node("answer_rag_no_docs", answer_rag_no_docs)
         
     | 
| 261 | 
         | 
| 262 | 
         
             
                # Entry point
         
     | 
| 263 | 
         
            -
                workflow.set_entry_point(" 
     | 
| 264 | 
         | 
| 265 | 
         
             
                # CONDITIONAL EDGES
         
     | 
| 266 | 
         
             
                workflow.add_conditional_edges(
         
     | 
| 
         @@ -293,6 +300,7 @@ def make_graph_agent_poc(llm, vectorstore_ipcc, vectorstore_graphs, vectorstore_ 
     | 
|
| 293 | 
         
             
                )
         
     | 
| 294 | 
         | 
| 295 | 
         
             
                # Define the edges
         
     | 
| 
         | 
|
| 296 | 
         
             
                workflow.add_edge("translate_query", "transform_query")
         
     | 
| 297 | 
         
             
                workflow.add_edge("transform_query", "retrieve_documents") #TODO put back
         
     | 
| 298 | 
         
             
                workflow.add_edge("transform_query", "retrieve_local_data")
         
     | 
| 
         | 
|
| 23 | 
         
             
            from .chains.answer_rag import make_rag_node
         
     | 
| 24 | 
         
             
            from .chains.graph_retriever import make_graph_retriever_node
         
     | 
| 25 | 
         
             
            from .chains.chitchat_categorization import make_chitchat_intent_categorization_node
         
     | 
| 26 | 
         
            +
            from .chains.standalone_question import make_standalone_question_node
         
     | 
| 27 | 
         | 
| 28 | 
         
             
            class GraphState(TypedDict):
         
     | 
| 29 | 
         
             
                """
         
     | 
| 30 | 
         
             
                Represents the state of our graph.
         
     | 
| 31 | 
         
             
                """
         
     | 
| 32 | 
         
             
                user_input : str
         
     | 
| 33 | 
         
            +
                chat_history : str
         
     | 
| 34 | 
         
             
                language : str
         
     | 
| 35 | 
         
             
                intent : str
         
     | 
| 36 | 
         
             
                search_graphs_chitchat : bool
         
     | 
| 
         | 
|
| 129 | 
         
             
                workflow = StateGraph(GraphState)
         
     | 
| 130 | 
         | 
| 131 | 
         
             
                # Define the node functions
         
     | 
| 132 | 
         
            +
                standalone_question_node = make_standalone_question_node(llm)
         
     | 
| 133 | 
         
             
                categorize_intent = make_intent_categorization_node(llm)
         
     | 
| 134 | 
         
             
                transform_query = make_query_transform_node(llm)
         
     | 
| 135 | 
         
             
                translate_query = make_translation_node(llm)
         
     | 
| 
         | 
|
| 144 | 
         | 
| 145 | 
         
             
                # Define the nodes
         
     | 
| 146 | 
         
             
                # workflow.add_node("set_defaults", set_defaults)
         
     | 
| 147 | 
         
            +
                workflow.add_node("standalone_question", standalone_question_node)
         
     | 
| 148 | 
         
             
                workflow.add_node("categorize_intent", categorize_intent)
         
     | 
| 149 | 
         
             
                workflow.add_node("answer_climate", dummy)
         
     | 
| 150 | 
         
             
                workflow.add_node("answer_search", answer_search)
         
     | 
| 
         | 
|
| 160 | 
         
             
                workflow.add_node("answer_rag_no_docs", answer_rag_no_docs)
         
     | 
| 161 | 
         | 
| 162 | 
         
             
                # Entry point
         
     | 
| 163 | 
         
            +
                workflow.set_entry_point("standalone_question")
         
     | 
| 164 | 
         | 
| 165 | 
         
             
                # CONDITIONAL EDGES
         
     | 
| 166 | 
         
             
                workflow.add_conditional_edges(
         
     | 
| 
         | 
|
| 193 | 
         
             
                )
         
     | 
| 194 | 
         | 
| 195 | 
         
             
                # Define the edges
         
     | 
| 196 | 
         
            +
                workflow.add_edge("standalone_question", "categorize_intent")
         
     | 
| 197 | 
         
             
                workflow.add_edge("translate_query", "transform_query")
         
     | 
| 198 | 
         
             
                workflow.add_edge("transform_query", "retrieve_documents") #TODO put back
         
     | 
| 199 | 
         
             
                # workflow.add_edge("transform_query", "retrieve_local_data")
         
     | 
| 
         | 
|
| 232 | 
         
             
                workflow = StateGraph(GraphState)
         
     | 
| 233 | 
         | 
| 234 | 
         
             
                # Define the node functions
         
     | 
| 235 | 
         
            +
                standalone_question_node = make_standalone_question_node(llm)
         
     | 
| 236 | 
         
            +
             
     | 
| 237 | 
         
             
                categorize_intent = make_intent_categorization_node(llm)
         
     | 
| 238 | 
         
             
                transform_query = make_query_transform_node(llm)
         
     | 
| 239 | 
         
             
                translate_query = make_translation_node(llm)
         
     | 
| 
         | 
|
| 249 | 
         | 
| 250 | 
         
             
                # Define the nodes
         
     | 
| 251 | 
         
             
                # workflow.add_node("set_defaults", set_defaults)
         
     | 
| 252 | 
         
            +
                workflow.add_node("standalone_question", standalone_question_node)
         
     | 
| 253 | 
         
             
                workflow.add_node("categorize_intent", categorize_intent)
         
     | 
| 254 | 
         
             
                workflow.add_node("answer_climate", dummy)
         
     | 
| 255 | 
         
             
                workflow.add_node("answer_search", answer_search)
         
     | 
| 
         | 
|
| 267 | 
         
             
                workflow.add_node("answer_rag_no_docs", answer_rag_no_docs)
         
     | 
| 268 | 
         | 
| 269 | 
         
             
                # Entry point
         
     | 
| 270 | 
         
            +
                workflow.set_entry_point("standalone_question")
         
     | 
| 271 | 
         | 
| 272 | 
         
             
                # CONDITIONAL EDGES
         
     | 
| 273 | 
         
             
                workflow.add_conditional_edges(
         
     | 
| 
         | 
|
| 300 | 
         
             
                )
         
     | 
| 301 | 
         | 
| 302 | 
         
             
                # Define the edges
         
     | 
| 303 | 
         
            +
                workflow.add_edge("standalone_question", "categorize_intent")
         
     | 
| 304 | 
         
             
                workflow.add_edge("translate_query", "transform_query")
         
     | 
| 305 | 
         
             
                workflow.add_edge("transform_query", "retrieve_documents") #TODO put back
         
     | 
| 306 | 
         
             
                workflow.add_edge("transform_query", "retrieve_local_data")
         
     |