diff --git "a/sandbox/20240702 - CQA - Graph Functionality.ipynb" "b/sandbox/20240702 - CQA - Graph Functionality.ipynb" new file mode 100644--- /dev/null +++ "b/sandbox/20240702 - CQA - Graph Functionality.ipynb" @@ -0,0 +1,3417 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ClimateQ&A\n", + "---\n", + "Goal of the notebook: Recommended graphs functionality\n", + "\n", + "Inputs of the notebook:\n", + "\n", + "Output of the notebook:\n", + "\n", + "\n", + "Takeaways:\n", + "\n", + "Questions, thoughts and remarks:\n", + "- What do I put for query instruction ?\n", + " - Default is \"Represent this sentence for searching relevant passages:\"\n", + " - embedding_function = get_embeddings_function(query_instruction=\"\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dependencies and path\n", + "Adjust the argument in `sys.path.append` to align with your specific requirements." + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n" + ] + }, + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import pandas as pd \n", + "import numpy as np\n", + "import os\n", + "from IPython.display import display, Markdown\n", + "\n", + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "ROOT_DIR = os.path.dirname(os.getcwd())\n", + "\n", + "import sys\n", + "sys.path.append(\"/home/dora/climate-question-answering\")\n", + "sys.path.append(ROOT_DIR)\n", + "\n", + "from dotenv import load_dotenv\n", + "load_dotenv()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Import objects\n", + "### 1.1 LLM" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from climateqa.engine.llm import get_llm\n", + "llm = get_llm(provider=\"openai\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.2 Embedding" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading embeddings model: BAAI/bge-base-en-v1.5\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/tim/anaconda3/envs/climateqa/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], + "source": [ + "from climateqa.engine.embeddings import get_embeddings_function\n", + "\n", + "embeddings_function = get_embeddings_function()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.3 Reranker" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading FlashRankRanker model ms-marco-TinyBERT-L-2-v2\n", + "Loading model FlashRank model ms-marco-TinyBERT-L-2-v2...\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from climateqa.engine.reranker import get_reranker\n", + "\n", + "reranker = get_reranker(\"nano\")\n", + "reranker" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.4 IPCC vectorstore" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/tim/ai4s/climate_qa/climate-question-answering/climateqa/engine/vectorstore.py:38: LangChainDeprecationWarning: The class `Pinecone` was deprecated in LangChain 0.0.18 and will be removed in 0.3.0. An updated version of the class exists in the langchain-pinecone package and should be used instead. To use it run `pip install -U langchain-pinecone` and import as `from langchain_pinecone import Pinecone`.\n", + " vectorstore = PineconeVectorstore(\n" + ] + } + ], + "source": [ + "from climateqa.engine.vectorstore import get_pinecone_vectorstore\n", + "\n", + "vectorstore = get_pinecone_vectorstore(embeddings_function)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2 Vectorstore" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.1 IEA data" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
titlereturned_contentsourcesnotesappears_inappears_in_urldoc_idsource
0Capital requirements for mining to meet demand...https://www.iea.org/data-and-statistics/charts...IEA analysis based on data from S&P Global and...Capital requirements are calculated based on c...Global Critical Minerals Outlook 2024https://www.iea.org/reports/global-critical-mi...iea_0IEA
1IEA energy transition mineral price index, Jan...https://www.iea.org/data-and-statistics/charts...IEA analysis based on Bloomberg and S&P Global.IEA energy transition minerals price index is ...Global Critical Minerals Outlook 2024https://www.iea.org/reports/global-critical-mi...iea_1IEA
2Price developments of minerals and metals by c...https://www.iea.org/data-and-statistics/charts...IEA analysis based on Bloomberg and S&P Global.Base metals include iron, aluminium, zinc and ...Global Critical Minerals Outlook 2024https://www.iea.org/reports/global-critical-mi...iea_2IEA
3Capital expenditure on nonferrous metal produc...https://www.iea.org/data-and-statistics/charts...IEA analysis based on company annual reports a...For diversified majors, capex on the productio...Global Critical Minerals Outlook 2024https://www.iea.org/reports/global-critical-mi...iea_3IEA
4Selected environmental, social and governance ...https://www.iea.org/data-and-statistics/charts...IEA analysis based on the latest sustainabilit...GHG= greenhouse gas. Aggregated data for 25 ma...Global Critical Minerals Outlook 2024https://www.iea.org/reports/global-critical-mi...iea_4IEA
\n", + "
" + ], + "text/plain": [ + " title \\\n", + "0 Capital requirements for mining to meet demand... \n", + "1 IEA energy transition mineral price index, Jan... \n", + "2 Price developments of minerals and metals by c... \n", + "3 Capital expenditure on nonferrous metal produc... \n", + "4 Selected environmental, social and governance ... \n", + "\n", + " returned_content \\\n", + "0 https://www.iea.org/data-and-statistics/charts... \n", + "1 https://www.iea.org/data-and-statistics/charts... \n", + "2 https://www.iea.org/data-and-statistics/charts... \n", + "3 https://www.iea.org/data-and-statistics/charts... \n", + "4 https://www.iea.org/data-and-statistics/charts... \n", + "\n", + " sources \\\n", + "0 IEA analysis based on data from S&P Global and... \n", + "1 IEA analysis based on Bloomberg and S&P Global. \n", + "2 IEA analysis based on Bloomberg and S&P Global. \n", + "3 IEA analysis based on company annual reports a... \n", + "4 IEA analysis based on the latest sustainabilit... \n", + "\n", + " notes \\\n", + "0 Capital requirements are calculated based on c... \n", + "1 IEA energy transition minerals price index is ... \n", + "2 Base metals include iron, aluminium, zinc and ... \n", + "3 For diversified majors, capex on the productio... \n", + "4 GHG= greenhouse gas. Aggregated data for 25 ma... \n", + "\n", + " appears_in \\\n", + "0 Global Critical Minerals Outlook 2024 \n", + "1 Global Critical Minerals Outlook 2024 \n", + "2 Global Critical Minerals Outlook 2024 \n", + "3 Global Critical Minerals Outlook 2024 \n", + "4 Global Critical Minerals Outlook 2024 \n", + "\n", + " appears_in_url doc_id source \n", + "0 https://www.iea.org/reports/global-critical-mi... iea_0 IEA \n", + "1 https://www.iea.org/reports/global-critical-mi... iea_1 IEA \n", + "2 https://www.iea.org/reports/global-critical-mi... iea_2 IEA \n", + "3 https://www.iea.org/reports/global-critical-mi... iea_3 IEA \n", + "4 https://www.iea.org/reports/global-critical-mi... iea_4 IEA " + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from langchain_community.document_loaders import DataFrameLoader\n", + "from langchain_chroma import Chroma\n", + "\n", + "df_iea = pd.read_csv(f\"{ROOT_DIR}/data/charts_iea.csv\")\n", + "df_iea = df_iea.rename(columns={'url': 'returned_content'})\n", + "df_iea[\"doc_id\"] = \"iea_\" + df_iea.index.astype(str)\n", + "df_iea[\"source\"] = \"IEA\"\n", + "df_iea.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5355" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Load csv file of charts\n", + "loader_iea = DataFrameLoader(df_iea, page_content_column='title')\n", + "documents_iea = loader_iea.load()\n", + "len(documents_iea)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.2 OWID data" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
categorytitleurlreturned_contentsubtitledoc_idsource
0Access to EnergyNumber of people with and without access to cl...https://ourworldindata.org/grapher/number-with...<iframe src=\"https://ourworldindata.org/graphe...Clean cooking fuels and technologies represent...owid_0OWID
1Access to EnergyNumber of people without access to clean fuels...https://ourworldindata.org/grapher/number-with...<iframe src=\"https://ourworldindata.org/graphe...Clean cooking fuels and technologies represent...owid_1OWID
2Access to EnergyPeople without clean fuels for cooking, by wor...https://ourworldindata.org/grapher/people-with...<iframe src=\"https://ourworldindata.org/graphe...Data source: World Bankowid_2OWID
3Access to EnergyShare of the population without access to clea...https://ourworldindata.org/grapher/share-of-th...<iframe src=\"https://ourworldindata.org/graphe...Access to clean fuels or technologies such as ...owid_3OWID
4Access to EnergyShare with access to electricity vs. per capit...https://ourworldindata.org/grapher/share-with-...<iframe src=\"https://ourworldindata.org/graphe...Having access to electricity is defined in int...owid_4OWID
\n", + "
" + ], + "text/plain": [ + " category title \\\n", + "0 Access to Energy Number of people with and without access to cl... \n", + "1 Access to Energy Number of people without access to clean fuels... \n", + "2 Access to Energy People without clean fuels for cooking, by wor... \n", + "3 Access to Energy Share of the population without access to clea... \n", + "4 Access to Energy Share with access to electricity vs. per capit... \n", + "\n", + " url \\\n", + "0 https://ourworldindata.org/grapher/number-with... \n", + "1 https://ourworldindata.org/grapher/number-with... \n", + "2 https://ourworldindata.org/grapher/people-with... \n", + "3 https://ourworldindata.org/grapher/share-of-th... \n", + "4 https://ourworldindata.org/grapher/share-with-... \n", + "\n", + " returned_content \\\n", + "0 ', 'subtitle': 'Total area of forests, savannas, shrublands/grasslands, croplands, and other land that have been burned as a result of wildfires each year.', 'doc_id': 'owid_2201', 'source': 'OWID'}, page_content='Wildfire area burned by land cover type')" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "documents_all[-1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.4 Chroma vectorstore" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "# DO NOT RUN AGAIN (persisted)\n", + "# vectorstore_graphs = Chroma.from_documents(documents_all, embeddings_function, persist_directory=f\"{ROOT_DIR}/data/vectorstore\")\n", + "# vectorstore_graphs = Chroma.from_documents(documents_owid, embeddings_function, persist_directory=f\"{ROOT_DIR}/data/vectorstore_owid\")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:chromadb.telemetry.posthog:Anonymized telemetry enabled. See https://docs.trychroma.com/telemetry for more information.\n" + ] + } + ], + "source": [ + "from langchain_chroma import Chroma\n", + "\n", + "vectorstore_graphs = Chroma(persist_directory=f\"{ROOT_DIR}/data/vectorstore_owid\", embedding_function=embeddings_function)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(Document(metadata={'category': 'Water Use & Stress', 'doc_id': 'owid_2184', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Water quality is assessed by means of core physical and chemical parameters that reflect natural water quality. A water body is classified as \"good\" quality if at least 80% of monitoring values meet target quality levels.', 'url': 'https://ourworldindata.org/grapher/water-bodies-good-water-quality'}, page_content='Share of water bodies with good ambient water quality'),\n", + " 0.46955257728383504),\n", + " (Document(metadata={'category': 'Clean Water & Sanitation', 'doc_id': 'owid_742', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Water quality is assessed by means of core physical and chemical parameters that reflect natural water quality. A water body is classified as \"good\" quality if at least 80% of monitoring values meet target quality levels.', 'url': 'https://ourworldindata.org/grapher/water-bodies-good-water-quality'}, page_content='Share of water bodies with good ambient water quality'),\n", + " 0.46955245084328956),\n", + " (Document(metadata={'category': 'Water Pollution', 'doc_id': 'owid_2151', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Water quality is assessed by means of core physical and chemical parameters that reflect natural water quality. A water body is classified as \"good\" quality if at least 80% of monitoring values meet target quality levels.', 'url': 'https://ourworldindata.org/grapher/water-bodies-good-water-quality'}, page_content='Share of water bodies with good ambient water quality'),\n", + " 0.46955245084328956),\n", + " (Document(metadata={'category': 'Clean Water & Sanitation', 'doc_id': 'owid_719', 'returned_content': '', 'source': 'OWID', 'subtitle': 'A basic drinking water service is water from an improved water source that can be collected within a 30-minute round trip, including queuing.', 'url': 'https://ourworldindata.org/grapher/population-using-at-least-basic-drinking-water'}, page_content='Share of population using at least a basic drinking water source'),\n", + " 0.43011969078910306)]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vectorstore_graphs.similarity_search_with_relevance_scores(\"What is the trend of clean water?\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Retriever for recommended graphs" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3.1 Custom retriever" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.retrievers import BaseRetriever\n", + "from langchain_core.documents.base import Document\n", + "from langchain_core.vectorstores import VectorStore\n", + "from langchain_core.callbacks.manager import CallbackManagerForRetrieverRun\n", + "\n", + "from typing import List\n", + "\n", + "class GraphRetriever(BaseRetriever):\n", + " vectorstore:VectorStore\n", + " sources:list = [\"IEA\", \"OWID\"] # plus tard ajouter OurWorldInData # faudra integrate avec l'autre retriever\n", + " threshold:float = 0.5\n", + " k_total:int = 10\n", + "\n", + " def _get_relevant_documents(\n", + " self, query: str, *, run_manager: CallbackManagerForRetrieverRun\n", + " ) -> List[Document]:\n", + "\n", + " # Check if all elements in the list are IEA or OWID\n", + " assert isinstance(self.sources,list)\n", + " assert any([x in [\"IEA\", \"OWID\"] for x in self.sources])\n", + "\n", + " # Prepare base search kwargs\n", + " filters = {}\n", + "\n", + " filters[\"source\"] = {\"$in\": self.sources}\n", + "\n", + " docs = self.vectorstore.similarity_search_with_score(query=query, filter=filters, k=self.k_total)\n", + " \n", + " # Filter if scores are below threshold\n", + " docs = [x for x in docs if x[1] > self.threshold]\n", + "\n", + " # Add score to metadata\n", + " results = []\n", + " for i,(doc,score) in enumerate(docs):\n", + " doc.metadata[\"similarity_score\"] = score\n", + " doc.metadata[\"content\"] = doc.page_content\n", + " results.append(doc)\n", + "\n", + " return results" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "retriever = GraphRetriever(vectorstore=vectorstore_graphs)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Document(metadata={'category': 'Energy', 'doc_id': 'owid_969', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Energy trade, measured as the percentage of energy use. Positive values indicate a country or region is a net importer of energy. Negative numbers indicate a country or region is a net exporter.', 'url': 'https://ourworldindata.org/grapher/energy-imports-and-exports-energy-use', 'similarity_score': 0.7722029089927673, 'content': 'Energy imports and exports'}, page_content='Energy imports and exports'),\n", + " Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_400', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Environmentally sound technologies (ESTs) are technologies that have the potential for significantly improved environmental performance relative to other technologies. This indicator shows the value of imported ESTs in current US-$.', 'url': 'https://ourworldindata.org/grapher/import-of-environmentally-sound-technologies', 'similarity_score': 0.782991886138916, 'content': 'Import of environmentally sound technologies'}, page_content='Import of environmentally sound technologies'),\n", + " Document(metadata={'category': 'Energy', 'doc_id': 'owid_1013', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Share of primary energy by source over the long-term, measured as the percentage of total energy consumption. Primary electricity includes: hydropower, nuclear power, wind, photo\\xadvoltaics, tidal, wave and solar thermal and geothermal (only figures for electricity production are included).', 'url': 'https://ourworldindata.org/grapher/long-term-energy-transitions', 'similarity_score': 0.8692131638526917, 'content': 'Long-term energy transitions'}, page_content='Long-term energy transitions'),\n", + " Document(metadata={'category': 'Forests & Deforestation', 'doc_id': 'owid_1376', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Imported deforestation is the amount of deforestation in other countries that is driven by the production of food and forestry products that are imported. This is measured in hectares.', 'url': 'https://ourworldindata.org/grapher/imported-deforestation', 'similarity_score': 0.8846064805984497, 'content': 'Imported deforestation'}, page_content='Imported deforestation'),\n", + " Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_401', 'returned_content': '', 'source': 'OWID', 'subtitle': 'This measures the net import-export balance in tonnes of CO₂ per capita. Positive values indicate net importers of CO₂. Negative values indicate net exporters of CO₂.', 'url': 'https://ourworldindata.org/grapher/imported-or-exported-co-emissions-per-capita', 'similarity_score': 0.8937123417854309, 'content': 'Imported or exported CO2 emissions per capita'}, page_content='Imported or exported CO2 emissions per capita'),\n", + " Document(metadata={'category': 'Energy', 'doc_id': 'owid_1019', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Net electricity imports are calculated as electricity imports minus exports. Countries with positive values are net importers of electricity; negative values are net exporters. Measured in terawatt-hours.', 'url': 'https://ourworldindata.org/grapher/net-electricity-imports', 'similarity_score': 0.8954001069068909, 'content': 'Net electricity imports'}, page_content='Net electricity imports'),\n", + " Document(metadata={'category': 'Energy', 'doc_id': 'owid_983', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Total fossil fuel production - differentiated by coal, oil and natural gas - by country over the long-run, measured in terawatt-hour (TWh) equivalents per year.', 'url': 'https://ourworldindata.org/grapher/fossil-fuel-production-over-the-long-term', 'similarity_score': 0.9086273312568665, 'content': 'Fossil fuel production over the long-term'}, page_content='Fossil fuel production over the long-term'),\n", + " Document(metadata={'category': 'Fossil Fuels', 'doc_id': 'owid_1443', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Total fossil fuel production - differentiated by coal, oil and natural gas - by country over the long-run, measured in terawatt-hour (TWh) equivalents per year.', 'url': 'https://ourworldindata.org/grapher/fossil-fuel-production-over-the-long-term', 'similarity_score': 0.9086273312568665, 'content': 'Fossil fuel production over the long-term'}, page_content='Fossil fuel production over the long-term'),\n", + " Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_379', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Environmentally sound technologies (ESTs) are technologies that have the potential for significantly improved environmental performance relative to other technologies. This indicator shows the value of exported ESTs in current US-$.', 'url': 'https://ourworldindata.org/grapher/export-of-environmentally-sound-technologies', 'similarity_score': 0.9094725847244263, 'content': 'Export of environmentally sound technologies'}, page_content='Export of environmentally sound technologies'),\n", + " Document(metadata={'category': 'Electricity Mix', 'doc_id': 'owid_892', 'returned_content': '', 'source': 'OWID', 'subtitle': \"Net electricity imports are calculated as electricity imports minus exports. This is given as a share of a country's electricity demand. Countries with positive values are net importers of electricity; negative values are net exporters.\", 'url': 'https://ourworldindata.org/grapher/electricity-imports-share-demand', 'similarity_score': 0.9217990636825562, 'content': 'Net electricity imports as a share of electricity demand'}, page_content='Net electricity imports as a share of electricity demand')]" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "retriever.invoke(\"hydrogen import evolutions\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3.2 Retriever node" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import os\n", + "from contextlib import contextmanager\n", + "\n", + "from climateqa.engine.reranker import rerank_docs\n", + "\n", + "\n", + "\n", + "def divide_into_parts(target, parts):\n", + " # Base value for each part\n", + " base = target // parts\n", + " # Remainder to distribute\n", + " remainder = target % parts\n", + " # List to hold the result\n", + " result = []\n", + " \n", + " for i in range(parts):\n", + " if i < remainder:\n", + " # These parts get base value + 1\n", + " result.append(base + 1)\n", + " else:\n", + " # The rest get the base value\n", + " result.append(base)\n", + " \n", + " return result\n", + "\n", + "\n", + "@contextmanager\n", + "def suppress_output():\n", + " # Open a null device\n", + " with open(os.devnull, 'w') as devnull:\n", + " # Store the original stdout and stderr\n", + " old_stdout = sys.stdout\n", + " old_stderr = sys.stderr\n", + " # Redirect stdout and stderr to the null device\n", + " sys.stdout = devnull\n", + " sys.stderr = devnull\n", + " try:\n", + " yield\n", + " finally:\n", + " # Restore stdout and stderr\n", + " sys.stdout = old_stdout\n", + " sys.stderr = old_stderr\n", + "\n", + "\n", + "def make_graph_retriever_node(vectorstore, reranker, rerank_by_question=True, k_final=15, k_before_reranking=100):\n", + "\n", + " def retrieve_graphs(state):\n", + " print(\"---- Retrieving graphs ----\")\n", + " \n", + " POSSIBLE_SOURCES = [\"IEA\", \"OWID\"]\n", + " questions = state[\"questions\"]\n", + " sources_input = state[\"sources_input\"]\n", + "\n", + " auto_mode = \"auto\" in sources_input\n", + "\n", + " # There are several options to get the final top k\n", + " # Option 1 - Get 100 documents by question and rerank by question\n", + " # Option 2 - Get 100/n documents by question and rerank the total\n", + " if rerank_by_question:\n", + " k_by_question = divide_into_parts(k_final,len(questions))\n", + " \n", + " docs = []\n", + " \n", + " for i,q in enumerate(questions):\n", + " \n", + " question = q[\"question\"]\n", + " \n", + " print(f\"Subquestion {i}: {question}\")\n", + " \n", + " # If auto mode, we use all sources\n", + " if auto_mode:\n", + " sources = POSSIBLE_SOURCES\n", + " # Otherwise, we use the config\n", + " else:\n", + " sources = sources_input\n", + "\n", + " if any([x in POSSIBLE_SOURCES for x in sources]):\n", + "\n", + " sources = [x for x in sources if x in POSSIBLE_SOURCES]\n", + " \n", + " # Search the document store using the retriever\n", + " retriever = GraphRetriever(\n", + " vectorstore = vectorstore,\n", + " sources = sources,\n", + " k_total = k_before_reranking,\n", + " threshold = 0.5,\n", + " )\n", + " docs_question = retriever.get_relevant_documents(question)\n", + " \n", + " # Rerank\n", + " if reranker is not None:\n", + " with suppress_output():\n", + " docs_question = rerank_docs(reranker,docs_question,question)\n", + " else:\n", + " # Add a default reranking score\n", + " for doc in docs_question:\n", + " doc.metadata[\"reranking_score\"] = doc.metadata[\"similarity_score\"]\n", + " \n", + " # If rerank by question we select the top documents for each question\n", + " if rerank_by_question:\n", + " docs_question = docs_question[:k_by_question[i]]\n", + " \n", + " # Add sources used in the metadata\n", + " for doc in docs_question:\n", + " doc.metadata[\"sources_used\"] = sources\n", + " \n", + " print(f\"{len(docs_question)} graphs retrieved for subquestion {i + 1}: {docs_question}\")\n", + " \n", + " # Add to the list of docs\n", + " docs.extend(docs_question)\n", + "\n", + " else:\n", + " print(f\"There are no graphs which match the sources filtered on. Sources filtered on: {sources}. Sources available: {POSSIBLE_SOURCES}.\")\n", + " \n", + " # Sorting the list in descending order by rerank_score\n", + " # Then select the top k\n", + " docs = sorted(docs, key=lambda x: x.metadata[\"reranking_score\"], reverse=True)\n", + " docs = docs[:k_final]\n", + "\n", + " return {\"recommended_content\": docs}\n", + " \n", + " return retrieve_graphs" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "# import sys\n", + "# import os\n", + "# from contextlib import contextmanager\n", + "\n", + "# from climateqa.engine.reranker import rerank_docs\n", + "\n", + "\n", + "# def divide_into_parts(target, parts):\n", + "# # Base value for each part\n", + "# base = target // parts\n", + "# # Remainder to distribute\n", + "# remainder = target % parts\n", + "# # List to hold the result\n", + "# result = []\n", + " \n", + "# for i in range(parts):\n", + "# if i < remainder:\n", + "# # These parts get base value + 1\n", + "# result.append(base + 1)\n", + "# else:\n", + "# # The rest get the base value\n", + "# result.append(base)\n", + " \n", + "# return result\n", + "\n", + "\n", + "# @contextmanager\n", + "# def suppress_output():\n", + "# # Open a null device\n", + "# with open(os.devnull, 'w') as devnull:\n", + "# # Store the original stdout and stderr\n", + "# old_stdout = sys.stdout\n", + "# old_stderr = sys.stderr\n", + "# # Redirect stdout and stderr to the null device\n", + "# sys.stdout = devnull\n", + "# sys.stderr = devnull\n", + "# try:\n", + "# yield\n", + "# finally:\n", + "# # Restore stdout and stderr\n", + "# sys.stdout = old_stdout\n", + "# sys.stderr = old_stderr\n", + "\n", + "\n", + "\n", + "# def make_retriever_node(vectorstore, reranker, rerank_by_question=True, k_final=15, k_before_reranking=100):\n", + "\n", + "# def retrieve_documents(state):\n", + " \n", + "# POSSIBLE_SOURCES = [\"IEA\",\"OWID\"]\n", + "# questions = state[\"questions\"]\n", + "# sources_input = state[\"sources_input\"]\n", + " \n", + "# # Sert à rien pour l'instant puisqu'on a des valeurs par défaut et qu'on fait pas de query transformation sur les sources de graphs\n", + "# # Use sources from the user input or from the LLM detection\n", + "# if \"sources_input\" not in state or state[\"sources_input\"] is None:\n", + "# sources_input = [\"auto\"]\n", + "# else:\n", + "# sources_input = state[\"sources_input\"]\n", + "# auto_mode = \"auto\" in sources_input\n", + "\n", + "# # There are several options to get the final top k\n", + "# # Option 1 - Get 100 documents by question and rerank by question\n", + "# # Option 2 - Get 100/n documents by question and rerank the total\n", + "# if rerank_by_question:\n", + "# k_by_question = divide_into_parts(k_final,len(questions))\n", + " \n", + "# docs = []\n", + " \n", + "# for i,q in enumerate(questions):\n", + " \n", + "# sources = q[\"sources\"]\n", + "# question = q[\"question\"]\n", + " \n", + "# # If auto mode, we use the sources detected by the LLM\n", + "# if auto_mode:\n", + "# sources = [x for x in sources if x in POSSIBLE_SOURCES]\n", + " \n", + "# # Otherwise, we use the config\n", + "# else:\n", + "# sources = sources_input\n", + " \n", + "# # Search the document store using the retriever\n", + "# # Configure high top k for further reranking step\n", + "# retriever = GraphRetriever(\n", + "# vectorstore=vectorstore,\n", + "# sources = sources,\n", + "# k_total = k_before_reranking,\n", + "# threshold = 0.5,\n", + "# )\n", + "# docs_question = retriever.get_relevant_documents(question)\n", + " \n", + "# # Rerank\n", + "# if reranker is not None:\n", + "# with suppress_output():\n", + "# docs_question = rerank_docs(reranker,docs_question,question)\n", + "# else:\n", + "# # Add a default reranking score\n", + "# for doc in docs_question:\n", + "# # doc.metadata[\"reranking_score\"] = doc.metadata[\"similarity_score\"]\n", + "# doc.metadata[\"reranking_score\"] = \"No reranking\"\n", + " \n", + "# # If rerank by question we select the top documents for each question\n", + "# if rerank_by_question:\n", + "# docs_question = docs_question[:k_by_question[i]]\n", + " \n", + "# # Add sources used in the metadata\n", + "# for doc in docs_question:\n", + "# doc.metadata[\"sources_used\"] = sources\n", + " \n", + "# # Add to the list of docs\n", + "# docs.extend(docs_question)\n", + " \n", + "# # Sorting the list in descending order by rerank_score\n", + "# # Then select the top k\n", + "# docs = sorted(docs, key=lambda x: x.metadata[\"reranking_score\"], reverse=True)\n", + "# docs = docs[:k_final]\n", + " \n", + "# new_state = {\"documents\": docs}\n", + "# return new_state\n", + " \n", + "# return retrieve_documents" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Node functions" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "from operator import itemgetter\n", + "\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "from langchain_core.output_parsers import StrOutputParser\n", + "from langchain_core.prompts.prompt import PromptTemplate\n", + "from langchain_core.prompts.base import format_document\n", + "\n", + "DEFAULT_DOCUMENT_PROMPT = PromptTemplate.from_template(template=\"\"\"Title: {page_content}. \\n\\n Embedding link: {returned_content}\"\"\")\n", + "\n", + "def _combine_recommended_content(\n", + " docs, document_prompt=DEFAULT_DOCUMENT_PROMPT, sep=\"\\n\\n-----------------\\n\\n\"\n", + "):\n", + "\n", + " doc_strings = []\n", + "\n", + " for i,doc in enumerate(docs):\n", + " # chunk_type = \"Doc\" if doc.metadata[\"chunk_type\"] == \"text\" else \"Image\"\n", + " chunk_type = \"Graph\"\n", + " if isinstance(doc,str):\n", + " doc_formatted = doc\n", + " else:\n", + " doc_formatted = format_document(doc, document_prompt)\n", + "\n", + " doc_string = f\"{chunk_type} {i+1}: \\n\\n\" + doc_formatted\n", + " # doc_string = doc_string.replace(\"\\n\",\" \") \n", + " doc_strings.append(doc_string)\n", + "\n", + " return sep.join(doc_strings)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "# display(Markdown(_combine_recommended_content(output[\"recommended_content\"])))" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.output_parsers import JsonOutputParser\n", + "from langchain_core.prompts import PromptTemplate\n", + "from langchain_core.pydantic_v1 import BaseModel, Field\n", + "from langchain_openai import ChatOpenAI\n", + "\n", + "from climateqa.engine.chains.prompts import answer_prompt_graph_template\n", + "\n", + "class RecommendedGraph(BaseModel):\n", + " title: str = Field(description=\"Title of the graph\")\n", + " embedding: str = Field(description=\"Embedding link of the graph\")\n", + "\n", + "# class RecommendedGraphs(BaseModel):\n", + "# recommended_content: List[RecommendedGraph] = Field(description=\"List of recommended graphs\")\n", + "\n", + "def make_rag_graph_chain(llm):\n", + " parser = JsonOutputParser(pydantic_object=RecommendedGraph)\n", + " prompt = PromptTemplate(\n", + " template=answer_prompt_graph_template,\n", + " input_variables=[\"query\", \"recommended_content\"],\n", + " partial_variables={\"format_instructions\": parser.get_format_instructions()},\n", + " )\n", + "\n", + " chain = prompt | llm | parser\n", + " return chain\n", + "\n", + "def make_rag_graph_node(llm):\n", + " chain = make_rag_graph_chain(llm)\n", + "\n", + " def answer_rag_graph(state):\n", + " output = chain.invoke(state)\n", + " return {\"graph_returned\": output}\n", + "\n", + " return answer_rag_graph" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Graph" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.1 Make graph agent" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import os\n", + "from contextlib import contextmanager\n", + "\n", + "from langchain.schema import Document\n", + "from langgraph.graph import END, StateGraph\n", + "from langchain_core.runnables.graph import MermaidDrawMethod\n", + "\n", + "from typing_extensions import TypedDict\n", + "from typing import List, Dict\n", + "\n", + "from IPython.display import display, HTML, Image\n", + "\n", + "from climateqa.engine.chains.answer_chitchat import make_chitchat_node\n", + "from climateqa.engine.chains.answer_ai_impact import make_ai_impact_node\n", + "from climateqa.engine.chains.query_transformation import make_query_transform_node\n", + "from climateqa.engine.chains.translation import make_translation_node\n", + "from climateqa.engine.chains.intent_categorization import make_intent_categorization_node\n", + "from climateqa.engine.chains.retriever import make_retriever_node\n", + "from climateqa.engine.chains.answer_rag import make_rag_node\n", + "from climateqa.engine.chains.set_defaults import set_defaults\n", + "from climateqa.engine.chains.graph_retriever import make_graph_retriever_node\n", + "\n", + "\n", + "class GraphState(TypedDict):\n", + " \"\"\"\n", + " Represents the state of our graph.\n", + " \"\"\"\n", + " user_input : str\n", + " language : str\n", + " intent : str\n", + " query: str\n", + " questions : List[dict]\n", + " answer: str\n", + " audience: str\n", + " sources_input: List[str]\n", + " documents: List[Document]\n", + " recommended_content : List[Document]\n", + " graph_returned: Dict[str,str]\n", + "\n", + "def search(state):\n", + " return {}\n", + "\n", + "def route_intent(state):\n", + " intent = state[\"intent\"]\n", + " if intent in [\"chitchat\",\"esg\"]:\n", + " return \"answer_chitchat\"\n", + " elif intent == \"ai_impact\":\n", + " return \"answer_ai_impact\"\n", + " else:\n", + " # Search route\n", + " return \"search\"\n", + " \n", + "def route_translation(state):\n", + " if state[\"language\"].lower() == \"english\":\n", + " return \"transform_query\"\n", + " else:\n", + " return \"translate_query\"\n", + " \n", + "def route_based_on_relevant_docs(state,threshold_docs=0.2):\n", + " docs = [x for x in state[\"documents\"] if x.metadata[\"reranking_score\"] > threshold_docs]\n", + " if len(docs) > 0:\n", + " return \"answer_rag\"\n", + " else:\n", + " return \"answer_rag_no_docs\"\n", + " \n", + "\n", + "def make_id_dict(values):\n", + " return {k:k for k in values}\n", + "\n", + "def make_graph_agent(llm, vectorstore_ipcc, vectorstore_graphs, reranker, threshold_docs=0.2):\n", + " \n", + " workflow = StateGraph(GraphState)\n", + "\n", + " # Define the node functions\n", + " categorize_intent = make_intent_categorization_node(llm)\n", + " transform_query = make_query_transform_node(llm)\n", + " translate_query = make_translation_node(llm)\n", + " answer_chitchat = make_chitchat_node(llm)\n", + " answer_ai_impact = make_ai_impact_node(llm)\n", + " retrieve_documents = make_retriever_node(vectorstore_ipcc, reranker)\n", + " retrieve_graphs = make_graph_retriever_node(vectorstore_graphs, reranker)\n", + " answer_rag_graph = make_rag_graph_node(llm)\n", + " answer_rag = make_rag_node(llm, with_docs=True)\n", + " answer_rag_no_docs = make_rag_node(llm, with_docs=False)\n", + "\n", + " # Define the nodes\n", + " workflow.add_node(\"set_defaults\", set_defaults)\n", + " workflow.add_node(\"categorize_intent\", categorize_intent)\n", + " workflow.add_node(\"search\", search)\n", + " workflow.add_node(\"transform_query\", transform_query)\n", + " workflow.add_node(\"translate_query\", translate_query)\n", + " workflow.add_node(\"answer_chitchat\", answer_chitchat)\n", + " workflow.add_node(\"answer_ai_impact\", answer_ai_impact)\n", + " workflow.add_node(\"retrieve_graphs\", retrieve_graphs)\n", + " workflow.add_node(\"answer_rag_graph\", answer_rag_graph)\n", + " workflow.add_node(\"retrieve_documents\", retrieve_documents)\n", + " workflow.add_node(\"answer_rag\", answer_rag)\n", + " workflow.add_node(\"answer_rag_no_docs\", answer_rag_no_docs)\n", + "\n", + " # Entry point\n", + " workflow.set_entry_point(\"set_defaults\")\n", + "\n", + " # CONDITIONAL EDGES\n", + " workflow.add_conditional_edges(\n", + " \"categorize_intent\",\n", + " route_intent,\n", + " make_id_dict([\"answer_chitchat\",\"answer_ai_impact\",\"search\"])\n", + " )\n", + "\n", + " workflow.add_conditional_edges(\n", + " \"search\",\n", + " route_translation,\n", + " make_id_dict([\"translate_query\",\"transform_query\"])\n", + " )\n", + "\n", + " workflow.add_conditional_edges(\n", + " \"retrieve_documents\",\n", + " lambda x : route_based_on_relevant_docs(x,threshold_docs=threshold_docs),\n", + " make_id_dict([\"answer_rag\",\"answer_rag_no_docs\"])\n", + " )\n", + "\n", + " # Define the edges\n", + " workflow.add_edge(\"set_defaults\", \"categorize_intent\")\n", + " workflow.add_edge(\"translate_query\", \"transform_query\")\n", + " workflow.add_edge(\"transform_query\", \"retrieve_graphs\")\n", + " workflow.add_edge(\"retrieve_graphs\", \"answer_rag_graph\")\n", + " workflow.add_edge(\"answer_rag_graph\", \"retrieve_documents\")\n", + " workflow.add_edge(\"answer_rag\", END)\n", + " workflow.add_edge(\"answer_rag_no_docs\", END)\n", + " workflow.add_edge(\"answer_chitchat\", END)\n", + " workflow.add_edge(\"answer_ai_impact\", END)\n", + "\n", + " # Compile\n", + " app = workflow.compile()\n", + " return app\n", + "\n", + "\n", + "\n", + "\n", + "def display_graph(app):\n", + "\n", + " display(\n", + " Image(\n", + " app.get_graph(xray = True).draw_mermaid_png(\n", + " draw_method=MermaidDrawMethod.API,\n", + " )\n", + " )\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Translate query ----\n" + ] + }, + { + "data": { + "image/jpeg": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "app = make_graph_agent(llm=llm, vectorstore_ipcc=vectorstore, vectorstore_graphs=vectorstore_graphs, reranker=reranker)\n", + "display_graph(app)" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "data": { + "text/plain": [ + "{'environment': True}" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from climateqa.engine.chains.chitchat_categorization import make_chitchat_intent_categorization_chain\n", + "\n", + "chain = make_chitchat_intent_categorization_chain(llm)\n", + "chain.invoke({\"input\": \"should i eat fish\"})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5.2 Testing graph agent" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Translate query ----\n" + ] + }, + { + "data": { + "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAOgAvkDASIAAhEBAxEB/8QAHQABAQADAAMBAQAAAAAAAAAAAAYEBQcBAwgCCf/EAF8QAAEEAQIDAwQMBw0FBAkDBQABAgMEBQYRBxIhExUxFCJBVggWFzJRVWGTlNLT1CM2QlRxldEkMzU3UlN0dYGSsrO0NENicrElc5GhCSYnRGOCosHDg6OkGEVXZfD/xAAbAQEBAAMBAQEAAAAAAAAAAAAAAQIDBAUGB//EADcRAQABAgIHBgUDAwUBAAAAAAABAhEDEhQxUVJhkdEEEyFBcZIzYqGxwTKB0gUVIiNCU7Lh8P/aAAwDAQACEQMRAD8A/qmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBzOXhwlF1mVkkzt0ZFBCiOkmkX3rGIqoiqq/CqInVVVERVTTJpSXUDe21JKtnnT+CoZFSpF18F2RFlX0Kr+i+hrd9jbTRExmqm0f/als28+osVVkWObJ04Xp4tksMaqf2Kp6vbVhPjih9KZ+0/MOj8DXbyxYTHRN+BlSNE/6H79q2F+KKH0Zn7DP/R4/RfB49tWE+OKH0pn7R7asJ8cUPpTP2nn2rYX4oofRmfsHtWwvxRQ+jM/YP9Hj9DwePbVhPjih9KZ+0e2rCfHFD6Uz9p59q2F+KKH0Zn7B7VsL8UUPozP2D/R4/Q8Hj21YT44ofSmftP3FqXETPRseVpSOXwa2wxV/6n59q2F+KKH0Zn7D8y6RwUzFZJhcfIxfFrqsaov/AJD/AEeP0TwbVFRURUXdFPJMromLE7zadmXCTIqu8mj605V/kvi8Gp8sfK75VTouzwWaTMQSpLA6nerv7OzUeu6xv+RfymqnVrvSi+CLuiY1URbNRN4+pbY2YANKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACY6ZfiC9j9nQ4eoySNq79J51e1XfBukbFRF+CV3wlOTGNb5HxBzUbt08tpVrEa7dF5FkY9N/k3j/vIb7JZKphsfZv37UNGjVjdNPasyJHFFG1N3Pe5VRGtREVVVeiIh0Y2umI1Wj7Xn63WWSCAb7IPha9yNbxK0g5yrsiJnqqqq/OHmL2QHC+xKyKLiRpGSR7ka1jM7VVXKvgiJ2nVTnROYX2R1XWWlc9nNN6S1Lbx9Khau0MlYpxMqZLsXKxUhcsyL1duqJJyKrWuVPA9XDPjtl9R8EMJrLL6H1HNkrNSo91PGVIZHXnyxtcs1ZjZ3bQ7uXZZXMVE8UQkNAcNNYJxDzctXSUvDXSOTxd2HJ4t2YivUrl6VydnYrQxqvYqidor12ZzcyJy7pualmhuJl/gNo3Rd7RVmFulbGOqZTHVM5XYmo6EMUkcjIZGyJyNVzYHqyVY+ZN2/DuHTLPsntLY/hxndYX8dnMfDgsjDispibNNrb9OeWSJjUdGj1RybTxv3Y527V83dehotdeyK1FgNS8PalHh1qRK+eyNuvYp2YKiXJo4qr5Wdii2ka1VciOXtFReWN6bI7ZF53W4Eaui0bxJxeP0FV01WzeosDmMXiad6s6KOCGet27FVHNa17G13SOT3qq/Zjnqdm45aY1Jcz3DzVWmcMmo7WmMtLZnxLbUdaSeGarNXcsb5FRnM1ZEds5U3RF6gdWryrPXikdE+Fz2o5YpNuZiqnguyqm6fIqnsOfJx60BRayvnNa6YwGZjajbuKu52ok1Obbz4X/hPfNdu1flQ/T/ZBcLo12fxJ0g1VRF2dnaqdFTdF/fPgUC/JjNbYnWODvs2amRV+MseO79mSTRKv/KrJET/AL1Tc4PPYzU2Kr5PD5GplsbYRXQ3KM7ZoZURVRVa9qqi9UVOi+KKafVbfLM/pWm3dXpefcfsm6JHHDIirv6PPkjT+06MD9Uxwn7SsKYAHOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA02osPNe8lvUFjZlqLlfXWZVRkiKmz4nqm6o1yenZeVUa7Z3LsvtxGep56OWJqOhtRptYoWURs0Kr6Ht3XovXZyKrXJ1aqoqKbQ1ea0zjdQdm67W55o02jsRSOimjT08sjFR7fBPBU8DdTVTVEU1+WqV9WX3bU/NYfm0/YEx1RF3SrCi/92hoF0O9qr2WpM9E3+Slpr9v7XsVf/M8e0if1pz3z8X2Rl3eHv8A0lbRtVIJb2kT+tOe+fi+yPzNoqwyJ7k1Tnt0aqp+Hi+yHd4e/wDSS0bVWDl3CvFZTWHDDR+eyOqcymQymHp3rPk80KR9rLAx7+X8Gvm7uXbqvT0lR7SJ/WnPfPxfZDu8Pf8ApJaNqhfQqyOVzq0LnKu6qrEVVPHdtT81h+bT9hP+0if1pz3z8X2R59o8qps/U2ee1fFPKWN/82xov/mO7w9/6Slo2tvlMxQ07UY+zI2Brl5IoY27vld48kbE6ucvwNRVMLA4yzJfsZrJRJDfssSGKtzI7yWBFVWsVUVUV6qvM9W9N9morkYjl92H0ljMJYdZggfLdcio65bmfPOqL4pzvVVRPkRUT5DcEmqmmJpo89cnoAA0IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeux/s8v/ACr/AND2Hrsf7PL/AMq/9AIfgErXcCeHCsVVaum8bsq+Kp5LH8q/9V/SXhB8A9/cK4c7q1V9reN3ViIjf9lj8OXpt+joXgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD12P9nl/wCVf+h7D12P9nl/5V/6AQvsf0ROA3DdEc16JprG+cxNkX9yx9UTZOn9hfED7H7b3BuG3Kqq32tY3ZVTZf8AZY/R6C+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlsxqu8uQno4OlXuS1lRtmxbndFFG5URUY3lY5Xu2VFVOiIip136GD35rD8xwf0qb7M6qezYkxE+EfvC2W4IjvzWH5jg/pU32Y781h+Y4P6VN9mZaLXtjnBZbgiO/NYfmOD+lTfZjvzWH5jg/pU32Y0WvbHOCy3BEd+aw/McH9Km+zHfmsPzHB/Spvsxote2OcFlucZ9lHx8v+x10NV1NFpJ+qMZJY8ltujveTOqq5PwblTs38zVVFRV6bLy+PN0r+/NYfmOD+lTfZk7xFwGd4naGzelczjcHLjcrWfWl2sy7s3969u8fvmuRHJ8rUGi17Y5wWQXsFOPU3GjhgzHppiXB0tKU6GIjuvspK289kKterWpGxGcqMYuyb/viJ026/Sxwvgdw5zPAjhti9IYaphrEFTmfNbknlbJZlcu7pHIke269E+RERPQXvfmsPzHB/Spvsxote2OcFluCI781h+Y4P6VN9mO/NYfmOD+lTfZjRa9sc4LLcER35rD8xwf0qb7Md+aw/McH9Km+zGi17Y5wWW4IjvzWH5jg/pU32Y781h+Y4P6VN9mNFr2xzgstwRHfmsPzHB/SpvszIpatydK1BHnqFWvXnkbCy3RnfI1kjlRGtka5jVaiqqIjkVU3VN9tyT2bEiLxaf3gsrwAciAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5/pdd7GoVXx73sdf7UQ3podLfv+of63s/9UN8exi/rWdYADUgDBZnMfLmpsQy7A/KQwNsyU2yIsrInOc1r3N8UaqtciKvjyr8BnAAAAANTp3VWL1XHfkxdlbLKN2bH2FWJ7OSeJ3LIzzkTfZfSm6L6FUg2wAKANTqrVWL0Tp+5m81ZWnjKjUdNOkT5ORFcjU81iK5eqp4IbYgAwVzmPbm2YdbsHer67raUu0TtVhRyNWTl8eXmcib+G6mcUADBTOY9c2uHS7AuVSultaSSJ2qQq7kSRW+KNVyKiL4KqL8CgZxPa+6aXsL6UlgVPkXtmFCT2vvxWs/97B/nMN2D8Wn1hlTrh0QAHjMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc+0t+/6h/rez/1Q3xodLfv+of63s/9UN8exi/rWdbgWHxWQ4zcTeIseU1dqHA1dM5KHF4/F4HIupdmzyeOVbMvL++rI6ReVH7tRGbbKQfshdV6gZb17qLRN7UscuimQpbuyagWtjYZ2xxyrEykkbks7se3n7Tl6v8ANcd71nwH0Lr/ADjsxm8EljJSQpXmsQWp6y2I08GTJE9qStTw2ejk26Hp1L7Hzh9rDLXsjmNOx3bF+JsVtjrMzYbCNZyMdJE16Rve1uyNerVc3ZNlTZNuaaZsjn+G0jUyvsvdQZOS/l4ZmaaxeQbBBlbEcLnLNYYrHRtejXR7MRezVFbzOcu27lVYDR68X+LeJsa1wV7yTKvy1hlft9VzQ06rIbTo/Jpca2o6NU5Gcqq56vdzc/Mm6In0dkuDWkMvmcDlrWLkdlMHDHWpXI7tiOVsUbkcxkjmyIszUc1HbScyb7r4qu+HLwC0FNrB2p+4Gx5h9tl974bU8cMllqorZnwNekTpEVEXnVirum++4yyPnrOZnUOpdb5Wj7YtVt17W1zDWi07SsWIcemGbPG5r3Nj2Yka107R0qqjld0367LuNTZPP57SPGXiC/WmbwmX0flchVxGPp3Viowspsa6Jktf3syzr1VZEVdpGo3bZDdaq9jrq/La+yWTwljEaZgt5RL7c1js1lWW4287XP3pdp5M97kRUVV2avMqq06pqLgHoHVmppM/ldPRW8lK+KSdVnmZDZfHt2bpoWvSOVW7Jsr2u8E+AxyyOc8Oq2U4l8Z9c3MvqDUFLH4xuEtVMJTyc1evDLJTZLIjmtcnM1V6LGvmru5XIqruknj3VavCPVV7UGqda2Xaf1dl8TiocdqO3Fdvu8p7GtVWRH80rlVrWt5lXl3cvhufTWL0jicLn83m6dTscnmnQuvz9o93bLEzs4/NVVa3ZvTzUTf07qR2ofY6aA1TVZWyOGsvhZlLOba2vlblfa7O7mlm3jlavMqqu3obuqNREVTLLI4jl8PxA0TW4YcNu/snl8xqFuQymWtWtTWKs0s0TInJUguqyaRkbEeq7MRFcke+6czt+3cD8BrfTeIy9PWNqOzF5bz4trsm/I2Ia6sbvHLYdDEsmz0eqKrd9nIiqu25+n+x40DNpdNPz4axcxrbneES28pbnsQWOVG88Vh8qyxrs1E8x6J4/Cu+Szh/lNFYalieHVnDYCgx8stlmZpWci+V71ReZH+Uxu335t1crlXdPDbqiJiRPeywluUOB+ayeOymSw+Qx01axBYxl2Sq/dZmRq1yxuRXMVsjt2r0Vdl26Ic+1tXzOe1F7IC43V+o8Yulq9e3h62PyckEFabuuOZXKxvR7Ve1FVjt2dXLy7uVTsa6GzescLk8HxDuYPUGEuMYnkuJx9mg7ma9HornrakVU3a3o3l8OqqnQ3MvDnTs8mq5H4/mfqmNsWYXt5P3U1IewRPfeZ+DTl8zl+Hx6iYv4jg+AwsevPZH6Oz2QyGWr3bmgK+XfHRylivG6VLMKqzkY9EWJebd0apyuXqqKpN4VeLnF6PUWqNPX3UcnXzdylR7XVUtarRSvOsbYZsc2o+OTzWorud6udz7ord0RPojN8FNGaibp5LuIcr8BClbHTQXJ4JYYkRqdmr43tc9uzG7teqou3Ux8hwD0Fk9XP1NPgGpmJLEduWSG1PFFNOxUVkskLHpG96KiLzOaq7p4kyyOI6x7/yNT2QGfTWGosdd0jKtrEVqOTkjq1pI8ZBOqLGnSRjnJsrH7t6uVGornKu9wunK+q/ZV1M3Zv5avam0Tjst2NTK2IYVk8qeixrG16NdF0RVjVFYqucqpu5VXtNnhjpq3T1bVlxvPBqtHJmWdvKnlXNA2BeqO3Z+Da1vmcvhv49TDznBzSGoslg8hexLlvYSJsFGzBbngkjiRWqkbnRvasjN2ovK/mTdPDqpcotCe19+K1n/AL2D/OYUJPa+/Faz/wB7B/nMOrB+LT6wyp1w6IADxmIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0t3WeEoTQRSZKB8s15uNbHAqyuSyqIvZORm6tVEVFXfbZF3XZD1QaluX5Wtp4G92Tbz6k0tzlro2NnjO1HLzPYq9G7J1236JsqhvwT1Stqe2+hLduY7HJHYlfZq04n2O2i8ImJK9W8qp4uXkXfwTbbdWP0XBWfip7uRyeYvY180kNq5bVqudLujueOLkifsi7N3Z5qeGyqqqE9pN7ZJtQOY5HN73spui7p75Dfmjj0lNoLtYNM4KCbByu7RmNoLHWWo7lRqtjYqtZyLy77IrdlVfFF83z3tn/U3J/Sqf257M2xP8qZjnEfeWUxduwaTvbP+puT+lU/tx3tn/U3J/Sqf25j3fzR7qepZuwaTvbP+puT+lU/tx3tn/U3J/Sqf247v5o91PUs3YNJ3tn/U3J/Sqf2472z/AKm5P6VT+3Hd/NHup6lm7BpO9s/6m5P6VT+3He2f9Tcn9Kp/bju/mj3U9Szdg0ne2f8AU3J/Sqf2472z/qbk/pVP7cd380e6nqWbsGk72z/qbk/pVP7cd7Z/1Nyf0qn9uO7+aPdT1LN2DSd7Z/1Nyf0qn9uO9s/6m5P6VT+3Hd/NHup6lm7BpO9s/wCpuT+lU/tx3tn/AFNyf0qn9uO7+aPdT1LN2TPEmJ8+jL8UUzq0j3RNbMxEV0arKzZyI5FRVTx6oqGX3tn/AFNyf0qn9uftmLy+qZIa9/FPw2NZLHNMtieN803I5Htja2Nzmoiq1OZyu8E2RF5t250Ww6orqqi0eOuJ+0kRabtw+jqio2Ra+Wx99rMckUUV2k6OSS4n++fKx/Kkbk8WNi3ReqO280S5nUNFs7ptOtvshoNnRMZdYsk9n8uBjZuzaifyXueiL6eUoweKxTljXNPHpadkKOUx7KtNl2aSSjJJG1rvFiPjRzXPavi1qqvp6p1Myrq/B3Lc1WHMUX24IY7M1byhqSxRSfvb3s35mtd6FVE3NuYeTw9DN056mRo1r9WdixSwWoWyMkYvi1zXIqKnyKBmAm73D3CXIckyKGzjH5BkEc8+KuTU5eWHbska+JzVbsibebtu3zV3b0P1kdOZV65ubHamuVLN9IVrMsQQz16Cs6OWNnK1yo9PfI97uvVvL13CiBO5BdWVVystFmGyaK6BcfVsOlpq1vRJkmmRJd18XNVsaehqp+UeMjqfI4puXlm01kLNam+JK7qD4ppLjX7czmsV7VbyL4ovVU6t5vACjBPXtfYPFPyXeNqXGRY+aKCexfqy14OaXbk5JXtRkiLvtzMc5EXoqovQ29TKU781mGtbgsy1n9lPHFI1zon7b8rkRfNXb0KBlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHpt3IMfVms2p461aFjpJZpnoxjGom7nOVeiIiIqqq/AB7gTT9YS5OFy6exsmYWXHNv07kknYUJ+ddo2dvs5UVU85Vax2zevirUXzbwGXzkd6HIZp1GnarxRsgxDVhmrvTrK5LCqqu5l81FRrFRvy9UDaZ7UGM0tibGUzOQrYrG10RZbdyVsUTN1RqbucqIm6qiJ8KqieKmtyOqrLHZevisHkMpfx7oG9m+PyWGdZNl3jml2Y9GNXdys5tve9XbtM+jpnFY3KXslXoQR5G8kTbVzk3mnSJNoke9eqo1FXZFXoqqviq77MCeuU9SZCW9GzIU8TW8oiWpNWhWeZYU6yI/n2ajnL0TZF5U69VXol0Pj7yyd5S28s1cg3JRx3LDnMgkb7xrGt2RGN23Rqoqb9V3XqUIAx6ePq49Jkq1oayTSumkSGNGc8jl3c923i5V8VXqpkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADTZfRuBz0M8WRw1G4yeWOeXta7VV8ka7xvVdt+ZvoXxT0G5AE7b0VXldekqZLLY2e5ZjtSy178j0RzPyWMkV7GNcnRzWtRF8V69RYxOo4VtPo5+vIstxkzI8jQSRsNf8uFvZvjXdfyXuVytXxRxRACdmyWpaa2HOwtO/H5c2OBKd5Wv8lXxlekjGoj2/yGuXdOqKi9BJrSKm6Xy7EZik1uQbj43+QusJMrvezJ2HacsK+l7+VG/lcpRADTVNZ4K9JOyDL03yQXlxkjFmajm2kTdYdlX3+3Xl8VTqnQ3JjXcdUySQpbqw2khlbPEk0aP5JGru17d/ByL1RU6oaZOH+Eh/2StNi98p3zJ3balqpPaX3zpUjc1JGu/KY/drvFUVeoFECeZp3LVHtWrqW3Ix2SdclZfgimTsHeNWNWtYrWIvVrlVzk9KuTZE8RT6qqJWbPUxWS7S85k0sE8lbsai+9ejHNk55E6IreZqL4ov5IFECeg1dIjq7L+By+OknuvpRo6u2w1durZnOgdIjInJ4Ofy7eDkap78ZrPB5iOq6rlKz1tSyQwMe/kfJJGu0jWsds5Vavim3QDdAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGPdyFXHRxyW7MNVkkrIWOmkRiOke5GsYir4uc5URE8VVURDX5zOSU3uoY6KK5nJa0k9WrM90cTuVWt3kkRruRvM9vXZXKm/K12yoea2nIUvzXbssmRsPmZPE2zs6Ko5sfInYM8I/fPVXdXLzuRXKnKiBjVcxlc3NVkoY/wAhxyWJo7MuTa6OdzGIqMfDEiLujn9d5FavK3dGrzIqMVo2pTkx9vITzZ3MU4H125TIIxZlR67vXlY1sbVd0ReRreiInghQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY9rHVL0kElmrDYfXf2kLpY0csb/wCU1V8F+VDIAE9S0JicTJRXGssYuKnPLYZWpWZIoHukRedHxI7kem67oip5q9U23XdTxOoMZ3ZE3Ox5WtC2dLj8nTalqyrlVYVbJCsccfJ71fwTuZNveqiqtCAJyjqHMxOxsGY05LBPPBJJZs4yyy3UrPZvszmckcruZE3aqQ7eheVdt8vC6uw+oW1vIrzHTWIPKo6syLDY7LmVqudC9Ee1EcitXmamypt4m4MLIYajlUd5XVinc6J8HaOb56Memz2o7xRFTx2UDNBLzYfL6crukwdqTJV61COvXwuRn3R72OTz/KnI6VXuZu1VkV6KqNXovMrt7jcrUy0cz6k7JkhldBKjV3WORq7OY5PQqfB+hfBQMsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANXqHLT4ukiUYIL2UmXs6lKe02ukz/AE+cqKqNa3d7la1zka1dmuXZF2hM4GSHUWev5lJMbfrU5JcdQnghVZ4FY/ktsdKvwzRI1Wt6fgE3VV6NDc4rFMxMD42z2bT5JHSvmtTLI9VcqqqJv0a1N+jWojUToiIZoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB6rNqGlXknsSsggjTmfLK5Gtanwqq9EQm14paOau3toxHw7pdjVF/wDM20YWJifopmfSFiJnUqQS3uqaO9aMT9Mj/aPdU0d60Yn6ZH+0z0bG3J5SuWdjd5vO43TOLnyeYyNTFY2uiLNcvTthhjRVREVz3KiJuqonVfFUIPQHFnR2o9VZ/GY7XWlc1ct5HmoUMXdhdYWNKcCvRUa7eZyObK/nbuiN2bv5iomZqvVvD3WmmcpgMtqHEWcbkq0lWxEtyPqx7Vauy79F67ovoXZT4d9hLwJxHCvjrqrUeqM5jooNOyS0cHZkssa24siOatiPr1b2Sq39Mip4tVBo2NuTykyzsf0gBLe6po71oxP0yP8AaPdU0d60Yn6ZH+0aNjbk8pMs7FSCW91TR3rRifpkf7TMxevNN5u0yrQz2NuWX78kMNpjnu28dkRd12+Qk4GLTF5onlKWlvQAaEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGFmstVwOHv5O9OytSpQSWZ55N+WONjVc5y7ddkRFXoYuka9irpbEx3LceQuJVjWxchrpXZYlVqK+RI094jnKruX0b+kxOImR7r0RmbHe0eCcldzGZKWt5S2u53mtesX5eyqnm+kogAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIvVTkyGssTjp0SSnHUmu9i7q18rZImscqeC8vM5URd+qovi1FNiazO/xkY7+qbH+dCbM9XVh0Rw/Msp8gAGLEAAAAADGyONr5anJWtRpJE/5dlaqdUc1U6tci7Kjk6oqIqdTJBYmYm8D26Dyk+a0Xg71p/a2Z6cT5ZNtud3Km7tvRuvXb5TfEtws/i505/QYv8JUnFjxFOLXEbZ+6zrAAaEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABO8QMh3XpK7Z72jwfI6JPL5a3lDY95WJt2fp5t+X5Obf0FETvEHId1aSuWe9o8HyOhTy+Wt5Q2PeVibLH6ebfl+Tm39BRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHjwNLlta4DBR3n38zSreQxMntNfO3nhjcuzHOai7ojl6J06r4AaTO/xkY7+qbH+dCbMnb+brZLirDVgSwslXESOkfJVljidzyQubySOajX9PHlVeXdEXZVKI9X/AGUen5llPk5pxW4vXNAak0rp3E4CLO5nUK2fJmW8kyhAiQtYrm9o5juaR3OnKxE67L1TYmeIfsnauiNSxacZRwyZ6GjDeyMGd1LWxUVbtEXlhZJIju2k812/KiNROVVcnMhR8d9Dai4iadZhMTitK5fHWY5mW4tTdsixSKiJFNA6NrtnM89fBF6t2c3Zd43GcEtdcPM3WzGl8pg9S3buEoYvNN1T2zO2nqxqxlqOSNr3buRzkcxyddkXm3NM5r+DFscn7JR83DjTWtdP4LHXMPl45XSS5zUVbFMryRvViwo96OSR6ua9E5fNXkVeZEVN/LfZJz55vDhuk9JyZybW2Nt36zbV9tRtRYOy52zO5H9PwjkVzd+rURGu5un71Vwr1jc1zprV1Bmlcnk6mDdirNXKxzMq1J3va99qqxqPXdyorVa5WqrUanOnUwOFfAbUWhb3DFb97GWYNJY/L4+eSs+RHWEszROge1is2TzY15kV3RdtlcnUn+VxvZeM2p8rqPJ4XS2g26hs4NsMWanfmWVYILT42yLXge6Ne3c1rk3VUjTqm6oq7ETd4u6w0VxO4zWa2nLeq8BgnULdhkmXbC2hAmPjklbXjcjuZ6+e9WpyIq/lKq7FbLw94g6H1vqvJ6EtabtYjU1lmQsVtQLYY+lbSJkT3x9k1e1Y5I2KrXKxUVOjtjKscJM1YscZ5Vs0EXWtSKGhs9/4JzcelZe18zzU50VU5ebzfl6F8R1DDZatnsPRydN6yVLsEdmF6psrmPajmrt+hUMw0ehMHPpjRGnsNafHJax2Or1JXwqqsc+OJrHK1VRFVN0XbdE/QbwzHp4Wfxc6c/oMX+EqSW4Wfxc6c/oMX+EqTl7R8av1n7rOuQAHOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ3iDkO6tJXLPe0eD5HQp5fLW8obHvKxNlj9PNvy/Jzb+goid4g5DurSVyz3tHg+R0KeXy1vKGx7ysTZY/Tzb8vyc2/oKIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGvt6hxdC7XpWclUr3LLZHQVpJ2tklRibyKxqru7lRFVdvD0gbAE5R17issmMdjku5GHIxSz17FajM6BWx+PNLy8jFVU2ajlRXfk7p1FTUWZyLKMkGmLNSOzXllk7ysxRPryJ0jje2NZOrvHdu6NTx6+aBRgnazNV2nU32ZcRjmOqOS1BAyW05tlfe9nKqxosbfTzR7u/4TxV0xknJRdkNTZC1JDVkgnjrxw14bD3/wC9VEYr2uanRqNeiJ4qir1AozUZDV2DxUs0VvL0oJ4ab8i+B07e0Ssz383JvzKxPBXbbb9DCj4eYLsoo7VaXKoyg/GOXK2ZbfbV3+/ZIkrnJJzeCq5FVU6b7dDcY7DY/EQV4aFGtShrwtrQx14Wxtjib72NqIibNT0NTogGodrqjL0pU8nknOxfe0K1cfL2U8S+9YyZzWxdq70RK9H7dVRE6iTO56y2VKOmlY5ce2zA7J3mQMWy7wrSdmkrmbflPRrkT8nmKMATk1bVd1thrbuKxbZKLGxLHXksvhtr7927nMR8aeCJyoq+KqngLOk7eQS225qTKuis02VVgqrFXbE9PfTRvYxJGvd6d3qiJ71E6qtGAJy1w90/kUutyOPblo71aOnahycj7UU0TPetdHIrmL16qu3nL1Xc3VbHVKT3Pr1YYHva1jnRRo1VRqbNRdvQidE+AyQBE53+MjHf1TY/zoTZmu1W1uO1hicnYVIqT6k1JZ3Ls1krpInMa5fBOblciKqom6Ini5ENiioqbp1Q9XXh0Tw/Msp8gAGLEAAAAAADFyeUrYio+xalSONvRE8XPcvRGtanVzlVURGpuqqqInVSxEzNoHs4Wfxc6c/oMX+EqTRaExc+E0ZhKFpnZ2a9OJkse/NyP5U3bv6dl3Tf5DenFjzFWLXMbZ+6zrAAaEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABO8Qch3VpK5Z72jwfI6FPL5a3lDY95WJssfp5t+X5Obf0FETvEHId1aSuWe9o8HyOhTy+Wt5Q2PeVibLH6ebfl+Tm39BRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAam9q3CYuWtFby9GtLauJj4I5bDGulsqm6QtTfdX7deVOuyKu2xhw63q3VrrQx+VvMlvOoPkZQkibE5vvpHLKjN4k/lt5kX8ncCiBOwZXUd3sXR4GvRYl90M6X76c6VU/30aRMejnOXwjc5uydVci+avmtjdSTPqPu5upD2VuSWWLH0eVs0H+7icsj3qip4ue3bf0I30hQnosX61SSCOexFDJO/s4myPRqyO235Woviu3oQ0lTRccfkD7uXzOUnpWJLMcs950XO535MjIezjkY1OjWPaqJ0XbdNz34rROAwkddlLD0oPJppLELkharo5JP3x6OXqjneld91A9FHiDp/LOxnduQTKxZKWWGtZxsT7UDnRb9pzSxtcxiIqbbuVEVeiKq9Bj9U3cquJfBpvKQ1bj5mzzXOygdTazfldJG5/OvOvvUai9OruX00QAncbNqu2uHmvVMRi2qsy5KpDYltuROqQpDKrIk3Xor+ZmydWpv74Y3AZtiYaXJ6nns2KaT+Vx0qkNetfV+/Jzsckj2JGnvUZI3derubwKIATmP0FjKLcUssl7JWMYyZkFnIXpZ5FSXftFfzO2eqouycyLyp0bsnQ2GG0zh9OUqlPE4mji6lSNYq0FKsyGOFirurWNaiI1N+uyGzAAAAAAAAAAAAAAAAAHrsV4rcEkM8TJoZEVr45Go5rkXxRUXxQm3cLtGvXd2k8Iq/CuPi+qVANlGJXh/oqmPSViZjUlvcs0Z6pYT9XxfVHuWaM9UsJ+r4vqlSDZpGNvzzlc07Ut7lmjPVLCfq+L6o9yzRnqlhP1fF9UqQNIxt+ecmadrnsvCXSlXV0NiLRWPsVbtRYbE3Yw+T1nROV0e0Lk98/tZEV7E3Xs2I7dEardz7lmjPVLCfq+L6p7tfY9benX2ocVFmL+MkbkaVWWz5Ojp4l5m7SbojVVN087zV32d5qqULHtkY1zXI5rk3RyLuioNIxt+ecmadqY9yzRnqlhP1fF9UzcVobTmDsts47AYyhYbvyy1qccb27+Oyom6bm8BJx8WqLTXPOUvO0ABoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATvEHId1aSuWe9o8HyOhTy+Wt5Q2PeVibLH6ebfl+Tm39BRE7xByHdWkrlnvaPB8joU8vlreUNj3lYmyx+nm35fk5t/QUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABjZHI1sTRsXLcqQVq8bpZJHdeVrWq5y7J1XZEVenwGhs5/N5RlhmCw/Zo6nHYq5HLqsMD5HqnmLEn4ZFa1VVyOYzrs3ffmVoU5g5rOY3TeNmyOWyFXF4+Hbtbd2ZsMUe6oicz3KiJuqonVfFUNTkdJ282/KxZDP5BMddjijjqY9/kbq3Lsr3Mnj2m5nqi7rzpsi7JsvVdhW0th6eSyGRhxlVl/ILCtu12SLLP2SbRc7vF3Invd/DdVTxUDCua1qxOyUVOjkstbx80UE1epUciq6TbblfJyxvREXdytcvKnjsqoi+LN/Utl12OliaVTsrUccE9+2rmzw/7yRGxtVWqng1qr19Kt9NEAJ6bB5y8tltjUj6ka3WT1+66ccT2V2/7h6y9qj+b8p7UYu3veRep4k0Fibfa+XJaybX5BMm1l63LMyKZvvOza52zGN9DERG79dt+pRADEx+Jo4lLCUaVemliZ9mZK8TY+0leu75HbJ1c5equXqvpMsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/E0MdmGSKVjZIpGq17HJujkXoqKnwGi0C18GksfUkqVaC0mupJVpz9tFE2Fyxtajt1X3rE6L1Rei9UUoCc0jAtK7qSqlKjShZlHSxJTl5nTJJFHK6WVv5EiyPk3T0oiO/KAowAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABO8Qch3VpK5Z72jwfI6FPL5a3lDY95WJssfp5t+X5Obf0FETvEHId1aSuWe9o8HyOhTy+Wt5Q2PeVibLH6ebfl+Tm39BRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJviRb1Lj9CZy3o+Cla1NXqvmoV8hG+SGaRvndmrWOa7dyIrU2cmyqir0A8YKBMtnsnk7smMuWaNmWjSfQldI6tArYnPjl3XZsyvbu7ZE83s067brSnxL7Cv2UfEzj9xGy+Pv6Y0phdNUWPuZe1i8fYhmfYenLG3mdO5vO5W7qrkVVbGvyKfbQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAncNWdW1jqNUp0II52VZ+3gk3sTu5XsVZm+hESNqNX0oip+SUROUq3ZcQ8vOlWgztsXTatqOX91yKyWz5kjPRG3n3Y70q+RPQBRgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACd4g5DurSVyz3tHg+R0KeXy1vKGx7ysTZY/Tzb8vyc2/oKIneIOQ7q0lcs97R4PkdCnl8tbyhse8rE2WP082/L8nNv6CiAAAAAAAAAAAAAAAAAEflsvksvmrmOx1tcXVoOYyxaZE18ssrmtfyM50VqNRjm7rsqqrtvN5fOsCBwn4z60/raP/Q1Ts7NTEzVVMao/MR+Vg7nzvrpmPo9H7sO58766Zj6PR+7G7B15/lj2x0W7Sdz5310zH0ej92Hc+d9dMx9Ho/djdgZ/lj2x0LtJ3PnfXTMfR6P3Ydz5310zH0ej92N2Bn+WPbHQu0nc+d9dMx9Ho/dh3PnfXTMfR6P3Y3YGf5Y9sdC7nuiuDdXh1LmpNOZ3JYp+ZvPyN90MFNe2nd4u6112T4Gps1N12RN1KfufO+umY+j0fuxuwM/yx7Y6F2k7nzvrpmPo9H7sO58766Zj6PR+7G7Az/LHtjoXaTufO+umY+j0fuw7nzvrpmPo9H7sbsDP8se2OhdpO58766Zj6PR+7DufO+umY+j0fuxuwM/yx7Y6F2mZjtQV/Pi1ddnlTq1l2pVfEq/A5I4o3Knw7ORflQp9M5v2w4eO26HyeZHyQTQ83MjJY3uY9EVUTdvM1dl2TdNl2TcwTE4Z/wJkP62vf6h5qxoirCmq0XiY1REbdhrhXAA81iAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATkUDW8Q7UyVKDXPxUTFtJL+63I2aRUYrP5tOZVR38pzkKMnGw7cQ3zeT41N8U1nlCP/dq7TKvKrf5rrvv/AClUCjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE7xByHdWkrlnvaPB8joU8vlreUNj3lYmyx+nm35fk5t/QURO8QMgmK0nctLlo8GjHRJ5dLW8obHvKxNlZsu/Nvy/Jzb+gogAAAAAAAAAAAAAAAABA4T8Z9af1tH/AKGqXxA4T8Z9af1tH/oap3dl1V+n5hY827NK3WGKdrJ+lksKubZQbk31+zds2u6RY2u5tturmuTbffp+g3R87ZnSWjXezM7wzeNxKXn6Wq3qdm6xiPdcjuPYkjHO8ZGsSJN06oiNM5myPokHynw+wel9J8OeLXETKYJ2cyeNz2pXtfzuSdkKTzNfDC/feFrkV26t298q9diY4e41mieJuRxlGzpqlUzmgr2Qs4bS80z4GSNfF2T5Vklf2knK+REkRrOZObp6THMPtM0utdV1NCaPzmpL8c01HEUpr88dZqOldHExXuRiKqIrtmrtuqJv6UPl/h1pLGaQo+xqz+IhdRzGfqMq5W6yVyyXY5MVJKrZVcq86NexjmovRvKiN2RNiWx+Pw+hdA8TtHRRYrUWcu6GyuTg1lhLzrC5asiKirbjVy8s/M9q8yK5HJvsqbbDMPtnFZGPL4yneha5sNqFk7GvREcjXNRU32367KYGW1hisJqHBYS3YWPJZt8zKMKRuXtFijWSTdUTZuzU9Kpvv0Pl/iRLpzihLpfBOg0u+Oho+LMrqLUNqZ9eOF6rHy1o4pY0WRHROVZebzPNTrvsafH47T3EPFexhy+u62PzMd7HW6d27mGte2ZzabljZI9/RXc7VVN13V2/pGYfaIPjHVeAj4mcV+Jceo9SaSxHc8kLMWmpILD308e6sx0dmpIy5C1iK5XuV7WqvMnV22yJ9aaJxd7CaOweOyWVXO5CpShgsZNW8q23tYiOlVN16uVObxXxMom43QPnfiZQ09q/2SuP09xAmhfpiLTSXsRjr9hYqlm75S5s71TdEkkZGkWzV32R6uRPSnPeDlmlj8rwVs+VMbjO/tX14bUs/Oxyulm7NO0cq8yuRq7Kqqq7ekmbxH2UD4a1Pn35ddTVqOZx1XSWZ4qzU8pkrXPLRc1MbB2cc6xSxqsTpmtRfwjU3REVVTdF2mrOFzNOaDyNKvqzDZDC5HVen6vdWlGS1q+Lm8rYkjo+azM6J72SRqqNVu3K1yJuu5M/AfaIPm/izSwPsXMxp/iHgcLDjtPxVreGzFOhFskiSNWetIqJ4r5RHyc3j+6FOq8DdH3ND8K8Bjcm5X5l8TruSe7xdcsPdPY//cken6EQyifGwuzE4Z/wJkP62vf6h5lmJwz/AIEyH9bXv9Q8yxPg1esflfJXAA8xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACd8nX3Qln8kx+3dfJ5Vz/ALs/fd+Tl/mvTv8AyiiJ3yZfdCWx5DS27r7Py7tf3T++79nyfzfp5vh6AUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAneIOQ7q0lcs97R4PkdCnl8tbyhse8rE2WP082/L8nNv6CiJ3iDkO6tJXLPe0eD5HQp5fLW8obHvKxNlj9PNvy/Jzb+gogAAAAAAAAAAAAAAAABA4T8Z9af1tH/oapfEFhmq3U+s99uuVjXbf0eRVf2Hd2X/AH+n5hY826NPndHYDVFilYzODxuWnov7WpLeqRzOrv6edGrkVWr0Tqm3ghuAbEYNHA4zGVbNanjqlStZlknnhggaxkskiq6R7kRNnOcqqrlXqqqu5qMZwy0dhWRMx2k8HQZEsro21cbDGjFkbySqnK1Nudvmu28U6LuUoFhqmaUwkcGJgZh8e2HEIiY6NtViNpbMWNOxTb8H5iq3zdvNVU8DGwOgtMaVfcfhdOYnDvu/7U6hRigWf/n5GpzeK+O/ib4ATUnDLR80OMhk0pg3w4tzn0I3Y6FW1HOdzOWJOXzFV3VVbtuvU91zh9pbIYFuDtaaxFnCtlWduNmoRPrJIrler0jVvLzK5znKu2+7lX0m/AtAncxw40lqGShJldL4XJvoMSOm65j4ZVrNTwbGrmryInwJsavNaD1DkspYs0uIuewtWRUWOhUpY18UKbImzVlqveqdN/OcviWwFhKP4cYrN4GnjdXxV9dvrSOkZa1Bj6sr+ZVVUVGMibG1UTZN2tRdkTfdeppdD8EcFpnh8ukcxUx+qMYmQt32w3sfGsLVmsSTNakTlenmdpyovyb7JvsdFAtA0cOhdN1sTexUWnsVFi7zue3SZSiSGw7la3eRiN5XrysYm6ovRrU9CHrocPNK4vERYqlpnD1MXFYZajpQUImQsmY5HMkRiN5Ue1yIqO23RURU8CgAsIbiRw0l4l2sNVvZha+mKlqK5dw8dVjlvyRSslhR0rlVWMR7EVWtTd3huib73IAAxOGf8CZD+tr3+oeZZi8NE2wd9fFFy1/ZUXff90yIXE+DV6x+V8laADzEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJzyX/ANoa2fIaf8Fdn5d237p/ft+z5P5Hp5vh6FGTqVP/AGhOtd31du60j7w7b90fvqr2XZ/yPyub4egFEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ3iDkO6tJXLPe0eD5HQp5fLW8obHvKxNlj9PNvy/Jzb+goid4g5DurSVyz3tHg+R0KeXy1vKGx7ysTZY/Tzb8vyc2/oKIAAAAAAAAAAAAAAAAATea0vZnyD8jibsdC5K1rLDLEKzQzo33qq1HNVr0TdOZF8Nt0dyt2pAbKMSrDm9K3siO4NYfGeD+gTfbDuDWHxng/oE32xbg6NKxNkcoW6I7g1h8Z4P6BN9sO4NYfGeD+gTfbFuBpWJsjlBdEdwaw+M8H9Am+2HcGsPjPB/QJvti3A0rE2RyguiO4NYfGeD+gTfbDuDWHxng/oE32xbgaVibI5QXcp0le1fqqTOtbawtbuvJy41VdTmd2isaxedPwqbb8/h8hv8AuDWHxng/oE32x6OH7u6da69wkzVjldkI8vXVfCWvPBG3mT9E0M7V+DZvwl8NKxNkcoLojuDWHxng/oE32w7g1h8Z4P6BN9sW4GlYmyOUF0R3BrD4zwf0Cb7Ydwaw+M8H9Am+2LcDSsTZHKC6I7g1h8Z4P6BN9sO4NYfGeD+gTfbFuBpWJsjlBdFs03qqbdk+ZxcEbuiyVsfIsiJ/w80qtRfgVUVOngpUYnFV8JjoaVVrmwxIu3O5XOcqqquc5V6qqqqqqr4qqmYDViY1eJFqtXpZL3AAaEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ1lN3uhTW+76qM7rZEmQSX90KvavVYlZ/ITo7m+FVT0FETsFDbiFeu+QVWquLrwpfSdVnf+FmVYlj8EYnRyO9Kucn5IFEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ3iDkO6tJXLPe0eD5HQp5fLW8obHvKxNlj9PNvy/Jzb+goid4g5DurSVyz3tHg+R0KeXy1vKGx7ysTZY/Tzb8vyc2/oKIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmdX6WsZWanlsRYbS1Fjkf5LLIqpDOxyJz150RFVYnq1qqqJu1WtcnVNl/GluINHUN6XEWopcLqSuznsYa8nLKjfDtIl97PFv4SRqrd+i8rkc1Kk0uqNG4bWdOOtmKLLbYnLJBMjnRz137bc8MrFR8T9lVOZjkXr4gboHPXYHXWkWr3FmaurKDduXH6kcsFljUTqjbkTHc3o27SJzl9L/SF4y08Kjk1bgszo9WLyrZvVfKKa+PneU11kjY3p4yKxfhRF6AdCBrcFqTEaopJcw2UpZeoq7JYo2GTx7/APM1VQ2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACcx9Jqa/zd7u6vE9+OpV+8GWOaaZGyWXdm6P8hrFk3R35Syu/koUZO6foNZqbU99aFWvJPPBAlqGdZJLLI4GKiyN8I1a6SRqN+BEd+UBRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACd4g5DurSVyz3tHg+R0KeXy1vKGx7ysTZY/Tzb8vyc2/oKIneIOQ7q0lcs97R4PkdCnl8tbyhse8rE2WP082/L8nNv6CiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACOz3B/RmpL0l+3p6pFlHps7J0UdUu+O/8AtEKskTr198axeGOdxCJ7XeIWdpsamzamZbFlIP8A5nStSdfnv2nRABz1b3FHCq/tsXpjVUKf7ylanxcy9fRFI2dq9PhlQ/PuvzYxqe2DQ2rMJsuzpIse3Jx/pTyJ8ztv0tRfhRDogAhsZxx0BlrbacWrsVXvu8KN6wlSz8zLyv8A/pLeORsrGvY5Hscm6Oau6KnwmLlMPQzlR1XI0q2QrO99DaibIxf0tcioRb+Aeg455Jsfp+PT871VXS6esTYtyqvi5VrPj3Xrvv47gdABzxvCzMYxHdy8RdT0m7bNgvurZCJOvpWaJ0q/B++J4/oPHkPFbE/vWW0nqRieDLNCzjZF/wCaRks7VX5UjT9AHRAc7XXeuMWid6cNbFzZPOfpzMVrbU/R5QtZyp+hu/yB3HPAUV5czjdR6fdsiq7I4G32Lf0zxxviT++B0QEnguLWidT2Fr4nV+DyNpruV1avkInysd8DmI7mRfkVNysAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPzJIyGN8kj2sjYiuc5y7IiJ4qqmg0LU7HButuqUas+RsS3pe7pVlil7R6qx/P8AlKsfZ7qnTfw6bHHuI3suuHeA1zmuG2XytbB52CxSqSv1HVkTHWoJ+RZuWSPmROWJ7k3m7NvMqdeTdydw07mcRqDC1L+CvUsliJW7V7OOmZLA9rVVvmOYqtVEVFTp4bbAbIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATvEHId1aSuWe9o8HyOhTy+Wt5Q2PeVibLH6ebfl+Tm39BRE7xByHdWkrlnvaPB8joU8vlreUNj3lYmyx+nm35fk5t/QUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGoz2kMDqqNI81hMdmI06I2/UjnT/wAHopJJwA0RV37qxlrTS+hNO5KzjGt/QyvIxv8AYqbfIdEAHPE4Y57GxqmH4kairpuithyUdS/Gm2/RVfCkq/Oeg8eS8VsU1OzyOkdSIi9Gz07OLeqfAr2yWE3+VGJ+g6IAOeO17rXFrtk+Gly21ETmk09l6tpqdOvSw6u5U/Q3f5PQeE456fqLy5jH6i085PfOyeBtthb+mdkbov8A6zogAlNPcWNFatk7PC6uweUm35VhqZCKSRq/ArUdui/IqblWabUOi9PauiWLO4LGZqJU25MhTjnbt+h6KSreAeiqb2vxOPt6bc1UVqafydrHMTbw/BwSMYqfIrVT5AOhg54nDLUONYqYfiTqGFN0VsOUhqXok+Td0KSr856Dz5NxTxbvMvaS1HGjejZqtnFvVdvS9r7CdV9KMTb4AOhA563Xms8cqJleG1ydEaqulwGVq22NVN/RM6u9f7Gb9fA/K8ddO0kRMxR1Dp53irspgbbIm/pnbG6L/wCsDogJXTvFbRWrpEiwmrcJlZt9lhp5CKSRF+BWo7dF+RUOfaC9lVw/41Y3VNXSOcVcvi47KJUtsWCeVrGu5Z4mr1dGu26flIm3M1qrsZUxmmKdo6Dc4g1YrMsVLGZPMNicrHz0oW9kjk6KiPe5qO2Xoqt3RF3TfdFRPT7oknqtnv7lf7Y9OmImQaaxMUbUZGypE1rU9CIxNkNmelOHhUzly3txll4R5ML3RJPVbPf3K/2w90ST1Wz39yv9sZoJlwtz6z1LxsYXuiSeq2e/uV/th7oknqtnv7lf7YzQMuFufWepeNjC90ST1Wz39yv9sPdEk9Vs9/cr/bGaBlwtz6z1LxsYXuiSeq2e/uV/th7oknqtnv7lf7YzQMuFufWepeNj444oexWZxk9lLY17qXCZZdFyVazpcZX7JLNueJiR9m9e1RGRKjWqrmuVyp0Tl35m/WWP1pDiaFajR0bmKdKtE2GCvBDWZHFG1ERrGtSbZERERERPBENqBlwtz6z1LxsYXuiSeq2e/uV/th7oknqtnv7lf7YzQMuFufWepeNjC90ST1Wz39yv9sPdEk9Vs9/cr/bGaBlwtz6z1LxsYXuiSeq2e/uV/th7oknqtnv7lf7YzQMuFufWepeNjMwOp6moO1ZEyerah2WWpbiWOViL4O28HNXZfOaqpuipvuiom3IWV6xa+02rV2WSK3E5U9LeVjtv/FjV/sLo5cfDiiYmnVMX+sx+EkABzIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ3iDkO6tJXLPe0eD5HQp5fLW8obHvKxNlj9PNvy/Jzb+goid4gZDuvSdyz3tHg+R0SeXy1vKGx7ysTZWenm35fk5t/QUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGk1FojTmr41jz2AxebjVNuTI0o7CbfBs9qnxdoD/ANGfheHNKTUWe1jkslmcfA+1DHiU8kiZIxqqnn7q9ybp/wAPwH3YajV/4p5r+hT/AOW424XxKfWFjW0env4Axn9Fi/wIbA1+nv4Axn9Fi/wIZlhJVgkSBzGTK1eR0jVc1HbdFVEVN039G6Ho1/qknW9gPlHQfEviFoX2MOrNb5HJYjUE+Ps5B1KKerYWVZW5KWN6SvdOvMzxRjWo1WtRqKrtuvSdda61zoLR1e9l81ozFZa7fbFBFNSuztZG6PfsY44nrJamR6Km7EYitRXcqbbGnMjsoPnLG+yO1RqDh/pW/jcXiWahyOsH6TuNtssR1Uc1k69uxrkbKxPwcbuR6c2yuauy+cns1Dx61tpPBa3pXcbh7uodM5XH1LGUqVrHkEVO0xknlkkCPdLtE1Xc7WvXw3323GaB9Eg+VeL9jV/ErF8I8aub0bmMVqHMSts+RV7E+OvrHBYkiV3LO1XxcrEV0fMv4RE85UbstflOJes2WNaQcP8AEaei0xoFraUtbJpN216SKu2Z8MCxuRsKNY5jEc5H7u9CIMw72DhWm+MesOJvEDu3ScWDo6dXAYrPpdyleaadGW+0csXIyVqK5Wt6O3RGq1d0fzJtN2+PPEtNPe2SpR0rJjPbZLpdlKZlls0m959WKdZEerWbLyczOR26I5Uc3dGozQPpkHNeGGu9RZfWms9I6pZjJcpp9KU7L2IikhhsQWWSKzeOR71a5qxPRfOVF6L0N3xb4hRcKuHOc1VLUfkFx8KLFUY7lWeV72xxs5vQive1FXrsi79TK/hcV4OCW+KPEzRmqcZh9V19KzPyODymWYuJisosElWOJyROV8nnJvKm7k232Xo3xXbRcaMv7VeCmVmr0GP1otbvP8G/khSTHSWnLD5+7dnsRE5ubzd/FepM0DsoPlzTXsq9UansYjNUcAl7TmTuxxR4mvgMqt2Oq+XkSwtxYvJnKjVSRWJs3ZFRHqqdaGrxQ4ramxnEbK4GnphtXS2WyWPqUrFWxLYyXk6KrERWzNSNy+a3fZ3Mqr0aiJvM0D6CBy7TPGF2vde6bx2nWVpsDb02mochala50kbZnNbUiaqORGudyzq5HIvSP0HUTKJuNNZ/HzS/6Lf+WheEHZ/HzS/6Lf8AloXhq7V/s9PzKz5AAOJAAAAAAAAAAAAAAAAAAAAAAAAAAAAABO8Qch3VpK5Z72jwfI6FPL5a3lDY95WJssfp5t+X5Obf0FETvEHId1aSuWe9o8HyOhTy+Wt5Q2PeVibLH6ebfl+Tm39BRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADUav8AxTzX9Cn/AMtxtzUav/FPNf0Kf/LcbcL4lPrCxraPT38AYz+ixf4ENga/T38AYz+ixf4ENgejX+qSdbhVz2NuUm0NrLRMOtGx6Tzb7M1KnJiWvmx8k1lLD/wqSp2rUcsiI1Uavn9VXYtuJnDK7rTN6Xz2GzrMBn9PSzuq2LFFLkLmTR9nK10SvYu6oibORyKmy+KKqF+DVlhHE8J7HKzi4MdHZ1bJknVNZe3F08+Pa2SaV0L2SwryPRqI58jno5G+anm7L4m/u8KM5W1NrXP6d1czB5PUc9CVr5MW2yyu2tD2TmOa6RO0R/junIrfQvpOmgZYHGNK+xxZpqPSb/bAtm1h9RXNR2ntotijtTWIpo3xxxtftAxO13RE5ve/Luns1fwFy2VzOq5dO62m0xiNWtb33QbjmWHvf2SQvkryq9Oxe+NrWqqtf1TdERTsYGWNQgNDcIaWgdZZHL461y4+fDY3C1sb2W3k8VNJUYvacy826Som3Km3L4rv0n09j9toePTvf3vNWe2jynyPx/d/lfYcvaf/ACc+/wAvL6Dr4FoHNren7fD/AF3qrW1PHZPVcmo4sfTXE4qKuySqlZs/4RXzzxtc13aomybKi7dFRVVMbUDX8bdNZjRmf0RqjTeMydVzH5G5JRRsTkVHMc1YbMjudHI1yebtu3qdSAsPnVOGetI+NWiG6sz82tsUmCzFGbIQYZKUddJErNRJXsc9FkkRF6qrUXkXlb4m4wPsds5jp+H1fI67TKYPRM6Ljsf3QyJ00KV5IGMmkSReZ7WPREeiNTZF3YqruncgTLA5Jw84L6j4Zz0cViNeye0WjYfLWwU+KjfYjicrneT+VK7dY0V3TzOZERE5tig0hpFvCXCayuvsWc0y9lr+oVgp01WZEl8/sI42ucsjk5dk22VyqnRC7BbRA4l7FrhdJoDT+pMpZx9rFTagy89upj72yT0cej3eS13oiqjeVrnu5d15e02XqinbQCxFosNNZ/HzS/6Lf+WheEHZ/HzS/wCi3/loXhq7V/s9PzKz5AAOJAAAAAAAAAAAAAAAAAAAAAAAAAAAAABO8Qch3VpK5Z72jwfI6FPL5a3lDY95WJssfp5t+X5Obf0FETvEHId1aSuWe9o8HyOhTy+Wt5Q2PeVibLH6ebfl+Tm39BRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADGydFuTxtum9ytZYhfCrk9CORU3/APMyQWJmJvA5rS1DFpqjWxuais07tWJsL3NqyyRS8qInPG9rVa5q7b7eKb7KiL0Pd7f8H+czfRJvqHRAd+k4c+NVE39f/GV4c79v+D/OZvok31B7f8H+czfRJvqHRANIwtyecfxPBzv2/wCD/OZvok31B7f8H+czfRJvqHRANIwtyecfxPBzv2/4P85m+iTfUHt/wf5zN9Em+odEA0jC3J5x/E8HO/b/AIP85m+iTfUPVDxJ07YknjivulfA/s5WsrSqsbuVHcrk5ei8rmrsvoci+k6Sc94YtamsuLKtVVVdTwq7fbx7nxv/ANtvEaRhbk84/ieD8+3/AAf5zN9Em+oPb/g/zmb6JN9Q6IBpGFuTzj+J4Od+3/B/nM30Sb6g9v8Ag/zmb6JN9Q6IBpGFuTzj+J4Od+3/AAf5zN9Em+oPb/g/zmb6JN9Q6IBpGFuTzj+J4Od+3/B/nM30Sb6g9v8Ag/zmb6JN9Q6IBpGFuTzj+J4IbBRP1LqWjlooJ4cbQilayWzE6J08kiNTzWuRHcrWou7lREVXJtvsu1yAcuLid5MTa0QkgANKAAAAAAAAAAAAAAAAAAAAAAAAAAAAACd4g5DurSVyz3tHg+R0KeXy1vKGx7ysTZY/Tzb8vyc2/oKIneIGQ7r0lcs97R4PkdEnl0tbyhse8rE2WP082/L8nNv6CiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABz/hnt7ceK2yIn/rNFuqKi7/APZGN+BOn9vX+zY6Ac/4ZOauseK6IqqqamiRUV2+y9z43w6Jt026df09dkDoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACd4g5DurSVyz3tHg+R0KeXy1vKGx7ysTZY/Tzb8vyc2/oKIneIOQ7q0lcs97R4PkdCnl8tbyhse8rE2WP082/L8nNv6CiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABz3hht7cuLO3Lv7aId9t99+58b47+n9HyfKdCOfcMWomsuLCp6dTwqvnov8A/Z8b6PR+hf0+kDoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACd4g5DurSVyz3tHg+R0KeXy1vKGx7ysTZY/Tzb8vyc2/oKIneIOQ7q0lcs97R4PkdCnl8tbyhse8rE2WP082/L8nNv6CiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH1BI7UeqLeHnlkZjKNaGZ8MMjo1nkkWRPPVqovK1rE2RF2VXLv71DCXh9p5VVVxrN/+d/7Tup7PTaJrqtM7Iv+YW0ebooOde57p74sj/vv/aPc9098WR/33/tMtHwt+eUfyPB0UHOvc9098WR/33/tHue6e+LI/wC+/wDaNHwt+eUfyPB0UHOvc9098WR/33/tHue6e+LI/wC+/wDaNHwt+eUfyPBTa90zNrLRmZwlbKXcJau1nxQ5HH2HwT1pNvMka9io5NnbL0Xqm6eCnwR7A7TXFfJeyD1VLq3VupZ8dpaWWHKU72Unmhu3nRrAxJGueqPVrGo5HKi7JHH8CH2j7nunviyP++/9p64uGmmIHyvjw8Eb5Xc8jmq5Fe7ZE3Xr1XZET+xBo+Fvzyj+R4Okg517nunviyP++/8AaPc9098WR/33/tGj4W/PKP5Hg6KDnXue6e+LI/77/wBo9z3T3xZH/ff+0aPhb88o/keDooOde57p74sj/vv/AGj3PdPfFkf99/7Ro+Fvzyj+R4Oig517nunviyP++/8Aafpug8LDu6tWkpzfkzVp5I3sX4UVHE0fC355f+ng6GDQaIzFnNYLtLjmyW69mepJI1vKkixSuYj9vBFcjUcqJ0RVVE6G/OOuicOqaJ1wT4AAMEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE7xByHdWkrlnvaPB8joU8vlreUNj3lYmyx+nm35fk5t/QURO8Qch3VpK5Z72jwfI6FPL5a3lDY95WJssfp5t+X5Obf0FEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEIz+MPUX9Fpf/AJjcGnZ/GHqL+i0v/wAxuD1q/L0p+0MqtYCK1nxk0joDNwYfN5SSvlbFV12ClBSsWZZomu5XKxsUblcqL1Vqbu2RV22RVTD1Jx90FpDNPxWXz7adyJsbrG9Wd8dTnRFZ5RI1isgVUVF2kc3oqL4Gu8MXQQcsj4+4leN13h4+ncSSGlVnivRUbMscsszn+YrmxKxjEa1q9qruRVcrd0VjkP3P7IzQ9rHZiXF5ea5LjY7KTyRYi7PDXkhcrHtlWOFdlRye998rfOaioqKS8DqAOZ1eOencHoXSGW1Pmqi389jobsTcPTtTpZR0bXuligRjpki89Or2pyo5Edspv9PcWNJaryWLoYjNQ37GToSZOn2THqyeBkiRyOa/l5eZr3Ijmb86elELeBWggMhx50LjMSzJTZxXVpb1jHQpBTnmlsTwPVkyRRMjV8rWORUV7Gq3p4lNpHWOF15g4cxgMhFksdK5zGzRbps5q7Oa5qoitcioqK1yIqL4oLwNyDQ6011guHmHTKagyDcfTdMyvGvZvkklld72OONiK9712XZrUVei9OhJReyQ4dy6cXPrn1gw6ZNMN5VPRsRt8rWPtOy2dGioqJui7psjkVq7L0F4gdLBzjNeyH0JpzG469k8pdowX2Sywtmw91siMjerHvfH2PPG1HJ756NTbrvsu5l6h46aJ0zPioLmYfNLlaK5KizH0bF1bNZFbvIzsI37p57V+HZd/BFUXgXgONaz9kbhcFPw4yuNydC5o/Ut21Xs5FIpJXtbHWlexsTW+d2iysaxWK1zt1VvKjikdx+0E3R0WqPbAx2Hlud3Mc2tM6d1rrvB5OjO17Toq8nJzbJvtt1JeB0EGs03qPHauwdTL4qdbOPtNV0Uro3xqqIqou7XojmqioqbKiL0NmZDE4Z/wLkf62vf6h5XEjwz/gXI/wBbXv8AUPK45e0/Gr9VnWAA5kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE7xByC4rSVy0mWjwasdEnl8tbyhse8rE2Vnp5t+X5Obf0FETnEHId16Su2e9Y8JyOhTy6at5Q2PeVibLH6ebfl+Tm39BRgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCM/jD1F/RaX/AOY3Bp2fxh6i/otL/wDMbg9avy9KftDKrW5TawNyX2U2NzK46d+Ni0bZrJfWFywsmddhckfabcqPVqOXl332RfQcddoKPA6u4h4bWGmuImah1BnLV+nNpe9e7tu1LO34KVsMzIo3MTmY7tUTdrU6qh9cA0zTdi4ZHSm4Y+yDjmj09mrmnMpprHYSldxtSS3HWkgsTIrZ3JusaIyVjud/RUR3XdD98H9M5HEcA9UULOKtUslZu56VK0tdzJpe0tWFjcjVTdeZqs5V9KK3bpsdwBbD42xWgsppazw4z2osHrefDSaAxeFlZpOa7Bdx1yFvM6OeGu9knI5Hr1VF5XM2VE8S21lwyvYLhZprUvC/A5OhqrEX5shVx2blkluP8u5orTZ1e967qsjZnbuXrF8J9JgxywPlfWXB53DTVHD60lDVea0jitOy4GxJpC1aivwWVlZKtl7Kz2ySMlVr+dE387lVU6Idr4Laaw2n9ISz4bE5zDR5a7NkLFfUc8st58zlRiySLK97kVzY2u2Vd9lTdEVVQvSY1Zww0hryzBZ1JpjE52xAxY4pcjTjndG1V3VEVyLsm5ctvGBz72TtXK1cXo3UeBoXclmcDno7UFetj5b0atdDLHIsscKLIjeVyojmNcqOVnTZVVOV4HFR6px2EnpMu5fPv4o1c7qOl3NYprjHurry80EredkbWNhXtHdHKu+6b7J3m37Hrhxaw82Lj0hjcdTmnjsvbimLRessaPRj+eBWORWpI9EVF/KX4Tf6H4dad4b46elp3Gtx8NiXt53rI+aWeTZE5pJJHOe9dkRN3KvRCTTMyOUca5NQWuJFehcraxsaLkwyrUh0c2RjrGSWVyOZZmiVHRsSPs+Xnc2NeZ3MvTY5bwuz9zhbqXhO3N6b1FNfo6Au46zjqOLlsW4ZI71dqqsTU5lZuzZHIioqOYqeau59mmnl0jiZtXV9Tvqb5yvSkx0VrtH+bXe9kj2cu/Ku7o2Luqb9Oi7KpZp8bj5t0HoPUlfVvDzOXtPXsbDktbZ7UEtGSFXOxdexSnbCk6t3bG5y8q7KvvpNvHoZGc0jDFa4jz5zT+r2xv1xFkcRkdMUJJLdWRMdC3yyJqIvOzdHxuVGvRVcqKi7KqfUQGUQnBDJ6rzHDHD29a131tQv7VJUmgSCV8aSvSKSSJqqkb3Roxzmp4Kqpsngl2AZQMThn/AuR/ra9/qHlcSPDP8AgXI/1te/1DyuObtPxq/VZ1gAOZAAAAAAAAAAAAAAAAAAAAAAAAAAAAABO8Qb/dmkrlnvSHDcjok8tsV+3ZHvKxNlZ6ebfl+RXIvoKIneIN5cdpK5YblYcIrXRJ5dYg7Zke8rE2Vmy782/L8iuRfQUQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQqp2XEXOtf5qy0acjN/ymo6Zqqn6FTr8G6fChtzOzum6eoY4vKO1inhVVhs1pFjlj36ORHJ6F2TdF6LsnTom2lXh0xV/GHOfSmfUPSjFw64jNNptEatngy8JZgMP3OWesOd+lM+oPc5Z6w536Uz6hc+FvfSS0bWYDD9zlnrDnfpTPqD3OWesOd+lM+oM+FvfSS0bWYDD9zlnrDnfpTPqD3OWesOd+lM+oM+FvfSS0bWYDD9zlnrDnfpTPqEnorTtvO6i15Tt6iy6wYbNx0KnZ2Wc3ZLj6c68/m++7SeT4OnL+lWfC3vpJaNq4Bh+5yz1hzv0pn1B7nLPWHO/SmfUGfC3vpJaNrMBh+5yz1hzv0pn1B7nLPWHO/SmfUGfC3vpJaNrMBh+5yz1hzv0pn1B7nLPWHO/SmfUGfC3vpJaNrMBh+5yz1hzv0pn1Dy3hxVd5tjMZm3CvR0Mtzla5PSi8iNXb+0Z8He+haNrzwyTfT1uVOsc2TvSRu/lN8pkRFT5F23RfSmylaeuCCOrBHDDGyGGNqMZHG1Gta1E2RERPBET0HsOHFr7zEqr2yk+MgANSAAAAAAAAAAAAAAAAAAAAAAAAAAAAACe1/cShpO5O7KQYZGuiTy2zX7dke8rE2Vnp335U+BXIvoKEneIFxtDSdyd+Rr4lrXRJ5Xbr9vGzeVibKz0778qfAqovoKIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHPuGSNTWPFhWruq6nhV3yL3PjflX0bfB+j0r0E5/wy5vbjxX35NvbNFty8u+3c+N8duu++/j1229GwHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE7xAttpaSuTOyVfEta6JPLLVft42bysTZWenfflT4FVF9BRE9r/IJitKXLS5SLCox0SeWz1vKGR7ysTZWenm35fk5t/QUIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOecMGoms+LSo5HKuqIVVE383/sfGdF/69PhOhnPOF6Ims+LWyqqrqiFV+T/sbGAdDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANVqHPswNWJyQutW7EnY1qrF2WWTZV238GtREVVcvgiL4rsi5U0zXOWnWNqCIXN6xcqqlPBsRfyVsTO2/t5E3/8EHfWsfzbB/PTfVOrRa9sc2VluCI761j+bYP56b6o761j+bYP56b6o0WvbHMstwRHfWsfzbB/PTfVHfWsfzbB/PTfVGi17Y5lluCI761j+bYP56b6o761j+bYP56b6o0WvbHMs4d7NH2Wec9jjNicbT0c3KVMxXSWDNSXkYyOaOVO1hWFYXo7zORUdzJ++eHm9etexz4wZHjtwwp6xv6YXSkd6aRKlRbvlSywt2RJebs2bbu50228Gou/XpFeyC4PZT2RGg/aznIsRUbHZjtV7teSVZIXtXZdt2+Dmq5qp8qL6ELzT8epNL4LH4fG4/A1sfQrsrV4WzTbMjY1GtT3vwINFr2xzLOjgiO+tY/m2D+em+qO+tY/m2D+em+qNFr2xzLLcER31rH82wfz031R31rH82wfz031Rote2OZZbgiO+tY/m2D+em+qO+tY/m2D+em+qNFr2xzLLcER31rH82wfz031T9N1Lqej+GuYzH26zesjKE8nbcvpVjXN2cvj03TfbxGi1+UxzgstQY9C9BlKNe5VlSatYjbLFI3wc1ybov8A4KZByTExNpYgAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANFqLUkmLngo0azb2VnY6VkMkixxsY1URXyPRF5U3VERERVVfBNkcrdKua1juu1XB7ejeab6p00dnrrjN4R6ytluCI761j+bYP56b6o761j+bYP56b6pnote2Oa2W4IjvrWP5tg/npvqjvrWP5tg/npvqjRa9scyy3BEd9ax/NsH89N9Ud9ax/NsH89N9UaLXtjmWW4IjvrWP5tg/npvqjvrWP5tg/npvqjRa9scyzbcQtQ5PSeiM1msPh01BkcfVfZixi2FgWzypu5iPRj9ncqLt5q7rsnTfc+QvYm+zTt8Y+Nmb05X4fvx0WobsmYt3kynbJj2xUIIEa5qV28/M6sxN1cip2u3XlRF+p++tY/m2D+em+qcj4N8AJuCOsNZ6iwNPDLa1JZ7ZY3vkRtOLdXLDFsz3nOqr1+BqejdWi17Y5ln0mCI761j+bYP56b6o761j+bYP56b6o0WvbHMstwRHfWsfzbB/PTfVHfWsfzbB/PTfVGi17Y5lluCI761j+bYP56b6o761j+bYP56b6o0WvbHMstwRHfWsfzbB/PTfVHfWsfzbB/PTfVGi17Y5lluCI761j+bYP56b6p+o9Q6qqr2lnGYy3C3q+KnZe2VU9PJzt5VX4EVWovwoNFr2xzhLLUGLi8nWzOOrXqkna1rEaSRv2VFVF+FF6ovwovVF6KZRyTExNpQABAAAAAAAAAAAAAACM1p+NmlE9HNaX+3sk/apZkZrP8bdKfptf5SHX2X4v7Vf9ZWGwAB0IAAAAAAAAAH4mmZXhklkXljY1XOXbfZE6qB+warSuqMZrXTmOz2Fs+WYnIwNs1bHZuj7SNybo7lciOT9CoimDW4i6btRXpUy0EUdLKJhZnWEdCiXVVjUhbzonO5VkYicu6Kq9FUlxRgGnXV2JTV6aX8r/AO3Vorkkq9m//Z0kSNX8+3L79UTbff07bAbgAwcpnMfhFppkLsFNblhtSsk8iNWaZyKrY2b++cqNcuyddkVfQUZwAA9HC1d+H2D+SuiJ+jdSqJXhb/F9g/8AuP8A7qVRydp+PX6z91nXIADnQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDX134m20+DD19vnp/2IbY1N7+M65/U9f/OnNsetVqp9I+zKQAGDEBgrnMe3Nsw63YO9X13W0pdonarCjkasnL48vM5E38N1M5V2TcADU6V1Ti9baepZzC2VuYu6xZIJ1jfHzt3VN+V6I5OqL4ohtiAACgAaeDV2Js6st6Zjt82bqU4r81Xs3pyQSPexj+bblXd0b02Rd026p1Qg3AAKAAAAAAD0ZC/WxVCzdu2IqlOtE6aexO9GRxRtRVc5zl6IiIiqqr4Ih5pXIMjTgt1ZWz1p42yxSsXdr2OTdHIvwKiooHuAAGNwuXfRVT5J7SJ+hLEhWEnwt/Eqr/SLf+plKw5e0/Hr9Z+6zrkABzIAAAAAAAAAAAAABGaz/G3Sn6bX+UhZkZrP8bdKfptf5SHX2X4v7Vf9ZWGwOWeyBzLa2BwmEruzj8znck2nj62AyPd8070jfI5JLGyrHEjGOc5W+d5qIiKdTJ3W/D/AcRsXBj9QUVu14J22oHRzyQSwytRUR8csbmvY7ZVTdrk6KqeCm+fGEfLtLVWtYuHWR0/kNQZTH5LG8SsdgGXYcotu1FUmfWc6JbLo2rNt2705ns6psiouxVZfDa2hzXFbh/o3U+Vmnix2IymMkyuUkksQrLLKlmGO1JzPZ2jINmqu/I526bejrWO4B6CxFeSClgG1oZMhUyr447U6NfbrKjoZ1Tn6vRURXKvv1Tz+Y2Go+Eek9W2c1YyuKWzPma9areelmaNZY68jpIETlenIrHuVyObsu+26rshryyOBS8SItE6X0/rGDKatrY3SWpJcTq3EajvvtTVo7ETY17RyOckzY5HV5I37u6PdsqbqhiaS4ia/1FmtN8O9RWbuN1HmszDqh89aV8bocE9rrbq3aJsqKyZnkqoi+9VE8FPoXF8HNG4bR1/StbBwrgr8rp7laeSSZ1mRVaqvlke5Xvd5rernKvmonoKGTTeMm1HXzz6Ua5ivVkpR3NvPbA97HvZ+hXRsX5Nuniu9yyPk7huvF/ivgMdr7E3vJshcyLpt7Gq5m0oYmWVY+q/GpUWNNmNczfn5+bzuffodO4MYe/qnXvETN5XUuetR4fV9unj8Z3lK2pDGleFVa6NHIj27ybox27Wq1FaiKrt7SLgFoKvrB2p4cA2DLutpfc6G1OyB1nx7ZYEekSyb9efk33677m8g0bFprH59dKMq4vKZe4/JTT3WS2oX2ntY10jo+0auytjanK1zU6fp3RTMaxuczekxmHvXIoVsy14JJWQt8ZFa1VRqfp22OG8EtN3NXcOcDxHy2tdQ5bM5fHPv2ajMi5uMRZY3fgG1U8xrY1XZNvO5mdVXqh0PGYzibHkarshqPSdig2Vq2Iq2n7UUr49/ORj3XXI1ypvsqtciL6F8DHxPsftAYHUbs5jsAlO+ssk7Ww252145JGua97IOfsmOcj3Iqtai+cpfGZuOA8HKOT4faD9j5nqOp85aZqGeviL+KuXFkorBJTnkakcOyNjWN0LNnNRHL15ldua/UuHlzXD29jslns/cgxfFytja9ixmbLp46/lNdiN7VX83mo5Vau/mu85Nl6n1LV4VaWp4TSuIhxfJjtLzx2cRD5RKvk0jI3xsdurt37Mkemz1cnXdeqIeq7wg0hktPZ/B2sNHPis9efkshXkmkXtbLla5ZUdzczHbsYqcit2VqKmxjlm1hzbUeLuZ7jNhOGLdT5/Dabx2mVzCyUspKy/kZlsdijZLSqsrmxtTmXZyKqyN3VUQ02Y4Zty/sjMTp5+qdTV4Kmh3q6/Vybor1ja+iIkk7UR67K7foqbq1N903RepZfgJobO4TDYq9h5bEGHWR1CwuQspbr86qr9rKSJNs5V6or1RenwIbbTXCzS+kMlSv4jFpTt08cuKgkSeV/LWWXtVZs5yoqrJ53Mu7vlLlHztiNY5viNw34dafW9qTL6ztplFV+Kzi4dksFO06sti1YYxzt+kezWNXmc5yqmxp7K5Hibwk4Iz6oy2UdlYddyYee3TycsMj2skuRNeskSs5pUSFiJLsjur1Tbnci/RNz2P+gruHxOMkwbmVcVLZmpOgvWYpYVsSOknRJWSI9Wve5VViuVq9E22RET2u4D6DXRk+k26ehi09Ld7wSjDNLG2CxzI7tIVa9HQqipuiRq1E3XbxXeZZ8xa42izF46rTjkmmjrxMhbJZmdNK5GoiIr3uVXPcu3VyqqqvVTJMHB4WppzEVMZQZJHTqxpFE2WZ8rkanwvequcvyqqqZxsHo4W/wAX2D/7j/7qVRK8Lf4vsH/3H/3Uqjl7T8ev1n7rOuQAHOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGvfxnXP6nr/505tjU3v4zrn9T1/8AOnNsetVqp9I+zKXEuLtTJah468NdOxahzGFw13G5ia/BibslVbSR+S8iK5iorVRXrs5NnIiuRFTmU51fg4hcRtf67xGBvXoa2k54MTj2pq+fGyQJ5NG9tiaNtaXylXucruaVyoqN25eiuX6avaRxOS1PitQ2anaZjFwz16lntHp2Uc3J2qcqLyrzdmzqqKqbdNt1JnWnAfQvEHOLmM5gW2ck+FK808FqestiJPBkyRPakrU+B6OTboaJpmWLkuJ0PfyfsmtLSaqyt9upYdCxW764jK2IK0tqK3E16NY1zUWFzt1WNW8rt91aqm34QaUua+yfEXI5vVmp5m1tVZfGUqlbM2K8NWv7zla1jk3VOdVaq78itarOVU3XqWruEulNc38TezGLWa7ikVtOzXtTVpImrtuzmie1XMXlbu127engbfTekcTpFuSbiankiZK9NkrSdo9/aWJV3kf5yrtuqeCbInoRC5fEfIOjdZ684gae4R6Tq5G9dde0vPmrliTUc2LtZCZlhIkatxsUsjuRqq5WN5VdzIqu2bst7PNr7g5hdLas1tnZH4nD52alkYWZOS5GmItI2OGWzIscaSywT8v4RY9+RV3Xqp1e9wA0DkdJ4LTc2ATuvBb92dnbnjnp7+PZ2GvSVN/T5/XpvvshuoOGOmK+g5tFtxETtMzQyQSUJHvej2SKrn7ucquVVc5yq7ffdd99zGKZHzPc1DxBzScP8Qy5fjs8QJ8pqOarLnZcZJFA1I3VaMNhsUroUZC9r3MY1qq5ruqbu37vwPwGt9N4jL09Y2o7MXlvPi2uyb8jYhrqxu8cth0MSybPR6oqt32ciKq7blHrjhppniPia2N1Dio79WrK2esrXvhkryImyOikjVr4126btVOnQ07OH+U0VhqWJ4dWcNgKDHyy2WZmlZyL5XvVF5kf5TG7ffm3VyuVd08NutiJibjUeyL1NlcDpXT+PxOSkwk2otQUcHNlodu1pQzOXnkjVd0R6o3kaqp0V6L4ohwzXneXAvV/FW1p/O5a9fi0lh+wyOdtuvTVO2vzQuk55N1VrEc6REduiLv6OifRTtB5fWmEymD4jzad1Ng7kbW+R4/FT1POR3NzOc+zKu6KiKit5VRU33PzpzgJoTSve3kGC5+96Tcdf8utz3PKa6c20b+2e/dPPcm/jtsm+yIiJiZ8RxLinqXP+xry1iLT2o83qpl3SWUyMlbP3XX3VbNXseytIr+rWu7V6OYmzF5eiJsV2oND3NC8DNZ6op681VnMw/SN2dLdnLySQunWssjbEDE6QuRU3b2fKiIvpXZToujeB+iNBSXpMPgmMlvVkpzyXLEtxzq/8wizPerYuv72mzfkPRpPgFoLRFqxPh8CldZ60lN0M1ueeFsEior4mRSPcxjHcqbtaiJ0QZZENqLU+Ui1TwPhhy1xkWSxeRltxssvRtpW45r2ukRF89UcvMirvsq7+JzPRuOzmU07wCvWNeawfY1ixa2ZXvqXaeNKUk7UanhG5FianaM5XqiuVXK5eY+gNP8AsedAaXy2NyeOwb472NjlgpzTZCzMteKRixujYj5HI1nKqojE81u+6Ii9TdY/hVpbFUtJ1KuL7KvpRVXDM8olXyXeJ0Pirt3+Y9yefzeO/j1GWfMfNGT13rPHY2TQmMzN652vEO1puHJ38q6va8kbTZaZXW6scr2vc96sSTlc9UTZFRV5k2mq8XxQ4f8AD7NtyWet4mhZzWDixUkGoJcpeqK+7HHZRbMsEauY5rmbMej098i7oux3vJ8GdGZrD53F3sFDbo5vILlr0cssjlfb5WN7ZrubeNyJGxEVit226bbrvj0OBuisbpubAw4d642a9Dk5WzXrEsklmJ7HxSOlfIsjlasUfRXbbNRFTboTLI4nxFxdvBM41aGXPZ7J4NdBpnoEyGUmnngn3tMe1kznc/Zv7FnNGq8qpzJtyuVDY5Lh9qWjwb4ev0lkNTZTERMiyOaxtHUEseStwvqNRra1iR+7WsfyuSFHNa7qibKvXvU+hsFa1Ffzs+PZNk7+ObibMsj3ObLVa570iWNV5Nt5X9dt15tlVU2IxvsaOHTMHXw7MLajx9eZZ4I2Ze610LlZyKjHpNzMby9ORqo3b0Fyio4X53Ham4d6cymIvXcljbNGJ0NvJLvalTlRN5l2TeTdF5vl3KgwMBgMdpbCUcPiakVDGUYWwV60KbMjY1NkRDPM4GNwt/Eqr/SLf+plKwk+Fv4lVf6Rb/1MpWHN2n49frP3WdcgAOZAAAAAAAAAAAAAAIzWf426U/Ta/wApCzNFqrBT5ZlO1SdG3I0JFmgbM5Wxy7sVro3qiKqIqL75EXZUauy7bL09nqijEiZ4xziYWHpBpVyOomrsukbjlT0x3KytX9G8iL/5IO89Q+p9/wCmVftTuyfNHujqtm6Bpe89Q+p9/wCmVftR3nqH1Pv/AEyr9qMnzR7o6lm6Bpe89Q+p9/6ZV+1HeeofU+/9Mq/ajJ80e6OpZugaXvPUPqff+mVftR3nqH1Pv/TKv2oyfNHujqWboEnqLWuS0ph58pk9K5CvShVjXyJZrP2Vz0Y3o2RV985E/tNl3nqH1Pv/AEyr9qMnzR7o6lm6Bpe89Q+p9/6ZV+1HeeofU+/9Mq/ajJ80e6OpZugaXvPUPqff+mVftR3nqH1Pv/TKv2oyfNHujqWboGl7z1D6n3/plX7Ud56h9T7/ANMq/ajJ80e6OpZugaXvPUPqff8AplX7U/TJdS5D8DDp92Me/p5VetRPZF/xcsbnK5U8Ub03VNuZu+6MltdUc46pZseFv8X2D/7j/wC6lUYODxEOAw9LG11e6CrC2FrpF3c5ETbdy+lV8V+VTOPOxqorxKq41TMk+MgANKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABjZDI1MTTnt3rUNOpBG6WWexIkccbGpu5znL0RETxVfADJBOS6+xLkttorZzEsFJl9I8bXfMk0T+rOzkROzcrkVFREdvt18Op4t5jUVqC43F4CKKZtaKSrJlriRRySPXz2OSJJHN5E8V22VeidPOQKQE5kcJqDKty0C6kTE17DYW0pcVSYlqordllVXz9rHIr13RN4k5U9Dl8485HQeIzTsumTZYylbJuhdPSu2pJazey25EjiV3IxN03dyonMvvt9k2DRWbcFjilko4po5ZIMTWZKxjkVY3drMuzk9C7Ki7L6FQ3hi53S0lXLuzmEqV3XpGLHbrdIvKk6crufb37dtkV3iiqm6dFTXrktQoqp7ULy/Klur1//dPWptiU0zExqiPGYjV6sp8W6Bpe89Q+p9/6ZV+1HeeofU+/9Mq/alyfNHujqWboGl7z1D6n3/plX7Ud56h9T7/0yr9qMnzR7o6lm6Bpe89Q+p9/6ZV+1HeeofU+/wDTKv2oyfNHujqWboGl7z1D6n3/AKZV+1HeeofU+/8ATKv2oyfNHujqWboGl7z1D6n3/plX7Uw6OqM1kbOQgh0dlEkozpXm7SauxqvWNknmK6REe3lkb5zd035m77tVEZPmj3R1LKYGl7z1D6n3/plX7U5/xH9kdhOEecw2J1fjreCtZdHLTdYlhWJ/KqIvNIj1Yzq5PfKgyfNHujqWdaBPUdQ5jKU4bdPS9q3UmYkkU8F+m9kjV8Fa5JdlRfhQ9/eeofU+/wDTKv2oyfNHujqWboGl7z1D6n3/AKZV+1HeeofU+/8ATKv2oyfNHujqWboGl7z1D6n3/plX7Ud56h9T7/0yr9qMnzR7o6lm6Bpe89Q+p9/6ZV+1P0yzqW4vZRabfRe7ok963CsbP+JUje5ztvgTbf4U8Rk+aPdHVLM/hb+JVX+kW/8AUylYa7T2Fj09hamOikdK2BmyyP8AfPcq7ucvyqqqv9psTzsaqK8WqqNUzJPjIADSgAAAAAAAAAAAAAAAAAAAAAAAAAAOfce0VeFWY2Tde0q+jf8A95i+RToJz3j83m4UZhF3X8LU8E3X/aojoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANfe1Di8Zeo0rmRq1rt+R0NStLM1slh6N53NY1V3cqN85UTwTr4AbAE7j9YOzXdUuOwuVno3XzNkt2a/kaVUj32dJFOrJdnqmzeVjt/Fdm7Kv5ox6ryEeOlvS4rDKsMyXaVRJLjkkXpEsVh3Zps1OruaFeZeibIm6hSGtv6kxOLuMp28lVguyQyWI6r5W9tJGxN3vazfmcjfSqIuxrquio9qT8nlcpmrNerJVfJZs9kywj/fvkhhRkTnbdEXk81PDbdd9nh9PYvT1OtUxeOq4+tWiSCGKtC2NscaLujGoidE367fCBrK+s25PyN2MxOUvQW6j7cVl1Za8abe9Y/tuRzXOXwTl8Oq7J1EE2qcg2s91fG4ZktJ6yse99qWC0vvETbka5jfFeqKq9E28SjAE2mkrd2NG5TUOStpJjVoWIaj0pxPe5d32GLEiSxyr4IrZdmp73Z27lyqmi8FSuMuMxdZ99tJmO8tnZ2th1Zq7tidK/d7m79dlVd16ruvU3QAAAAAAAAAAAAAAAAAAAAaDTUvaZjVTe1yknZ5NjeXIM5YWfuSsu1VdvOh67qvX8Ksyb9Nk35O6We52a1civyz0blGIiZFm0LU8iqrtUX0w9VVV/nVmT0AUR8wezZ9i7m/ZLO4fVsLaq49lDITR5C7Y6+TVZGIrpUZ0WRUWJGoxFTd0jd1a3mc36fAHIvY18GtPcCtFzaVwt3KZC5TkazJ2cjJO1k9jlR/awwvcscbFR6IixJsqMRrnPexynXTRakr2ar4MzRiu37dFj40xta0kUdmORzOfma/zHPajOZiqrVRUVvM1r377tj2yMa5qo5rk3RU8FQD9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA55x/VE4T5hV/nano3/96iOhnPePvN7lGY5Vcju0q+98f9qiOhAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACWdO7XsF2KlkOx089j6q3cfLJFcfYZM5kzWP2RGMb2at52KrnK9VarORHPDZZfVeNwq8k00k0/bRQLWpwvszI+RV5OaONHOai7KvMqI1EaqqqIiqmK+9qHISIlTGwYuOHJdlK/JSJI6em1E5pYmxOXZzl6NR6oqJ5zm7+abepjKdCe1NWqwV5rcna2JIo0a6Z/KjUc9U6uXlaibr6ERPQZQE/FpSWaeCbJZrJX5K92S5C1kvksbUXoyJzYeXtI2J4JJzbr1Xfptn4TTmK03VWticbVxsDpHzOjqwtjR0j3cz3rsnVzndVVeqr1U2IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABO6XVFzWrdp8nMqZRm7L/AO8xfuOt5tb/AOF+Uv8A8V0xRE7pabtc1q5vlGSm7PKMbyXmcsUX7iqry1l/Ki68yr/OOlT0AUQAAEzomuzDMyWCiq0aNTG2OWlXpz8+1Z7UexXMVd4/PWVqN8NmJy7J0SmJ1jW1OIEnLFjInX8YiukRyNvTLDLsiKn5UTO38fyXSf8AEgFEAAAAAAAAAAAAAAAAAAAAAAE9f4h6YxdqWtaz+OhsROVkkTrLeZjk8WuTfovyKZ0UV4k2oi/otr6lCCW91PSHrJjfpDR7qekPWTG/SGm3RsbcnlK5Z2KkEt7qekPWTG/SGj3U9IesmN+kNGjY25PKTLOxUglvdT0h6yY36Q0e6npD1kxv0ho0bG3J5SZZ2KkEt7qekPWTG/SGj3U9IesmN+kNGjY25PKTLOxUglvdT0h6yY36Q0e6npD1kxv0ho0bG3J5SZZ2KkEt7qekPWTG/SGj3U9IesmN+kNGjY25PKTLOxD+yV19pbAaByWHy2pMRjMrOlWeKhcvRRTyR+VM89sbnI5W+Y/qnTzXfAp0rTOr8FrWg+9p7N47PUo5FhfZxluOzG2RERVYrmKqI5Ec1dvHZU+E+LP/AEiPDzA8Y9JYbU2lcjRyWqsPKlV9avK10tmpI7wRPFezevNt8D3r6Du/sdKOhuBfCHAaTg1FiltQRdtfmZYb+GtP6yu39PXzUX+S1o0bG3J5SZZ2O5glvdT0h6yY36Q0e6npD1kxv0ho0bG3J5SZZ2KkEt7qekPWTG/SGj3U9IesmN+kNGjY25PKTLOxUglvdT0h6yY36Q0e6npD1kxv0ho0bG3J5SZZ2KkEt7qekPWTG/SGj3U9IesmN+kNGjY25PKTLOxUglvdT0h6yY36Q0e6npD1kxv0ho0bG3J5SZZ2KkEt7qekPWTG/SGj3U9IesmN+kNGjY25PKTLOxUg1GF1dhNRySR4vLUshLG3mfHXna97W77bq1F3RN/Sbc01U1UTaqLSx1AAMQAAAAAAAAB+XvbGxz3uRrWpurlXZET4Sak4n6RjcrV1JjFVOm7bLFT4PFFNlGHXifopmfRbTOpTglvdT0h6yY36Q0e6npD1kxv0hps0bG3J5SuWdipBLe6npD1kxv0ho91PSHrJjfpDRo2NuTykyzsVIJb3U9IesmN+kNHup6Q9ZMb9IaNGxtyeUmWdjZam1hgdFUI72oc3jsDSklSBlnJ2460bpFRXIxHPVEVyo1y7eOzV+AleEnE/TOtsNUpY3XWF1hmI4XzTux80TJXMR+3OsDV5mNTma3dUROqfChDeyWxmiOPHBzPaVfqHFJfkj8pxsz7DfwVuNFWNd9+iL1Yq/wAl7ji//o8tA6f4NaGyeotTZGjjtV5uVYvJ7ErWy1qsa+a1UXqivciuVPgRijRsbcnlJlnY+4gS3up6Q9ZMb9IaPdT0h6yY36Q0aNjbk8pMs7FSCW91PSHrJjfpDR7qekPWTG/SGjRsbcnlJlnYqQS3up6Q9ZMb9IaPdT0h6yY36Q0aNjbk8pMs7FSCWbxR0i5yImo8cqr0REsNN/jcpTzNOO3QtwXqsnvJ68iSMd+hyLsphXhYmHF66Zj1hLTDKABqQAAAAAAAAAAAAAAAAAAAAACd0tN2ua1c3yjJTdnlGN5LzOWKL9xVV5ay/lRdeZV/nHSp6CiJ3S03a5rVze3yU3Z5RjeS+zlii/cVVeWsv5UXXmVf5x0qegCiAAAnMs10eudPTNgxa81a5A6xYVEutR3Yv5IPhY5Y0V6f8Ea+goyd1BE5dT6XlbDi3o2xOx0t1drLEWB6/ub4XKrU5k/kI5fQBRAAAAAAAAAAAAAAAAAAAAAJviHfmx2kL0leV8Er3RQJLGuzmJJKyNVRU6ouzl2VOqHqp04MfVirVoWQV4mo1kcabNanwIh+OKX4l2P6TU/1MRknpYXwI9Z+0L5AAKgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACf1s5KWGXKRJyXcfIyaCZvRzV5kRyb/A5qq1U8FRToZzriF+JuT/5G/wCNp0U19o+HRPGfwvkAA4EAAAAAAAASGv3+UWNP4yTzqd665tiJfCVjIJHox3/CrmtVU8FRNlRUVTMRNk2Tohga6/GDSH9Nm/0spnnp0+GFR6T95WdUAACAAAAAAAAAAAAAAAABqsa5MdxCrQwfg48lQsTWGNTZr5InwNY9f+Llkc1V23VOXdfNRDamoj/jKwX9WX/8yqZ0+MVRwn7XWF0ADyUAAAAAAAAAAAAAAAAAAAAAAnNLWEmzWr2JdvWuyyrGLFbj5Y637iqu7OBfyo/O51X+XJInoKMntLz9rmdWt8pyFjssoxnZ3Y+WKH9x1l5K6/lRdeZV/nHyp6AKEAACc1NFz6g0i/scZIrMjL595/LPHvTsdayemVfBU/m1lX0FGTup4ufOaQd5PjZuTKSLz3n8s0X7itJzVk/Kl68qp/NumX0AUQAAAAAAAAAAAAAAAAAAAACT4pfiXY/pNT/UxGSY3FL8S7H9Jqf6mIyT0sL4Ees/alfJodd60xnDnR2Y1NmHvjxuLruszdm3me5E8GtT0uVdkRPhVDkPEbiFr+3wS4gZHJaQl0N2WnLVyhkK2bbNailSNVa1zWMasUiIu+7XOROXx32OocV+H9fipw6z+lLNl9KPKVlhbZjbzLC9FRzH7dN+VzWrtum+226EBn9HcWNfcNtWaW1LLpCN2SwdjH17WOktbzWXt5WyyI5m0TNubdrUeu6psvTZcZuj3aO4x6knyuO03m9GOxWWyODlyeEknyzJm5B0LY0fFM5rF7B+8sart2ibOVd1VNl5vg+LmuH6f4JP0xQfeiz9/Jst1c7nu1msOjZackMlnyZV5G8iva5GovmMZtt5x2a7w3ydjiRw61A2eolLTmKv0bcavd2j3ztrIxY05dlanYv33VF6psi9doPGcB9X6a4e8NYcVcwsuq9G5O1dSO3LMlGzHP5Qx7O0aznavJOiovIvVqptt1MfH/79hWZfjHqGzrDK6b0holNT3sHFA7MTS5ZlKCvLKztGwRPdG5ZX8io5ejWoit3VFXYh7vFTWmlOLfFiShpu1qrF4qljLs1OXMNgjoM8me+VsDHI5HSO2Vdmo1F5Ort1TejZw/4laR1jntQ6Un0tOuqI61jK0MvJZbHTvRwNidJXfGxVkjcjW+a9Gr5u+6bqht6nC3Nt1FxTydmzQd7bMbTqVUic9OzliqyRPV6K3zWq56KmyuXbx6l8ZGu4jeyFn0fpnBalxeCx2S0/lMczJR28rqGvi3va9iPbFFHIjlkk5VRdt0Tqib7ml1Txk1dltfcIpdEY2rkNO6pw9vKeS38h5I6x+Cie1JFSCRWdm2RFTZV5leqKiciKuvp+x61hg34KSlLpjIzs0bR0tamy6TSd2vhY5sk1REZ+Ea/m3VrljVeRvnJ4JsqfBfW+nNN8Ip8RZwE+pdDUZ8XNXuzTtp24JImRc7ZGxq9r0SGN23Jturk36Iqz/KR345Xn+MGdm1vmdM6K0YurLGCZCuVs2MmyhDDJKznZDGrmP7STk2cqea1OZu7kVTZSccNO0ZHVrkGoPLIVWObybS2Vli506O5HpWVHN3RdlToqdSUj0frjEayz+ruHdjB2cTrBle7Zo6oitVJalhkLYkkY1rOZUcxrOaORGKit8U3VDKZ2Dxxg9kda4NZJr8xpygmDZHFLLYk1FXivPau3aLBTcnNNyKq7+c1V5V2RT2Wdf65//qffpijjqN3SiYCrdVsuR7JzGvsuZJaRqQOVz05VYkSvRqoxHcyK5USV4g+x31pqibiRWp2NLSRa1gj7XL5Fk7rtJWV2R+TxsRqosXMxVa7nRWdo5eV6p1uMhoDWtPifg9aYZ2BlmkwMODzNG9PM1saMm7XtK72xqr13fImz2t3TlXdPAnjcROV9mzp7HZK5YZXxM+mqd51GW0uo6rMk7ll7J80ePXz3Ro7dU3cjnNTmRuypvutY+yVymDfnr2J0Y3J6XwmaiwF3NWcoldWWnSRxPVIUje50THytart9999mqiKp7+H/AAr13wwst07iH6VyOh2ZOS1BayLJ+8a9aWZZZIORreR7kV70bIr023Tdq7bHDuJGZp6O4y6p83G6lryZyvkl0PVyl+tPcstSLlkbT8mdHNLzNa9XJL2blaiqiKimMzVEeI7rqT2Rl/Fy6syWK0XPmtHaTtPp5nMtyDIpWviRrrCwV1aqypEjvOVXs3VrkTfY21fjNmM/xPy2ktOaUiytXGQY+5PmJ8p5PCkFpHO3RvZOcr0Rqq1qdHIjt3M6IspqTghrpaWvdK6dymCg0drS7YuW7d5JvL6CWmoltkUbW9nKjvPVquczl51332QvOH/DGzoniNrDMNkrrh8pRxVKjCx7nTRpUilY7tEVqIm/O3bZV32XfYy8biJ0HxH1tZwOqruK0kzK5Grqe9VyFTMas2hpdmyL94lWr0h6rtHypy9V3XfphQey2fW4e4PUGb03jsHkNRXp6+FqW9QRxVbNeJN3W5LUsUaRRL+T5rnORzFRF5un51dwS4hzaJ1hp/AWsB2Wp9V2cte8rvWIFfjZOz3rI5kLla+TkVr1TojVVEVVXps83wu4hajTSefdX0fhdU6SsTR43HVZ7FjGWaU0LY5YZVWFj43eY1Wq1rkTkTou/Sf5Cv4K8bKHGKrm2QQ1a+Rw1lle3Hj8jFkKrudiPY+KxH5r2qm6eDVRWuRUTY9PsltU3dGcFdTZelVtWUr11Wd1DKLjrMMX5UkMyRSbPTpsnL6fEzKOsbugcJDJrurBFkrk8ixxaRxN/IQxxtRuzXujhc7m6r5zmsRd9kTopoOJFyr7ILhbrDRmmHXqmVv490ccucw1/H12qrk8XywJv+hqKvyGV/C3mPxqfjlnsNqLWmHwmie/otIVK9y9bmy7a6yRSQLLtG1Y3K6TZj/NXZq7dXIqohqJ+LusM5xs0XV0xjamQ0lmtKuzLYLmQ8mc5j5q34ddoHrzxskREj5tnc7lVW7JvVN4W5VNUcWMl5RT7DVmPqVKLed/NG+KtJE5ZfN2ROZ6KnKrum/h4E3U4Pa10i7hlldO2MDazWnNMJprJVcnNMyvMxW11WSGRkau3R8HRHNTdHfkqSbjU6x9mbg9MZvPxV6mJu4nA2pKl6SbUdWtkJHxrtN5NSf58qNXdE3cxXq1Uai9FXeag9kVlqeQ1z3HopM7idIQwXLt92VbXWatJUZa5oY1jcrpEa53mKrUVGp527uVGA4Wa74e6hzlTTUmlcjpTLZiXLo/NMnS7RWd6PniY1jVbK3m5lYquaqc3XfY2lzhFl57XGqRlii1mtascGORXv8AwKtx6Vl7bzPNTnTfzebzfl6D/IaZ3FLWOV9kJg8VgcfTyGj7+mI8qjLGQ8nckcliJHWdkgcqva13KkXMiORVXmap3U4pX4Uaw0vqfQufwFjCWrWM01HprK1cjLMyNY2uif2sD2MVVcjo3JyuRqKip1Q7WZRfzE7xC/E3J/8AI3/G06Kc64hfibk/+Rv+Np0UnaPhUes/alfIAB56AAAAAAAAI3XX4waQ/ps3+llM8wNdfjBpD+mzf6WUzz1I+HR6fmVnyTXEPU9/R2lbWWx2Mr5WeBWq6G5kY6ELGKvnPfM9FRrWp1Xoq/AhynH+ysr5Dhtl9SQ6fZdyOJzdTCWcbjctDailfPJC1kkFlqckjVbMipvy9Wq1eXxLPjlw5yfEfBYKPFLjp7WIzNfLd35hXpSvJG16dlKrGuVE3ej0XlcnMxu6Kc5k9j/rTI0tYpes6cisZ/UGGzrGUXTRxV0qyQ9tDsrFVfMgZyv6c7nO3axDVN7+CN/nPZIXNE47Wyaq0g7HZnTePq5RtKjkW2ordeeV0THpKsbOTle1yP3bs1EVUVyG5g4yZrHLo12o9KVsVV1FllxTbdLMsuwxK6BZK8jXNjbztlc10fXl2VEXzkch51Nw81O/iZqTVuDdg5lvaaqYetVy6yujdLHamkkSVrG/vbo5dkVFVd9927J1iKPsac3Pwi1vpye7i9P5LM5NuXw9TBvlWjg7EfZPiWBzmtcm8kXO7la1E512T4X+Qoq3sn8RmdP5K7hMc/I5CvqiPS9Wg+fsvK5ZJWtZO1/Ku0axq+VF2XpG79JL5X2bOnsdkrlhlfEz6ap3nUZbS6jqsyTuWXsnzR49fPdGjt1TdyOc1OZG7Km9XjvY1YnBcTtD6ixk3k+K03iPIHY9VXaxPExYqs7k8Fc2Oe0iuXru5u3p2xeH/CvXfDCy3TuIfpXI6HZk5LUFrIsn7xr1pZllkg5Gt5HuRXvRsivTbdN2rtsT/IUGmeLme1fxE1Lp3G6Qj7s09lG4+7mLGURiOa6FkqOiiSJVc9OfZWKrUROVeZd1ROnvfyMc5UVURN9mpupzvRml7HDO/wASc9lpWTUcxmVy8DMfFNZmZClWCLldGxiuV/NE5eViO6Knp6Jk0uNumsjcgqV4NRJPPI2KPttLZSJnM5dk5nurI1qbr1cqoieKqZxNtYiNK+ye724bZjiHmdNsw2jKlZ88FuLKxWbEj0kSNsEsKNb2MrlVE5VcqIq7K5Bw69lDW1vrCHTU+Pw7cpdpz26DcFqWrlmyLEiK6GZY0TsXqioqb7tXZ2zuhL5P2MOp+IOR1Xb1JZ05peTM4hKUi6TbMrLtxlmOeG7YjkRqc0bokRE85yo9yK/Y6BU0bxF1RpXUeD1VLpbDeX4efH18hppJ3TpPIxWduvaNYjERFVeROZd/yuhhGYYXDn2RjtX8QJ9HZfC47E5dKU12FuLz8GUaiROa2SKbs2osMqc7V5VRUVObZ3QwNNeyayGT4UwcQ8tol+KwN2vEmOrw5JLN27bklbFHAyLs2ojXPd0er0XZN1aiGLoTgnrLCay0Nlb9bSGLxuncVaw7qODWdFkZLGzadHOjaiuV8LPwaomyOevO5ehsqfAHKv8AY3aY0FPlKtLU2BZTs1cjXa6avHcrSpLG7ZyNVzFVuy7oi7Ko/wAhquNOv9f1eCGp8jktMy6MyNWzi3VJMTnG2ZZ0ffhbJGj2tjVjuVeVUXzVR+3Mqbl/oPinlM/rfJ6R1LpddL5ytRiyleOO+y7FYqve6Pm52tbyva9uzm7L4oqKqdSa1lobidxP4c5vAai9qdC3PPj5andc9p8e8NuOaZ0j3xoqczY0RrUauy+LlRd0sE0HkE46O1p21butdNph+x5ndv2yWll5tuXl5OVdt+bff0ekvjcXZqI/4ysF/Vl//Mqm3NRH/GVgv6sv/wCZVN9Hn6T9pWF0ADyUAAAAAAAAAAAAAAAAAAAAAAndL2VnzWrmLYyM3Y5RjEZdjRsUX7irO5a6/lRedzKv846VPQURO6WxvkOa1dN3O3GeWZRk/lLbXbLkNqVWPt1b/ulTs+x5PT2CP/LAogAAJ3U8CzZrSL0rY2fsso96vvP5ZYf3Fabz1k9Mvncqp/NvlX0FETuqIe1zekHeTY6fs8o9/Pefyyw/uK0nPWT8qXryqn826VfQBRAAAAAAAAAAAAAAAAAAAAAJPil+Jdj+k1P9TEZJ54g4+fJ6Ruw1onTzMdFO2Jnvn9nKyRWp8KqjVREMWhkquTrMsVZ2TwvTdHNX/wAlT0L8i9UPSwvHAj1n7QvkyQeOZPhQcyfChUeQeOZPhQcyfCgHkHjmT4UHMnwoB5B45k+FBzJ8KAeQeOZPhQcyfCgHkHjmT4UHMnwoB5B45k+FBzJ8KAeQeOZPhQcyfCgHkHjmT4UHMnwoB5B45k+FBzJ8KAeQeOZPhQcyfCgHkHjmT4UHMnwoB5B45k+FBzJ8KAT3EL8Tcn/yN/xtOinO9ZOZkcauGhekt+89kcUDF3dy87eZ6ong1qbqqr09G+6odENfaPh0Rxn8L5AAOBAAAAAAAAEbrr8YNIf02b/SymeYfEBnk0mCysnm08fcdJal9EMb4ZGdo7/hRzm7r0REVXKqI1TJjmjlYj2Pa9juqOau6KepT44VExsn7ys6ofsHjmT4UHMnwoRHkHjmT4UHMnwoB5B45k+FBzJ8KAeQeOZPhQcyfCgHkHjmT4UHMnwoB5B45k+FBzJ8KAeQeOZPhQcyfCgHk1Ef8ZWC/qy//mVTbcyfChqsQ5mY19BZquSeDGUZ4LEzF3Y2WV8Lmx7+Cu5Ylcqb7tRWbp57TOnwiqfK0/aywuQAeSgAAAAAAAAAAAAAAAAAAAAAE/pmhLTzGq5ZMbDQZaybJo54plkdcalOsztnt38xyKx0fL06RNd+UUBO6Yxy0s5q6ZcVFj0uZOOdLMdjtHXtqVaPtnt/3ap2fZcvpSFrvygKIAACd1PD22d0g7ybHT9lk5H891/LND+4rLeesn5Uvncqp/NvlX0FETmpIe21HpNfJsdP2V2aTtLknLPD+5Zm81dPyn+dyr8DHPAowAAAAAAAAAAAAAAAAAAAAA0WS0HpnMWXWb+ncTesPXd0tmjFI9V+FVVqqb0GdNdVE3pmy3sl/ct0Z6o4H9WQ/VHuW6M9UcD+rIfqlQDbpGNvzzlc07Uv7lujPVHA/qyH6o9y3Rnqjgf1ZD9UqANIxt+ecmadqX9y3Rnqjgf1ZD9Ue5boz1RwP6sh+qVB6blyDH1J7VqeOtWgY6WWaZ6MZGxqbuc5y9ERERVVVGkY2/POTNO1O+5boz1RwP6sh+qaS1o3R1qwtPDaO0/esc00EtpmPrvgpSsYiok22zt1c5icjfO6qvREVSgSW7qxHJC6bF4VyVbFe9Xm5bFtq/hHsWNzN4mKnI3ffnXmkREj5WvdvKdKvj4OxqwR14uZz+SJiNTmc5XOdsnpVyqqr6VVV9I0jG355yZp2o7EcGtIUImyWtOYa7fkiiZYnXHRtje9rdlcyLZWx7ruqo34eqrshsPct0Z6o4H9WQ/VKgDSMbfnnJmnal/ct0Z6o4H9WQ/VHuW6M9UcD+rIfqlQBpGNvzzkzTtS/uW6M9UcD+rIfqj3LdGeqOB/VkP1SoA0jG355yZp2pf3LdGeqOB/VkP1R7lujPVHA/qyH6pUAaRjb885M07Uv7lujPVHA/qyH6pqrfBrTDLsVnHadwMPPZZJbhs4yOZksSMVitjRf3pfeu3amyq1d03cri9A0jG355yZp2oLCaO0Nl2RxS6NweOyvYNnnxVmjVWzXarnNRXNZzJyq5j0RyKrXcq7Kptfct0Z6o4H9WQ/VNpnMDHmIHuimdj8kkL4a+TrsYtisjnMcvIrmqmyujjVWqitdyIjkVEPFLNOdkJ6N+KOha7Z6VGOsMctyFrWOWWNN+bZOdGuRURUci+LVa5zSMbfnnJmna1nuW6M9UcD+rIfqj3LdGeqOB/VkP1SoA0jG355yZp2pf3LdGeqOB/VkP1R7lujPVHA/qyH6pUAaRjb885M07Uv7lujPVHA/qyH6o9y3Rnqjgf1ZD9UqANIxt+ecmadrWYbTGG06j0xOJo4xH9HJTrMh5v08qJubMA01VTVN6pvLEABiAAAAAAAafOamrYaKy2OKbKZGGNkqYuhyvtPa9/I1UYrkRGq7dOZyo1OVyqqI1VQNwQuQ03oWTI14E0nisrbnsPrvdWxcUyQPa3nd2z+XaPZFT3yoqq5ERFVTdzYjKZe3L5ff8hpQXYrFSLGPcySWNib8s71Tqjn9VYxG9Go1XORXIu1xuKpYastehUgpQK90ix140Y1XucrnOVE9KuVVVfFVVVU2UYleH+iZj0W8xqQNbgzgsv2VjL6dwlGOSo+GfE46lD2aSOdvz+UJG2Xma1EaitVibq5dlXl5aBOFmi0RE9qOC6f/wCth+qVANmkY2/POVzTtS/uW6M9UcD+rIfqj3LdGeqOB/VkP1SoA0jG355yZp2pf3LdGeqOB/VkP1R7lujPVHA/qyH6pUAaRjb885M07Uv7lujPVHA/qyH6o9y3Rnqjgf1ZD9UqANIxt+ecmadqX9y3Rnqjgf1ZD9Ue5boz1RwP6sh+qVAGkY2/POTNO1L+5boz1RwP6sh+qPct0Z6o4H9WQ/VKgDSMbfnnJmnal/ct0Z6o4H9WQ/VNVb4J6TdbgsUsJi6W1ryixEuNgmjsN5ORY9ntVY29EcnZq3Zyb9eZyOvQNIxt+ecmadrnFPS2k8c6tDndDYLF3FglsSWq+OjkpRpG7qqzrG1GKrdn7PRvTfZV5VUv8fUqUaUMNGGGvUa38FHXajY0RevmonTbr6D3SRsmjcx7UexyK1zXJuioviioTk+lrGGryv0xPFjpI6TKlTFzs3xsfI7du0TNljXlVWbsVERFRVa7lahrrxcSvwrqmfWUvMqUGlj1RBFkLFPIQy4t8UsMEU9tWtgtvlbu1IH7+evMjmcqojt2+92c1Xbo1oAAAAAAAAAAAAAAAAAAAAABO6cxvkOpNVzph2Y9ty5DOt1tntFvqlaKPtFZ/u1akaR7elGI70lETuGxq09Y6jsphUpx22VXrk0s8/lr2sc1WrHv+D7NGsTf8rm+RQKIAACczcPb6w01+58bN2SWZu0sv2tRfg0ZzQN9O/Ps5fQip8JRk5bi7fiDi3rBjZErY20vbSP/AHbEr5YERI2/zTkY7mX+UyNPhAowAAAAAAAAAAAAAAAAAAAAAAAAAAAAGJlMpUwtGW5enZWrR7I6R/wqqI1ETxVVVURETqqqiJuqmuq461lbkd7KItfyaadtapXncsT43eYySVNk5nq1HLyr0b2ip5ytRx4oPsZbUFuy9MlRq4576cdeZGMguKrY3rYaibvVGqro27qibpIvKqcjjegAAAAAAAAAAAAAAAADDy2MblaT4e0dWn2csFuOON8laRWq1JY0ka5vO3mXbdqp8KKm6GYANXgsjPbZPWtwzsuUnNhmnkr9lFZdyNVZYvOcnIu69OZVaqKi9UNoT2qKjqklbPVKSW8jR2iVrri1mLWfIzt1cvvHK1jVe1HptzMROZnMrk37HtlY17HI9jk3a5q7oqfCgH6AAAAAAAAAAAAADx4Hkl6DKuvWwZSV1fIYFssVrGRLBKxyyxq78M/nVEenNyujTk2RWNkRzlVisD2x37+qWRuoK7HYaeCxG+1LG+O6kiOVjHRMe3Zrejno9yLunJs1UcqptcVhaeGia2tEvadnHFJZlcsk8yMbytWSR27pHIn5TlVfHqZwAAAAAAAAAAAAAAAAAAAAAAAAA9FylXyFd0FqCKzA5UVYpmI9qqioqLsvToqIv6UNRHjMnhLMXkFhcjRnuTT24shO50sLHorkSB38lr/CN/RGvVGuajGsXfADDw+VhzeLrX4GTxRTsR6R2YXQys+Fr2ORHNci7oqKm6KhmGlyuBc6+7L4ptatnFjirPsTsc5k1dsvOsT0a5u/RZUY9d+zdI5yI5Fex+ZhM3T1Fiq+RoSulqToqsc+N0bk2VUVHMciOa5FRUVrkRUVFRURQM4AAAAAAAAAAAAAAAAAACerYrybiBkMkzENZ5ZjK1eXLpaVVk7GWdzIFh8E5e3kdzp486ovvUKEnMrjWt1vgMrHimWZ217WPfkVtLG6rDJ2cqtSLwk53140/lN23TorgKMAACcoR+Ua9y9hYcW5tejVrMnhfzXWuV8r5I5U/Jj2WFzE8VVXqvTYoyc0gxLE+dyPJiXeV5GRrbGLdzrMyJGwp27/AEytdG5ionveVG+KKBRgAAAAAAAAAAAAAAAAAAAAAAAAAAAca9ltnNfaU4J5bUPDnINoZvDvbenRasdhZqjUckrUa9rkTZFR++2+0a/CB0Ph/WWppOm11a9Ue980r4clL2k7XPle9eZ36XKqJ6EVE9BRHxb/AOjp4jcU+K2NzmW1Zm1u6PxzPIKED6sbXS2nOSR7+1RvO7kb02VVT8KnwdPtIAAAAAAAAAAAAAAAAAAAPzJGyaN0cjUexyK1zXJuioviioT+hkWphX4pzcbC7FWJKLK2LkV0deBq712ORerH9g6FXMXwV3TdqopRE5ikSnrfPV07mhZar1rqR1fNvyyefE+Sw3wczlihYx/j5jmr71AKMAAAAAAAAAAAABpNb30xWi8/ddbmx7a2PsTLbrRdrLAjY3LzsZ+U5u26N9KpsbLGptjqqLK+dUiZ+FlTZz+iecvyr4nzJ7P3iLxN4UcO8RqXQGW7soRzyVMurasUz9pUakMiK9jlZyq16bpt1e3x6G79hBq/iTxH4Tv1dxFy6ZFcpP8A9lwpThg7OuzdqyL2bU5ud2/j6GIqeIH0SAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE5o68lyfUUSZGzkFq5WSFUsw9n2H4ON/ZMX8tic/R3yqnoMTi1X1TZ4b6gbom83HarbVdJjp3wsmRZWqjkZyvRWrzois6p05t/QfFXsG+PvG/jfxiuVNR5/wAr0riY5bGVikx8Ee8jmLHFC17Y0Vq8/n7IqfvbvhUD+gYAAAAAAAAAAAAAAAAAAE7rqg2ziILjcfXyNrGWor0DLNhYGxq12z3o/wAEVI3Sbb9F8F6KpRHpuU4MhTnq2YmT1p43RSxSJu17HJsrVT0oqKqAe1FRURUXdF9KHk0GiZXpgY6MzaUNnHPdRkgoWFmjiRi7Roqr5yKsXZuVruqc3p8V34GJl8pWwmJu5G5Ygp06cD7E1i1KkUMTGNVznvevRrURFVVXwRFUwtIYyfD6YxlW5Xx1XINga65HiYViqeUu86Z0TV6o10ivcnNuvXqqruYetpW2KuPxCSYtZcrcjrrVysfasswtXtLDGx/lPWFkm2/RF2Vd0TZaQAAAAAAAAAAAPVZsR1K0s8q8sUTFe5fgRE3Ug4Zc7qavDke/reEhsMSWKnQhru5GKm7Ue6WJ6q7bx22RF6bLtutbqr8WMx/Q5v8AApPaZ/FzFf0SL/Ah6HZ4imia7RM3t4xf7so8Iuxu5c1665v5ij92Hcua9dc38xR+7G7Bv7zhHtjoXaTuXNeuub+Yo/dh3LmvXXN/MUfuxuwO84R7Y6F2k7lzXrrm/mKP3Ydy5r11zfzFH7sbsDvOEe2OhdpO5c1665v5ij92Hcua9dc38xR+7G7A7zhHtjoXaTuXNeuub+Yo/dh3LmvXXN/MUfuxuwO84R7Y6F2k7lzXrrm/mKP3Y9djTuWtwSQT6xzM0MrVY+N9egrXNVNlRUWt1RUN+B3nCPbHQug9BcJYeGGmKundL6iy+Iw1ZXuirRx037K5yucqudXVyqqqvVVX0J4IhQ9y5r11zfzFH7sbsDvOEe2OhdpO5c1665v5ij92Hcua9dc38xR+7G7A7zhHtjoXaTuXNeuub+Yo/dh3LmvXXN/MUfuxuwO84R7Y6F2k7lzXrrm/mKP3Ydy5r11zfzFH7sbsDvOEe2OhdpO5c1665v5ij92Hcua9dc38xR+7G7A7zhHtjoXaTuXNeuub+Yo/dh3LmvXXN/MUfuxuwO84R7Y6F2lbis9AvPFrDJyyJ1ay3WqPjVfgcjIWOVP0ORflQptL5x2fxXlEkTYLMcsleeJqqrWyMerXbKqIqtXbdF28FQwzD4bfwfmf63tf4zXjRFeFNUxF4tqiI+xrhXgA8xiE7YckPEOin/Y7Fs4uxvzptkpOzlh25F9MDe1Xn+Bz4/5SlETmUfya60/+ExTFfUuM5bDf3c/rAu0C/wAjzd5E9K9l8AFGAAB6blqOjUnsyryxQsdI9fgRE3X/AKHuNPrH8Uc5/QZ/8txnRGaqKZ81jWl4X57UleLIOz1vCR2GJJFToQ13JGxU3RHuliernbKm+2yb9ETpuv67lzXrrm/mKP3YzMB/AWO/o0f+FDPPWmrLMxFMW9I6LdpO5c1665v5ij92Hcua9dc38xR+7G7Bj3nCPbHQu0ncua9dc38xR+7DuXNeuub+Yo/djdgd5wj2x0LozWHDV2vtM5HT2oNT5jJYbIRLDZqyRUmpI3x8W10VF3RFRUVFRURUUysJou7pvDUcTjNWZinjqMDK1evHBR5Y42NRrWpvW9CIhUgd5wj2x0LtJ3LmvXXN/MUfuw7lzXrrm/mKP3Y3YHecI9sdC7Sdy5r11zfzFH7sO5c1665v5ij92N2B3nCPbHQu0ncua9dc38xR+7H5sZDMaRrrkp8zZzdCBOa1Bdhha9It/OfG6KNnnNTrsqKio1U6KvMm9JviV/F3qf8Aqyz/AJTjZh2xK6aKqYtM21R0Im82dHAB4jEAAAAAQ8+Tyuprdx1PJzYXHV55KsS1YY3TTOY5WPe5ZWOajedFRrUb4N5lcvNyt9Pcua9dc38xR+7Hq0R/BFz+tcl/rpygPZqth1TRTEWjw1RP3hlM2mzSdy5r11zfzFH7sO5c1665v5ij92N2DHvOEe2OhdpO5c1665v5ij92Hcua9dc38xR+7G7A7zhHtjoXaTuXNeuub+Yo/dh3LmvXXN/MUfuxuwO84R7Y6F2k7lzXrrm/mKP3Ydy5r11zfzFH7sbsDvOEe2OhdpO5c1665v5ij92JnR3Bunw/t52zp7PZTFz5y67IZGSKKmq2J3eLl3rrsnj5qbIm67J1U6CB3nCPbHQu0ncua9dc38xR+7DuXNeuub+Yo/djdgd5wj2x0LtJ3LmvXXN/MUfuw7lzXrrm/mKP3Y3YHecI9sdC7Sdy5r11zfzFH7sO5c1665v5ij92N2B3nCPbHQu0ncua9dc38xR+7DuXNeuub+Yo/djdgd5wj2x0LtJ3LmvXXN/MUfuwTD5ti7prPMuVPQ+CirV/TtXRf/M3YHecI9sdEu9ulM5YyjLtS8kfeFCVIZZIkVrJUViObI1F8N0Xqm67Kipuvib4jNF/jZqz/nq/5RZnD2imKMSYjhPOIknWAA5kAABNxq3C63ljV2IqVczEkrI2t7O7auRt5ZHOXwlRIWwon5TUi9LduWkJ3XT0oYJ2XSarVXDyNyD7NqqthI4Gf7RyNanMj3QLMxHN3VFf4OTdq7pchVTHreWxF5F2Xb+Uc6dn2e2/NzeG23XcDSQWu9tcWWRXaU9fE1kimqth5p4rMuz0VZF96nZInmp1Xn3XpylGaDQ8rrun48muSTLR5SR+QgtJT8l3ryu5oGKxU5t2RLGxVf5yq3dUbvypvwAAAAAAAAAAA1eqvxYzH9Dm/wACk9pn8XMV/RIv8CFDqr8WMx/Q5v8AApPaZ/FzFf0SL/Ah6OD8GfX8MvJsiexHEXSmoLi1MXqfDZK0ldbnYVMhFK/sEXlWXla5V5EVUTm8N/SUJ8bYXR1iX2AsSaaxsi5C03yi+mOga+3ar94c1lqIqLzqsTFTlVFRUby7KnQkzZi+nW8WNHWNP5jNUtT4fJ47ExOmuz0chDM2BGoq7OVHbNXoqJuqdTX6G44aM17ovF6lp6hxdepdSBjop78PPWsStRza0uz1Rs3Xbk333Q41w50vonWuYy2Y0rru7rLK1tP2MetVmLqU4EimROWOXsKsKK5HMTZj1VW9eibqSdbMaW1t7Hfg9pmFa9u1jc/prG57GPhVr4ZUckckUzFROqrG9FRfFE+UxzSPpGLjBgsvq3TWG0/lcFn48s2xJJNUzldZYY4mu2fHCjldMivY5i8nvVa5V8FN/W17pm5qKbAQaixM+dh37XFx3onWo9k3XmiR3MmyfChyri5jFr8auEkeIhgp3nQZ2Ou9kaNRr1pbt32Tw5l3/tU4vwN0tpPPU9B6ezWt8zj9c4m/FbsaZdiKcVqvfgcskqyTNqdt2b1a7eR0vno/ZXKri5pibD7BZrTT8mDq5pmdxj8NaeyODItuRrXme9/IxrJN+Vyuf5qIi9V6J1PXPrzTNbUbNPTaixMWfkRFZin3oktO3TdNoldzLunyHAtM6BysPG/2hS03t0Np3Ky63qS7fgnLYRUr1kT0dnZddlRP/hxnM9HaS09na17RmvNd5jAa4t6hnW1h4sRTWxNYdcc+CzDOtR0zmKixuSXtNmpum7WoiDNI+5ib1DxL0jpG95FnNU4bD3eyWZKt7IRQyrGn5SMc5FVOi9dikPhziXcwnuh8S9A5PIaao389qKjkmapzN9lazjmIys7smxvbzuVjY1SNzFRi9qqK5NnIWqbD7Es8QdLUswzE2NS4iDKvsNqNoy34mzrO5rXNiRiu5udWva5G7bqjkX0oecJr/S+pcpaxmI1JiMrkqu62KdK9FNNDsuy87GuVW9enVDlXC/EUk43cdMy3Gw3MpHkcfHFIrUWRWtxsDmsa5fe7uX/x2+A4fw/1LSy/E7g5qJ+YpxZeXJWq+UweKwkVKthHT1ZmtqSSNjSTtFk5W8sr15nN5mtTbcmaw+vcdxQ0bl8vFiqGrcFdykqvSOlXyUMk71a5WvRGI5XLsrXIvToqKnoJ7RvHHAakzWcw+QuY3BZWjnbOFqUrORj7e/2SM/CRsdyu6q/blRHbbeKnyzQ1BpbO8CIdFYVsFvilPquxLj69Wqq2686Zl70sq9G+axsLV3kVduVOXf0G/wBZaexa8DvZE5pcdUXMV9W3Zob6wt7eN8Tq7o1a/bmTlVVVNl6br8KmOaR9Zz6405W1HHp6bP4uLPyNRzMU+7G209FTdFSJXcypt8huz5cy2awehfZIrHp23Q1LldQ56tHmNO3Mc517HSLAjVvVrHLukTGI1XIvM1PORrmruh9RmyJuNDf1/pjFZ+DBXdR4inm7G3Y42xeiZZk38OWNXcy7/IhLcOeOOA106apZu43DZxMnex8GIlyMb7NhtaxJD2rWLyuVHdmrtkRdvDddtzk3BzUuhdH5PN6f13DVr8SbWqbU8rchQdLYuufaVak8LuRVdGkaxcrmrszlVV5dtyRsaexdX2PWpM/DjqkWbg4jusR5FkLUnbImfZGjkftvvyKrfHwXYxzTrHf89x7wemKfELJ35cfJhdIRxrLYo5avPPNMrX89d0PMiwyo9qRtbIqK9zungU2H4oaUzej26or6jxK4JGp2uQS/EteF2ybsfIjuVrk3RFRVOC62wMuZv+ynx2PpeVW7ODpdlWhj3dLKtCZU2RPFyr4elVMLU+uNGajZwd1M6WvleG2FsWIs2+Os6StSvuqRpWksxo3pyKsiczk2a57d1QmaR2fUXHfTuGyei0q38Xk8FqK1arvzkOSj8lqJDVknV6vTdrkXs+X3zdt99+mxWLr3TLdNJqJdR4lNPqm6ZZb0Xki9dv33m5fHp4nCtVXdD8Q9e8Fn6drY3J6dk1FklekVJG15p2Y6Z/OjVaiPVHI1edEVN2psu6EfmswzQ9biRjalbGY3ATcRa9ezfvY9tqphYpaMEr7SQqnIi9oiIiuTlR0u6/Lc1h9Ba7456Q0Jw7XWk2Yp5LCPnirQT0LcL22JHyIxEjfzo13L5znbLujWPXboWOCz+L1RioMphslUy+MsIqw3aM7ZoZNlVq8r2qqLsqKnRfFFPiZlerPwk470MVan1FSq53FZqGXu9kDp6+9V0tlkMcbG8i9hP5zGIjkjVeu+6/ZeitV4DWmn4Mnpm9WyGHe5zYp6ibRqqL5yJ0T0libyN6YfDb+D8z/W9r/GZhh8Nv4PzP8AW9r/ABmdfwav2WNSvAB5iBO5hyt1np1EkxDUWO0ittp+7Xeaz/Z/k/l/JylETuY39uWnOmG27O11uf7d71n+zfJ/OfJygUQAAGn1j+KOc/oM/wDluNwafWP4o5z+gz/5bjbhfEp9YWNbS4D+Asd/Ro/8KGeYGA/gLHf0aP8AwoZNyWSvUnliiWxKxjnMiauyvVE6N3+XwPQr/VKNPhNf6X1LlLWMxGpMRlclV3WxTpXoppodl2XnY1yq3r06oevHcR9JZfLQYuhqjC3cnPGssVKvkIZJpGJvu5rEcqqnReqJ6D4+4f6lpZfidwc1E/MU4svLkrVfKYPFYSKlWwjp6szW1JJGxpJ2iycreWV68zm8zWptubnSWGoUfY/cGsjWpV4Mg7X9VzrUcTWyOV+SmjequRN13YvKvybJ6DRFdx9TTcTNIVr2SpTarwkV3GRumvV35GFJKjGpu58rVduxqelXbIhu48nTlnrwstwPmsROsQxtkRXSxorUc9qb9Wor2bqnTz2/Ch8saBdpirxdyOgMDNQ1lp3PyZlcm2THOjyWBe/mWZkk6tTnhlermN5kR3VuzntQisdj+JWltJT8REgsWs5w7aujaONRV5cjUi7SCazt6VdK+s/f4Ki+O4zD7Ev8RdKYvDJl7up8NUxKzurJfnyETIFla5Wuj7RXcvMjmuard90Vqp6D23td6axdKlcuaixVSpdjfLVsT3YmRzsYzne5jlds5EaiuVU32RN/A+UdW6DrcJdacOqOptS29MaUx+k1x8GdZRrXK7cqs3Pa7RbEErYnTIqOR+zVdyqm/ihuMTw/0vS1TwKqYy/Y1Pp69nM3loJMnVjhar1qSSeZC2KNrGJK3naiMRN13TpsM0j6oxeVpZzHVshjblfIULMaSwWqsrZYpWL1RzXNVUci/Cimqz3EHS2lrLq2a1LiMRYayOR0V+/FA9Gvc5rHKjnIuznMciL6VaqJ4KbyKJkETIomNjjYiNaxibI1E8ERPQhxWDBY/J+zBzVu5SgtWKuiqLYHzRo9Y+e7a5uXfwVeVE3/AGmczYdPh1/pexqR+notSYiXUDN+bFMvRLabsm67xc3N0T5D053iXpDTGT7tzGqcLi8irUelO5kIoplavRF5HOR2y/DsfHevNVVcxqOLL5DJVMHnsPr6tJLprH4WJklOrHeaxblqz2ay/hI/PWTnbG5JEbsu57dVXcJLxE1toHI5HTWPyOQ1rVzLNU5S+yvcqMa+vKkLInt53PajFiY5FRio/wAU674Zx9xk3xK/i71P/Vln/KcUhN8Sv4u9T/1ZZ/ynHZgfGo9Y+7KnXDo4APFYgAAAADnmiP4Iuf1rkv8AXTlAT+iP4Iuf1rkv9dOUB7GN8Sr1lZ1y0Muv9L19SM09LqTER59+3Lin3oktO3TdNoubmXp8h68hxH0lici3H3tUYWlfdY8kbVsZCGOVZuVruyRqu35+WRi8u2+z2r6UPjvj3qaDNW9ey38hVwOoMLqCq+lp+hhYnXLFevLA7vGaysbpeVY0c5HscxrWsRqqu6otlqrB4nLaX9lfflo1LVjke6O06Jrn7MxEMkeztt9mu85PgXqcuZH0zkNcacxOdqYS9n8XSzNvbyfHWLscdibddk5I1dzO3Xp0QyKGp8NlcfUvUstRuUbciw17Neyx8c0iK5FYxyLs5yK1ybJ13avwKfK2c1Dh9GcT8LmcVdpak1bne44cvpPJY501qReSNsdynPy+Y6Nrke73zPNVVVrj0Z3hZrHJ681fpHC9rRxOk70uucBMxytZYv2dpK1bbw7NszL6L49JG9ELmkfVtrVuCoplFs5rH10xSMdkFltRt8jRzeZqzbr+D3aqKnNtui7mNV4gaXvYHvytqTEWML2rYe8or8Tq3aOcjGs7RHcvMrnNaib7qrkT0nyPqHDZXJcLdH69zvl2GxepNXP1NqF9apHbkx9aSJ8dFz45Y5GvjiY2vvzMVEVeZE3RFTI1npLR2R4Oa5zeA1bb1pUzmZwNHISy069aq9Y78HWNIIImPVWTcrnoi78qIq7t6TNI+vMBqfDarqS2sJlqOZqxSugknx9lk7GSN25mK5iqiOTdN08U3Q/Od1Zg9L9j3zmcfiO3SR0Xl1pkHaIxqvereZU35Worl28ETdehnUcfVxldtenWhqQNREbFBGjGp026InTwRDjfGjD0s5xu4IVshViuV25HJzdlM1HNV7KL3sVUX4HNa5PlRDOZtA6FNxU0VWfjGTawwMT8mxstBr8nAi22O966Ld3novoVu+5n6i1tp3R7qrc9n8XhHWnKyumRuR11md8DOdycy9U6J8J8seyWyNTN6h4gaYyU9LTvkunY4cLSrYOK1f1A98UjkZHI+J7kjjk8xGxIjmqrnczehO671piMVl8Xcysmn86mruHVKlDNqK82syg9e0RXo+Rqo9j3PVXpHu9FiTdE3aq4TXYfbOKytLO4yrkcdahvULUTZoLNd6PjlY5N2ua5OioqL4oazUOvNM6Rc5ud1FicK5sbZXJkL0UCoxzla1y87k6K5FRF9KoqGFwpxkOE4YaRx1fKxZ2CniatZmTgej47aMha3tWuRV3R226Luvic+yeHoZb2XdRb1Kvc7HQ8jo/KImv5FW81qqm6dFVFVP0Kqekzv4DqWW1pp7AYOLNZPO4zG4eVGrHkLdyOKu9HJu3aRyo1d06p16mwxuTp5mhBex9uC9Snaj4rNaRJI5Gr4K1yKqKnyofF/Da1h9L0eEOe1mkbdDY+vqGhXsW4uepQu94ubCsnRUZvBHIxir0TZUTbc7j7FqD/ANV9XXaVSSlpjI6ovXcBC+JYm+RP7PZ8caonJG+VJntTZOjt9upjFVx1/J5SnhaE97IW4KFKBqvms2ZGxxxtTxVznKiInyqQuiONWF13qrWOOx1ihYw+noac/fdW+yevYbPHI9y7tTlajOzVFXmXf5NiS9lL5PXp6CyGdrvt6HoaiisagjSJZY2wpFKkMkzEReaJsyxq5FRU8FVOhxHU0+E1le4zX9IQR5PSfl2lreThxNZUbboxve63yta1OdORqquyLujXJ1E1WkfYunNaae1jTmt4DO4zOVIXcks+NuR2GMd8DnMVURfkUxMXxM0hm4shJjtV4S/Hjmq+6+rkYZEqtTxWRWuXkRPhdsfJvFF1biXlNfZLhJWdkMCmjoaWVmwUCxRXZUvxSLBHyoiSSpUS03puqJI1viux0jUOoeBvErhVqTDYrJUsVimYyFLlzEYxzJKELZo+ya9Ei6csiM3icngjt023UZh3rTuqcLq/HeX4HL0M3Q5lZ5VjrLLEXMm26czFVN03Tp8ptDjfsZdZS6t09qFiw4q1Vx+UWtBqDB0lqVMy3so18obGvg9OjHKiq3dnRdk2TshnE3i41+i/xs1Z/wA9X/KLMjNF/jZqz/nq/wCUWZo7V8X9qf8ArDKrWAA5GIAAPCpumy9UIJmVnbiU047M37eaTJ92SZGpjEjdCitWy1XN27NrUr8rO1TzVcqbIjl5EvjSrppXaybqBctk+VtBaKYlJ0SjusiPWdY9t1l6I3mVejd0ROqqoboAAAAAAAAAAAABq9VfixmP6HN/gUntM/i5iv6JF/gQotUNV+mss1qbuWpMiInp8xSd0yqLpvEqioqLUi2VF3RfMQ9HB+DPr+GXk2QAMmIAAAAAAADnr+B+Eke5y5vWSK5d9m6vyiJ/4JY6Gs1b7HrHa0muQ5HV2sHYO7GyK3gUy3NTnY1jWcrudjpERyNTm5ZE5lVVXqqqdVBjaB+IYWV4WRRtRkbGo1rU8EROiIfsAyE3w+0Hj+G2mI8FjJrM9RlmzaR9tzXSc088k703a1qbI6RyJ08ETfdepSAEHqtV22600D3SMZKxWK6J6seiKm27XNVFavwKi7oQKcDcG1UXvvWXT4dYZT7wdDAtEgACgAAAAAAAAYfDb+D8z/W9r/GZhicNk2x2YX0LlrWyp6fP2/6oor+DV+35WNSuAB5iBOZn8ctNrthveWutxf3d7xn+zfJ/OfJylGTubT/1v007kxC/7S3nuLtcb+DRdq36dvP/AOFAKIAADT6x/FHOf0Gf/Lcbg1Gr2q/Seba1N3LRnRE+H8G424XxKfWFjW0mA/gLHf0aP/ChnmBp9UdgcaqKiotaNUVF6L5qGeehX+qUAAYgAAAAAh8xwhxGbylm/Pl9VQS2Hq90dPVGRrwtX4Gxxzo1qfI1EQqMBg4NOYivjq09yzDBzcsuQuS253buV3nSyuc93j03Vdk2ROiIbAEsBy3Wfsfsdr3I5F2Y1VqufCZGRslvTqZJvd8qJt5nKrO0axeVN2se1PH4TqQExE6w8Cb4lfxd6n/qyz/lOKQnOJDVfw+1K1NuZ2OsNTddt1WNyIdGB8Wj1j7sqdcOjAA8ViAAAAAOeaI/gi5/WuS/105QGg0U1WYm41dt0yuS3RF32/dsym/PYxviVesrOuQAGpAAAAABKaq4bY3V+RZduZHUFSVkSRIzFZ+7RiVEVV3WOGVjVd5y+cqb7Iib9EM7Sejqeja08FO5lrjJno9zstlbN96Ltts1073q1PkRUQ3oJaAIXXfCt2uMpFdZrHVOnOWDyeSthL7IoJm7qu7mPjeiO85U5m7O22TfohdAaxzPG+x60thsbTx+OvaoxtGpBHXhrUdT5CvExrGo1NmRzNairtuqoibqqqvVVLfTWnK+lcUyhVsX7ULXOckmSvzXZlVV36yTOc9U+BN9k9BtQLRAE3q3QNDWctaS5fzdNYGua1MTmrdBrt9vfJBIxHL06K7fb0FIAJzSWg6GjH2nUr2auLYRqOTL5m3fRvLvtyJPI/k8evLtv038EKMAAACgAANfov8AGzVn/PV/yizIzRaf+tWq3eKdpWTf5ex8P/NP/Eszn7V8X9qftDKdYADkYgAAAAAAAAAAAAAAAAAA8OajmqioiovRUX0kY/RuZxi9hhMvThxzf3qtkKb53Qp/Ja9srPNT0IqKqJ032RC0Buw8WvCvl6/dYmyJ9rusPjjB/qyb7wPa7rD44wf6sm+8FsDdpWJw5R0W6J9rusPjjB/qyb7wPa7rD44wf6sm+8FsBpWJw5R0Lon2u6w+OMH+rJvvA9rusPjjB/qyb7wWwGlYnDlHQuifa7rD44wf6sm+8D2u6w+OMH+rJvvBbAaVicOUdC6J9rusPjjB/qyb7wPa7rD44wf6sm+8FsBpWJw5R0Lon2u6w+OMH+rJvvA9rusPjjB/qyb7wWwGlYnDlHQu5RoG3q/XOkcfnEvYWiltr18ndj5nqzle5vj26b+938PSUPtd1h8cYP8AVk33gw+BTkr6CdinJyWMPk8hjZo/S3s7cqMXwTo+NY5E+R6HQhpWJw5R0Lon2u6w+OMH+rJvvA9rusPjjB/qyb7wWwGlYnDlHQuifa7rD44wf6sm+8D2u6w+OMH+rJvvBbAaVicOUdC6J9rusPjjB/qyb7wPa7rD44wf6sm+8FsBpWJw5R0Lon2u6w+OMH+rJvvA9rusPjjB/qyb7wWwGlYnDlHQuifa7rD44wf6sm+8D2u6w+OMH+rJvvBbAaVicOUdC6KbprVcq8k2dxUMa9FfWxknaIn/AA806tRflVFT5FKjEYmvhMfFTrI7so915pHK573Kqq5zlXxVVVVVfhUzQasTGrxItVq9Ij7JM3AAaECd1Cxyam0rIjMQrfKp2K+/0tJvXkXar/xry+cn82j19BRE7qyNEv6Zsq3EfufKIvaZR3LJHzwTRfuZf55VkRqIvix0ieKoBRAAAeHNa9qtciOaqbKipuioeQBFu0bmsZ+AwuYpxY9vSKvkKb53wt/kte2Vu7U9CKiqielT8+13WHxxg/1ZN94LYHXpWL525R0ZXRPtd1h8cYP9WTfeB7XdYfHGD/Vk33gtgXSsThyjoXRPtd1h8cYP9WTfeB7XdYfHGD/Vk33gtgNKxOHKOhdy7W79YaN0Zn8/5fhbvdWPsXvJm46Zqy9lG5/Ii9uu2/LtvsvibWnhdYW6kE/e+Eb2rGv5e7Jl23Tfb/aD9ceLLafA/iHO9N2RadyL1Tp1RK0i+lF/6L+gs6EK1qNeJfGONrF/sTYaVicOUdC6Q9rusPjjB/qyb7wPa7rD44wf6sm+8FsBpWJw5R0Lon2u6w+OMH+rJvvA9rusPjjB/qyb7wWwGlYnDlHQuifa7rD44wf6sm+8Hur6NyeQliTO5StapxubItSjUdA2ZzV3RJHOkeqs32XlTbfl2VVaqtWwBJ7VicOUdC4ADkYgAAAACVyWkr0V6xawmRgo+Uu7SetbrLPEsm2yvZyvYrFXork3VFVN9kc5zlw/a7rD44wf6sm+8FsDqjtOJEW8OUdGV0T7XdYfHGD/AFZN94Htd1h8cYP9WTfeC2BlpWJw5R0Lon2u6w+OMH+rJvvA9rusPjjB/qyb7wWwGlYnDlHQuifa7rD44wf6sm+8D2u6w+OMH+rJvvBbAaVicOUdC6J9rusPjjB/qyb7wPa7rD44wf6sm+8FsBpWJw5R0Lon2u6w+OMH+rJvvBP6Tt6v1Rb1FCl7C1e6Mm/G8y4+Z3bcsUUnOn4dNv33bbr73xOrEDwbf3jgsznGora+bzNy9WVU254Ef2MMifI+OFkifI9BpWJw5R0Lsj2u6w+OMH+rJvvA9rusPjjB/qyb7wWwGlYnDlHQuifa7rD44wf6sm+8D2u6w+OMH+rJvvBbAaVicOUdC6J9rusPjjB/qyb7wPa7rD44wf6sm+8FsBpWJw5R0Lon2u6w+OMH+rJvvA9rusPjjB/qyb7wWwGlYnDlHQuifa7rD44wf6sm+8HlunNXOVEdmsK1vpVuLmVU/wD5BagmlYnDlHQu1mAwUWBpvjbLJZsTP7WxZl9/NIqInMu3RE2RERE6IiIhswDmqqmuc1WtiAAxAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABz/AD6y8OdU3dUokkumsm2JuZjZu7yGZicjbyNT8hWckcq/ktijf0Rsil7DNHZhjmhkbLFI1HskYqK1yL1RUVPFD9nPp9BZjRs0lrQVurXrPcskumsq6Tu96r1XyeRvM6mqr48rJI/Fey5nK4DoIOf1+M2Jx1iKlq2pb0PkHuSNvfSNbUlevREittVYH7r71qvR67puxq9C+jkbKxr2OR7HIitc1d0VPhQD9AAAAAAAAAAAAAAAAE5xARkWmn3XtxKNx88F502bdyVoI4pWvklV/wCQ5saPVrvBHI1V6blGY9+hWytGzSu14rdOzG6GevOxHxyscio5rmr0cioqoqL0VFAyAaLRuUkyGHSvbtULOXx7kp5FMa1zIY7DWtVURjt3MRWuY5Gqq7Ne3q5FRV3oAAAAAAAAAAAc+49uWXhZlceyTs5cvLVw8aoq7q61Zjr9Nv8AvV/QiKq7IiqdBOfZ93ty4o4XCRtbJjtOJ3zkZEVdvKnNdHUg6Lsq7Ommci9W9nAu2z0U6CAAAAAAAAAAAAAAAAAAAAAAAAAAJ7VPELTOiezTO57H4qWVFWKCzYa2Wb5I49+Z69F6NRV6AUJ4VdkOfN4lZrUiozSejclaiei8uTz6LiqiL128yRq2Hf2Q7Kn5R59zG5qlySa6zTtQQLyu7ipxLVxSKidUfFzOfYRfS2Z7o12RUjaoHi/mV4rxWcPgLE0enHosWQz8CK1thq7c0FN/Tn5mq5rp2KqM6oxVk3WK9q1YaVaGvXiZXrwsSOOKJqNYxqJsjUROiIidNkP1DDHXhZFExsUUbUaxjE2a1E6IiIngh+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9divFbgkgniZNBI1WPjkajmuavRUVF6KikC7gjgsZI6bStrI6GsLuu2n7CRVd19K1Ho+uq79d+z3+U6EAOeNj4nabXpNgNbVGouySNkxNxE9G6p20Ujt/+GJOvydfDeMsGLXk1PpfUmlXIi7zWaC3K3T0rPUWZjG/Asis+DZF6HRABodLa901riF8undQYzOMZ79cfbjn5PQqORqryqi9FRfBTfEzqfhnpLWc7bGc05jMnbYm0dueqxZ4+m27Jdudi7dN2qnQ0TeDy4hyO05rLVGARq7pXfkO8YF/4eS42ZWt+Rjm7ehUA6GDnXYcVMF+92tLavhTwZPFPiJ9vle1bDHO/Qxifo8TyvFbJ4hdtRaA1LjGN8bWOgjysC/8AK2s58y/2xIB0QEXhuM+h87fShW1Rjo8nvt3dcm8mt/MS8sn/ANJaAAAAAAAAAaLMss4i73zXWzZqsi5LWMqVo3vmVXNRJkVdnq6NqO3aiu5m7o1rncqG7ZI2RvM1Ucm6punwp0U/RPW6EmmlmvYqsi0U8pt3cbWi5pbMrmo7mh6oiPVzV3b0Ryyucq83VQoQSdjirpOprLA6TmzUEepM5UfeoYxzXdtLAxN1e5u34NNkdtz8vNyPRN1Y7asAAAAAazU2pcZo7T2RzmZtsoYrHQPs2rMiKqRxtTdy7Iiqq7J0REVVXoiKqgbMl9W6snx1mHC4SGK/qa5Gr4K8q/gq8e+y2J9uqRovTZOr181vpVukp8XsbrvF41eHtupqW1lazbkNpquWpSrucre3sqmzmqite1sHmyPexzfMRkskVNpTSVfStWbaebIZG07tbuTtqiz2pP5TlRERETwaxqI1qdGoiAedIaUr6QxLqsUr7dqeeS3cuzfvlqxIvM+R3/kjWp0Y1rGN2a1qJvAAAAAAAAAAAAAAE5qXiRpLRn8P6nw+EXw5chfigVV+BEc5FVfkAowc893XTNtyMxEGc1E923K7EYO3PCu//wAfs0hT+16HhNf60ym/dPDS7WRfey6iytWmx3y7QOsPRP0sRfkA6IDnfkXFXLp+Fyuk9MsX3zK1Gxk5ET/hkfJA1F+VY1/QPcqy2RVHZviLqjINXxr0n18dEn6FgibL/wCMigdAnnjrQvlmkZFExN3Pe5GtanwqqkRkOOegsfMsDdUUcjbRVatTEOdkLCKm26dlAj379U6bek9VfgHoGOVJbmnYc7OnVJ9QTS5WTffffntPkXfdPHcuKGOqYqqytSqw06zPew140Yxv6ETogEInFXJZR3LgdAanyTVTdtm9BFjIU6bpzJZeyVP7IlVPSh4/9quc9VdIRL/SMxNt/wDxmtd/fRPlOiADnfuR2Mvuuptb6mzzXe+q17iYuunyIlRsT1b8j5H79UXdOhR6X4eaZ0UjlwWBx+Lkcmz569drZZOu/nybczl3XxcqlCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1+b09itS0nU8vjKeVqO8a92Bk0a/8AyuRUIx3AjStNebApk9IvRERjdO5KenA3bw/c7Xdgu3o3jXY6GAOeP0nxBwyouI11Vy0LURPJ9TYhkj3bJ6JqzoOVflWN/wCgO1nrzCLtluH6ZWJETefTGWinX5VWKyldU/Q1z1+Ddeh0MAc993jSFORY83au6TkRdnLqPHz4+JP0TysSJyfK16oWuJzWPz9JlzGX62RqP97YqTNljd+hzVVFMxURyKioiovRUUictwT0Nl7Ult+mqVLISKivyGLRaNtypvtvPArJOm67ed03UC3Bzt3C/N4pebT3ELUFFjURG1Mt2OUr/wDzOmZ26/PJ8p8CcAdT+yGxvGnUOrdIaRy+e0tqLLWMhbpZGquPpW2SSucj2dpI5sEmzk22e/l6IqvTxD+n5GZ7i5prA2ZKq25MhbjVUfBj4nTKxU8Uc5PMavyK5F+QkOKmvLNu1Lp2jJ5PHE1qZGaF68znqiO7FjunTZUVy+K7onTzkOcxRMgjbHGxsbGpsjWpsif2H0/Yf6RGNRGLjzMROqI/J4Q+XslwQ4lYjj5T4m47UUmq8rFko8hNby7EpzToioixqxjnta3kTkRqKjWt2aiIiIffXu/Yr4hznzdf7Y5QD1/7P2TZPMzcHV/d+xXxDnPm6/2w937FfEOc+br/AGxygD+z9k3Z5mbg6v7v2K+Ic583X+2OKey51VneNPCKfR+jcbaoT5C1F5dNk3RxsWs1VcrU5HPVVV6M+Doi/CbQD+z9k3Z5mbg577CvSGT9jazKw6g1Fk7eLyTed+Fq0EkqQ2N2olhr0er+bkarVRrE5kVu+/I3b7T09qnE6qqusYm/FdjYqJI1i7PjVeqI9i7OYu3XZyIp83Hto27OJyMOQoTLVvQ+9lb4OT0sem6czF9LV/SmyoipzY/9Fwaqf9GZiecF4l9Qg4fxJ9lto7hNwzr6n1A96ZGdZK8OFrLzTTWY0bzsaq9EYnOx3Ou3mvau26o05Z7E/wBmlqbjimtUvaIyOYtUr0UtODALXSOtWlYrWRSOnkiRFR0L3c6vVXLI5ERqMRD42uirDqmiuLTA+wwc7TUXEzLKnkejcJhYV/3uZzjpJm//AKMEL2r86h5bpbiNk13yWvMdi41RU7PT+BRj29P5yzLOjlT4ezRPkMB0MwcvncbgK6T5TIVMbAq7JLbnbE3/AMXKiEW3gxTuKi5vVGrNQO5Va5LGalqRv3335o6nYxr4+Ct28OnQzcNwV0DgLTbdLR2FZeT/AN9kpRy2V/TK9Fevp8V9IGE7j/oObmTGZ32yOavLy6bqT5Vd/g/czJPg/s9J4Xijm8iu2F4caluNVN0s31q4+Hw9KSzJMn9kSnQmtRjUa1Ea1E2RE8EPIHPPK+KuWavJjtJaZRV8189uzlXonwuY2OuiL4dEev6TwnD/AFlk1RcvxLvwJ+VDp/F1acbvk3mbYkRP0PRflOiADnacCNL2kVcxLm9SOcmzm5rN27MTv/0Fk7JP7GIUemuHmldGtRuA01iMIib/AMHUYoP0+8ahQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPlGhcfk4HX5F3luyPtvXffzpHK9f8WxkHsu4d+msvkcNI3kWjYeyNP5ULl5onfLuxzf7UcnoU0uos5ZwcML62DyOcdI5UWPHLAjo/ld2srE2/Qqn6rFdM0xXTq8vRKtctsSnE/XbeHekZ8sldbdlZYqtavs5eeaR6MbujUc5URV3VGoqqiKiIq7HpTX2U5VX2g6l3RUTl5qG6//AMr/AP7c1+eqP4sYe1gMnpzPabjcjbEGTndV3gmje10bmdnM9eZHIi9U2VEVFXqaa8SaqJjD/V5eEojU426no4jU0trHQXH4/DT5OtkI8RfpVklj2/AyNsI1XKu+6K13VGu6IUEXE3OabztWLVcWM7tv4e1l4X4xsnPXSujHSRvV7lSTzZEVHIjOqe9Nnb4e6jz2kNR4PP6vZk1ytF1KKWLFsgbX3a5Fk5UeqvcvMm6cyJ5vREMzNcNK+ezOBt27XPVx2MuYyWr2X+0MsMia5ebm83ZI16bLvzeKbdeaKMe14mfLXbb4+c+XEc1yGb1dqbNcK8znK+JpYrIZltmpTqdo6zAjqk7mJK9V5XqrFXflRuy9Op345Nj+D2cxa6ZS1q6TM4vTFjymjRXGxsnkY2F8bI3S9oiOcjX7I7ZE6dU67pTpr/Kqv4gamT5eah96M8DNh3nEibz+/lGy4sgRnugZX/8Ax/qb+9Q+9Fk1eZqKqK3dPBfFDsprirV9kWPCfF43UGV1BhMvjquWxtqtDYfUvQsmiVzXPYq8jkVOqK1P/lQudAcCdCcK89lMvpHT8Wn7eTY2O4ylPKyvMjV3aqwc/ZbtVXbORu6I5yIqI5d9DwJxD3SZrNuT8DMrKVddvfJGrlkcnwpzu5f0xqdbPgf6tVTV2yvLw52hskAB5CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACM4icPWawgZbpvjrZquxWQyybpHK3ffs5Nuu2++zkRVaqqqIqK5ruG5eKzpydYMzUmxMiLtzWW7RO/wCWRPMd/Yu/woh9SnhzUcio5EVF8UU9vsf9UxOy093VGan7fuvh5vk/vej+e1+vX99b+0d70fz2v8639p9RuweOcqquPqqq+KrC39g7ixvxfU+Yb+w9X+/Uf8c8/wDxLQ+XO96P57X+db+0d70fz2v8639p9R9xY34vqfMN/YO4sb8X1PmG/sH9+o/455/+FofLne9H89r/ADrf2jvej+e1/nW/tPqPuLG/F9T5hv7B3Fjfi+p8w39g/v1H/HPP/wALQ+W3ZrHtVEW9X5l8GpK1VX9Cb9Sv0pw7y+rp2OlgsYnE7or7c7OSSRvpbEx3nIq/ynIiJvunNtsd7r46pTcroKsMCr6Y40b/ANDIObG/rldVOXCoyztmb/hfCGNjcbWw9CClThbXqwMSOONvg1E/6/pXxMkA+ZmZmbygACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/Z", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from climateqa.engine.graph import make_graph_agent, display_graph\n", + "\n", + "app = make_graph_agent(llm=llm, vectorstore_ipcc=vectorstore, vectorstore_graphs=vectorstore_graphs, reranker=reranker)\n", + "display_graph(app)" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "'Metadata' object is not subscriptable", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[34], line 52\u001b[0m\n\u001b[1;32m 50\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m event[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mname\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;129;01min\u001b[39;00m steps_display\u001b[38;5;241m.\u001b[39mkeys() \u001b[38;5;129;01mand\u001b[39;00m event[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mevent\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mon_chain_start\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;66;03m#display steps\u001b[39;00m\n\u001b[1;32m 51\u001b[0m event_description,display_output \u001b[38;5;241m=\u001b[39m steps_display[node]\n\u001b[0;32m---> 52\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mhasattr\u001b[39m(history[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m], \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmetadata\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m \u001b[43mhistory\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmetadata\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mtitle\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m \u001b[38;5;241m!=\u001b[39m event_description: \u001b[38;5;66;03m# if a new step begins\u001b[39;00m\n\u001b[1;32m 53\u001b[0m history\u001b[38;5;241m.\u001b[39mappend(ChatMessage(role\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124massistant\u001b[39m\u001b[38;5;124m\"\u001b[39m, content \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m, metadata\u001b[38;5;241m=\u001b[39m{\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtitle\u001b[39m\u001b[38;5;124m'\u001b[39m :event_description}))\n\u001b[1;32m 55\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m event[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mname\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m!=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtransform_query\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m event[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mevent\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mon_chat_model_stream\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m node \u001b[38;5;129;01min\u001b[39;00m [\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124manswer_rag\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124manswer_search\u001b[39m\u001b[38;5;124m\"\u001b[39m]:\u001b[38;5;66;03m# if streaming answer\u001b[39;00m\n", + "\u001b[0;31mTypeError\u001b[0m: 'Metadata' object is not subscriptable" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Categorize_message ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "Output intent categorization: {'intent': 'search'}\n", + "\n", + "---- Transform query ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Retrieving graphs ----\n", + "Subquestion 0: What is radiative forcing?\n", + "8 graphs retrieved for subquestion 1: [Document(metadata={'category': 'Energy', 'doc_id': 'owid_971', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Energy intensity is measured as primary energy consumption per unit of gross domestic product (GDP), in kilowatt-hours per dollar. GDP is adjusted for inflation and differences in the cost of living between countries.', 'url': 'https://ourworldindata.org/grapher/energy-intensity', 'similarity_score': 0.9688466787338257, 'content': 'Energy intensity', 'reranking_score': 1.0006295269704424e-05, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Energy intensity'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_342', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions factors quantify the average CO₂ output per unit of energy. They are measured in kilograms of CO₂ per megawatt-hour (MWh) of energy from various fossil fuel sources.', 'url': 'https://ourworldindata.org/grapher/carbon-dioxide-emissions-factor', 'similarity_score': 1.0487818717956543, 'content': 'Carbon dioxide emissions factors', 'reranking_score': 9.884071005217265e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Carbon dioxide emissions factors'), Document(metadata={'category': 'Ozone Layer', 'doc_id': 'owid_1847', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Ozone-depleting substance emissions are measured in ODP tonnes.', 'url': 'https://ourworldindata.org/grapher/ozone-depleting-substance-emissions', 'similarity_score': 1.0677553415298462, 'content': 'Ozone-depleting substance emissions', 'reranking_score': 9.861145372269675e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Ozone-depleting substance emissions'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_345', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Amount of carbon dioxide emitted per unit of energy production, measured in kilograms of CO₂ per kilowatt-hour.', 'url': 'https://ourworldindata.org/grapher/co2-per-unit-energy', 'similarity_score': 1.072110891342163, 'content': 'Carbon intensity of energy production', 'reranking_score': 9.729433259053621e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Carbon intensity of energy production'), Document(metadata={'category': 'Energy', 'doc_id': 'owid_1013', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Share of primary energy by source over the long-term, measured as the percentage of total energy consumption. Primary electricity includes: hydropower, nuclear power, wind, photo\\xadvoltaics, tidal, wave and solar thermal and geothermal (only figures for electricity production are included).', 'url': 'https://ourworldindata.org/grapher/long-term-energy-transitions', 'similarity_score': 1.0745391845703125, 'content': 'Long-term energy transitions', 'reranking_score': 9.729433259053621e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Long-term energy transitions'), Document(metadata={'category': 'Energy', 'doc_id': 'owid_1082', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Direct primary energy measures the amount of electricity generated from power plants. Substituted primary energy estimates the amount of energy required by power plants if these sources had the same inefficiencies as fossil fuels. Measured in terawatt-hours.', 'url': 'https://ourworldindata.org/grapher/renewable-nuclear-direct-substitution', 'similarity_score': 1.0793521404266357, 'content': 'Renewable and nuclear energy: direct vs. substituted energy', 'reranking_score': 9.676273293734994e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Renewable and nuclear energy: direct vs. substituted energy'), Document(metadata={'category': 'Climate Change', 'doc_id': 'owid_780', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Nationally determined contributions (NDCs) embody efforts by each country to reduce national emissions and adapt to the impacts of climate change. The Paris Agreement requires each of the 193 Parties to prepare, communicate and maintain NDCs outlining what they intend to achieve. NDCs must be updated every five years.', 'url': 'https://ourworldindata.org/grapher/nationally-determined-contributions', 'similarity_score': 1.0885636806488037, 'content': 'Nationally determined contributions to climate change', 'reranking_score': 9.672482519818004e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Nationally determined contributions to climate change'), Document(metadata={'category': 'Natural Disasters', 'doc_id': 'owid_1728', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Accumulated cyclone energy (ACE) is an index used to measure the activity of a cyclone/hurricane season. It combines the number of hurricane systems, how long they existed and how intense they became.', 'url': 'https://ourworldindata.org/grapher/ace-north-atlantic-hurricanes', 'similarity_score': 1.088597297668457, 'content': 'Accumulated cyclone energy of North Atlantic hurricanes', 'reranking_score': 9.653728739067446e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Accumulated cyclone energy of North Atlantic hurricanes')]\n", + "Subquestion 1: What are the impacts of radiative forcing on the climate?\n", + "7 graphs retrieved for subquestion 2: [Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_386', 'returned_content': '', 'source': 'OWID', 'subtitle': \"This is shown as a country or region's share of the global mean surface temperature change as a result of its cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/contributions-global-temp-change', 'similarity_score': 0.8161638975143433, 'content': 'Global warming: Contributions to the change in global mean surface temperature', 'reranking_score': 0.03297441452741623, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Global warming: Contributions to the change in global mean surface temperature'), Document(metadata={'category': 'Climate Change', 'doc_id': 'owid_780', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Nationally determined contributions (NDCs) embody efforts by each country to reduce national emissions and adapt to the impacts of climate change. The Paris Agreement requires each of the 193 Parties to prepare, communicate and maintain NDCs outlining what they intend to achieve. NDCs must be updated every five years.', 'url': 'https://ourworldindata.org/grapher/nationally-determined-contributions', 'similarity_score': 0.8179692625999451, 'content': 'Nationally determined contributions to climate change', 'reranking_score': 2.881309228541795e-05, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Nationally determined contributions to climate change'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_342', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions factors quantify the average CO₂ output per unit of energy. They are measured in kilograms of CO₂ per megawatt-hour (MWh) of energy from various fossil fuel sources.', 'url': 'https://ourworldindata.org/grapher/carbon-dioxide-emissions-factor', 'similarity_score': 0.8352534770965576, 'content': 'Carbon dioxide emissions factors', 'reranking_score': 1.8446306057740003e-05, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Carbon dioxide emissions factors'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_357', 'returned_content': '', 'source': 'OWID', 'subtitle': \"The global mean surface temperature change as a result of a country or region's cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/contribution-temp-rise-degrees', 'similarity_score': 0.8398256301879883, 'content': 'Contribution to global mean surface temperature rise', 'reranking_score': 1.7488076991867274e-05, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Contribution to global mean surface temperature rise'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_383', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The global mean surface temperature change as a result of the cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.', 'url': 'https://ourworldindata.org/grapher/global-warming-by-gas-and-source', 'similarity_score': 0.8541404008865356, 'content': 'Global warming contributions by gas and source', 'reranking_score': 1.7253492842428386e-05, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Global warming contributions by gas and source'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_358', 'returned_content': '', 'source': 'OWID', 'subtitle': \"The global mean surface temperature change as a result of a country or region's cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/contribution-to-temp-rise-by-gas', 'similarity_score': 0.8612645864486694, 'content': 'Contribution to global mean surface temperature rise by gas', 'reranking_score': 1.544259794172831e-05, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Contribution to global mean surface temperature rise by gas'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_384', 'returned_content': '', 'source': 'OWID', 'subtitle': \"The global mean surface temperature change as a result of a country or region's cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/warming-fossil-fuels-land-use', 'similarity_score': 0.8817370533943176, 'content': 'Global warming contributions from fossil fuels and land use', 'reranking_score': 1.4706844012835063e-05, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Global warming contributions from fossil fuels and land use')]\n", + "---- Retrieve documents ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:langchain_core.callbacks.manager:Error in LogStreamCallbackHandler.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LogStreamCallbackHandler.on_chain_end callback: TracerException('No indexed run ID 7fa2a01f-9254-4273-ae99-1413a7d105cc.')\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_end callback: TracerException('No indexed run ID 7fa2a01f-9254-4273-ae99-1413a7d105cc.')\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Retrieve documents ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:langchain_core.callbacks.manager:Error in LogStreamCallbackHandler.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LogStreamCallbackHandler.on_chain_end callback: TracerException('No indexed run ID 0910f30c-f64d-4a7b-a032-b269da2e8852.')\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_end callback: TracerException('No indexed run ID 0910f30c-f64d-4a7b-a032-b269da2e8852.')\n", + "WARNING:langchain_core.callbacks.manager:Error in LogStreamCallbackHandler.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LogStreamCallbackHandler.on_chain_end callback: TracerException('No indexed run ID 809958e3-d092-413d-91ad-a52c9de80590.')\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_end callback: TracerException('No indexed run ID 809958e3-d092-413d-91ad-a52c9de80590.')\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Answer RAG ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "Answer:\n", + "Radiative forcing is a key concept in understanding climate change. It refers to the balance between energy coming into the Earth's atmosphere and the energy being emitted back out. When there is more energy coming in than going out, it leads to warming, and when there is more energy going out than coming in, it leads to cooling.\n", + "\n", + "- Human activities, such as the increase in greenhouse gas concentrations, have caused a significant radiative forcing of 2.72 W m-2 in 2019 compared to 1750 [Doc 1]. This extra energy has warmed the climate system, with most of the warming attributed to greenhouse gases and partially offset by cooling from increased aerosol concentrations.\n", + "\n", + "- The additional energy accumulated in the climate system due to human-caused radiative forcing has led to an increase in the average rate of heating. From 1971-2006 to 2006-2018, the observed heating of the climate system has increased, with ocean warming being the primary contributor [Doc 3].\n", + "\n", + "- The impact of radiative forcing can be seen in the global temperature changes observed from 2010-2019 compared to the pre-industrial period. Human activities, particularly greenhouse gas emissions, have been a significant factor contributing to global warming, while aerosols have partially offset this effect [Doc 5].\n", + "\n", + "- It's important to note that radiative forcing can have both warming and cooling effects on the climate system. Positive radiative forcing leads to warming, while negative radiative forcing leads to cooling. The Earth responds to these forcings by adjusting its temperature to restore balance, which can result in additional changes in the climate system known as climate feedbacks [Doc 7].\n", + "\n", + "In summary, radiative forcing from human activities has significantly impacted the climate system by causing warming, which has implications for global temperature changes and the overall climate.\n" + ] + } + ], + "source": [ + "from climateqa.engine.chains.prompts import audience_prompts\n", + "from front.utils import make_html_source,parse_output_llm_with_sources,serialize_docs,make_toolbox,generate_html_graphs\n", + "from gradio import ChatMessage\n", + "init_prompt = \"\"\n", + "\n", + "docs = []\n", + "docs_used = True\n", + "docs_html = \"\"\n", + "current_graphs = []\n", + "output_query = \"\"\n", + "output_language = \"\"\n", + "output_keywords = \"\"\n", + "gallery = []\n", + "updates = []\n", + "start_streaming = False\n", + "\n", + "steps_display = {\n", + " \"categorize_intent\":(\"🔄️ Analyzing user message\",True),\n", + " \"transform_query\":(\"🔄️ Thinking step by step to answer the question\",True),\n", + " \"retrieve_documents\":(\"🔄️ Searching in the knowledge base\",False),\n", + "}\n", + "query = \"what is the impact of radiative forcing\"\n", + "inputs = {\"user_input\": query,\"audience\": audience_prompts[\"general\"] ,\"sources\": [\"IPCC\", \"IPBES\", \"IPOS\"]}\n", + "history = [ChatMessage(role=\"assistant\", content=init_prompt)]\n", + "history + [ChatMessage(role=\"user\", content=query)]\n", + "\n", + "\n", + "result = app.astream_events(inputs,version = \"v1\") #{\"callbacks\":[MyCustomAsyncHandler()]})\n", + "\n", + "async for event in result:\n", + " if \"langgraph_node\" in event[\"metadata\"]:\n", + " node = event[\"metadata\"][\"langgraph_node\"]\n", + "\n", + " if event[\"event\"] == \"on_chain_end\" and event[\"name\"] == \"retrieve_documents\" :# when documents are retrieved\n", + " try:\n", + " docs = event[\"data\"][\"output\"][\"documents\"]\n", + " docs_html = []\n", + " for i, d in enumerate(docs, 1):\n", + " docs_html.append(make_html_source(d, i))\n", + " \n", + " used_documents = used_documents + [d.metadata[\"name\"] for d in docs]\n", + " history[-1].content = \"Adding sources :\\n\\n - \" + \"\\n - \".join(np.unique(used_documents))\n", + " \n", + " docs_html = \"\".join(docs_html)\n", + " \n", + " except Exception as e:\n", + " print(f\"Error getting documents: {e}\")\n", + " print(event)\n", + "\n", + " elif event[\"name\"] in steps_display.keys() and event[\"event\"] == \"on_chain_start\": #display steps\n", + " event_description,display_output = steps_display[node]\n", + " if not hasattr(history[-1], 'metadata') or history[-1].metadata[\"title\"] != event_description: # if a new step begins\n", + " history.append(ChatMessage(role=\"assistant\", content = \"\", metadata={'title' :event_description}))\n", + "\n", + " elif event[\"name\"] != \"transform_query\" and event[\"event\"] == \"on_chat_model_stream\" and node in [\"answer_rag\", \"answer_search\"]:# if streaming answer\n", + " if start_streaming == False:\n", + " start_streaming = True\n", + " history.append(ChatMessage(role=\"assistant\", content = \"\"))\n", + " answer_message_content += event[\"data\"][\"chunk\"].content\n", + " answer_message_content = parse_output_llm_with_sources(answer_message_content)\n", + " history[-1] = ChatMessage(role=\"assistant\", content = answer_message_content)\n", + " \n", + " elif event[\"name\"] in [\"retrieve_graphs\", \"retrieve_graphs_ai\"] and event[\"event\"] == \"on_chain_end\":\n", + " try:\n", + " recommended_content = event[\"data\"][\"output\"][\"recommended_content\"]\n", + " # graphs = [\n", + " # {\n", + " # \"embedding\": x.metadata[\"returned_content\"],\n", + " # \"metadata\": {\n", + " # \"source\": x.metadata[\"source\"],\n", + " # \"category\": x.metadata[\"category\"]\n", + " # }\n", + " # } for x in recommended_content if x.metadata[\"source\"] == \"OWID\"\n", + " # ]\n", + " \n", + " unique_graphs = []\n", + " seen_embeddings = set()\n", + "\n", + " for x in recommended_content:\n", + " embedding = x.metadata[\"returned_content\"]\n", + " \n", + " # Check if the embedding has already been seen\n", + " if embedding not in seen_embeddings:\n", + " unique_graphs.append({\n", + " \"embedding\": embedding,\n", + " \"metadata\": {\n", + " \"source\": x.metadata[\"source\"],\n", + " \"category\": x.metadata[\"category\"]\n", + " }\n", + " })\n", + " # Add the embedding to the seen set\n", + " seen_embeddings.add(embedding)\n", + "\n", + "\n", + " categories = {}\n", + " for graph in unique_graphs:\n", + " category = graph['metadata']['category']\n", + " if category not in categories:\n", + " categories[category] = []\n", + " categories[category].append(graph['embedding'])\n", + "\n", + " # graphs_html = \"\"\n", + " for category, embeddings in categories.items():\n", + " # graphs_html += f\"

{category}

\"\n", + " # current_graphs.append(f\"

{category}

\")\n", + " for embedding in embeddings:\n", + " current_graphs.append([embedding, category])\n", + " # graphs_html += f\"
{embedding}
\"\n", + " \n", + " except Exception as e:\n", + " print(f\"Error getting graphs: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "'Metadata' object is not subscriptable", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[31], line 152\u001b[0m\n\u001b[1;32m 150\u001b[0m node \u001b[38;5;241m=\u001b[39m event[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmetadata\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mlanggraph_node\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n\u001b[1;32m 151\u001b[0m event_description,display_output \u001b[38;5;241m=\u001b[39m steps_display[node]\n\u001b[0;32m--> 152\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mhasattr\u001b[39m(history[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m], \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmetadata\u001b[39m\u001b[38;5;124m'\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m \u001b[43mhistory\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m-\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmetadata\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mtitle\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m \u001b[38;5;241m!=\u001b[39m event_description: \u001b[38;5;66;03m# if a new step begins\u001b[39;00m\n\u001b[1;32m 153\u001b[0m history\u001b[38;5;241m.\u001b[39mappend(ChatMessage(role\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124massistant\u001b[39m\u001b[38;5;124m\"\u001b[39m, content \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m\"\u001b[39m, metadata\u001b[38;5;241m=\u001b[39m{\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtitle\u001b[39m\u001b[38;5;124m'\u001b[39m :event_description}))\n\u001b[1;32m 155\u001b[0m \u001b[38;5;66;03m# for event_name,(event_description,display_output) in steps_display.items():\u001b[39;00m\n\u001b[1;32m 156\u001b[0m \u001b[38;5;66;03m# if event[\"name\"] == event_name:\u001b[39;00m\n\u001b[1;32m 157\u001b[0m \u001b[38;5;66;03m# if event[\"event\"] == \"on_chain_start\":\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 184\u001b[0m \n\u001b[1;32m 185\u001b[0m \u001b[38;5;66;03m# history = [tuple(x) for x in history]\u001b[39;00m\n", + "\u001b[0;31mTypeError\u001b[0m: 'Metadata' object is not subscriptable" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Categorize_message ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "Output intent categorization: {'intent': 'search'}\n", + "\n", + "---- Transform query ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Retrieving graphs ----\n", + "Subquestion 0: What is radiative forcing?\n", + "8 graphs retrieved for subquestion 1: [Document(metadata={'category': 'Energy', 'doc_id': 'owid_971', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Energy intensity is measured as primary energy consumption per unit of gross domestic product (GDP), in kilowatt-hours per dollar. GDP is adjusted for inflation and differences in the cost of living between countries.', 'url': 'https://ourworldindata.org/grapher/energy-intensity', 'similarity_score': 0.9688466787338257, 'content': 'Energy intensity', 'reranking_score': 1.0006295269704424e-05, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Energy intensity'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_342', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions factors quantify the average CO₂ output per unit of energy. They are measured in kilograms of CO₂ per megawatt-hour (MWh) of energy from various fossil fuel sources.', 'url': 'https://ourworldindata.org/grapher/carbon-dioxide-emissions-factor', 'similarity_score': 1.0487818717956543, 'content': 'Carbon dioxide emissions factors', 'reranking_score': 9.884071005217265e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Carbon dioxide emissions factors'), Document(metadata={'category': 'Ozone Layer', 'doc_id': 'owid_1847', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Ozone-depleting substance emissions are measured in ODP tonnes.', 'url': 'https://ourworldindata.org/grapher/ozone-depleting-substance-emissions', 'similarity_score': 1.0677553415298462, 'content': 'Ozone-depleting substance emissions', 'reranking_score': 9.861145372269675e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Ozone-depleting substance emissions'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_345', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Amount of carbon dioxide emitted per unit of energy production, measured in kilograms of CO₂ per kilowatt-hour.', 'url': 'https://ourworldindata.org/grapher/co2-per-unit-energy', 'similarity_score': 1.072110891342163, 'content': 'Carbon intensity of energy production', 'reranking_score': 9.729433259053621e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Carbon intensity of energy production'), Document(metadata={'category': 'Energy', 'doc_id': 'owid_1013', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Share of primary energy by source over the long-term, measured as the percentage of total energy consumption. Primary electricity includes: hydropower, nuclear power, wind, photo\\xadvoltaics, tidal, wave and solar thermal and geothermal (only figures for electricity production are included).', 'url': 'https://ourworldindata.org/grapher/long-term-energy-transitions', 'similarity_score': 1.0745391845703125, 'content': 'Long-term energy transitions', 'reranking_score': 9.729433259053621e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Long-term energy transitions'), Document(metadata={'category': 'Energy', 'doc_id': 'owid_1082', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Direct primary energy measures the amount of electricity generated from power plants. Substituted primary energy estimates the amount of energy required by power plants if these sources had the same inefficiencies as fossil fuels. Measured in terawatt-hours.', 'url': 'https://ourworldindata.org/grapher/renewable-nuclear-direct-substitution', 'similarity_score': 1.0793521404266357, 'content': 'Renewable and nuclear energy: direct vs. substituted energy', 'reranking_score': 9.676273293734994e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Renewable and nuclear energy: direct vs. substituted energy'), Document(metadata={'category': 'Climate Change', 'doc_id': 'owid_780', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Nationally determined contributions (NDCs) embody efforts by each country to reduce national emissions and adapt to the impacts of climate change. The Paris Agreement requires each of the 193 Parties to prepare, communicate and maintain NDCs outlining what they intend to achieve. NDCs must be updated every five years.', 'url': 'https://ourworldindata.org/grapher/nationally-determined-contributions', 'similarity_score': 1.0885636806488037, 'content': 'Nationally determined contributions to climate change', 'reranking_score': 9.672482519818004e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Nationally determined contributions to climate change'), Document(metadata={'category': 'Natural Disasters', 'doc_id': 'owid_1728', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Accumulated cyclone energy (ACE) is an index used to measure the activity of a cyclone/hurricane season. It combines the number of hurricane systems, how long they existed and how intense they became.', 'url': 'https://ourworldindata.org/grapher/ace-north-atlantic-hurricanes', 'similarity_score': 1.088597297668457, 'content': 'Accumulated cyclone energy of North Atlantic hurricanes', 'reranking_score': 9.653728739067446e-06, 'query_used_for_retrieval': 'What is radiative forcing?', 'sources_used': ['IEA', 'OWID']}, page_content='Accumulated cyclone energy of North Atlantic hurricanes')]\n", + "Subquestion 1: What are the impacts of radiative forcing on the climate?\n", + "7 graphs retrieved for subquestion 2: [Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_386', 'returned_content': '', 'source': 'OWID', 'subtitle': \"This is shown as a country or region's share of the global mean surface temperature change as a result of its cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/contributions-global-temp-change', 'similarity_score': 0.8161638975143433, 'content': 'Global warming: Contributions to the change in global mean surface temperature', 'reranking_score': 0.03297441452741623, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Global warming: Contributions to the change in global mean surface temperature'), Document(metadata={'category': 'Climate Change', 'doc_id': 'owid_780', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Nationally determined contributions (NDCs) embody efforts by each country to reduce national emissions and adapt to the impacts of climate change. The Paris Agreement requires each of the 193 Parties to prepare, communicate and maintain NDCs outlining what they intend to achieve. NDCs must be updated every five years.', 'url': 'https://ourworldindata.org/grapher/nationally-determined-contributions', 'similarity_score': 0.8179692625999451, 'content': 'Nationally determined contributions to climate change', 'reranking_score': 2.881309228541795e-05, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Nationally determined contributions to climate change'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_342', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions factors quantify the average CO₂ output per unit of energy. They are measured in kilograms of CO₂ per megawatt-hour (MWh) of energy from various fossil fuel sources.', 'url': 'https://ourworldindata.org/grapher/carbon-dioxide-emissions-factor', 'similarity_score': 0.8352534770965576, 'content': 'Carbon dioxide emissions factors', 'reranking_score': 1.8446306057740003e-05, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Carbon dioxide emissions factors'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_357', 'returned_content': '', 'source': 'OWID', 'subtitle': \"The global mean surface temperature change as a result of a country or region's cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/contribution-temp-rise-degrees', 'similarity_score': 0.8398256301879883, 'content': 'Contribution to global mean surface temperature rise', 'reranking_score': 1.7488076991867274e-05, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Contribution to global mean surface temperature rise'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_383', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The global mean surface temperature change as a result of the cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.', 'url': 'https://ourworldindata.org/grapher/global-warming-by-gas-and-source', 'similarity_score': 0.8541404008865356, 'content': 'Global warming contributions by gas and source', 'reranking_score': 1.7253492842428386e-05, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Global warming contributions by gas and source'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_358', 'returned_content': '', 'source': 'OWID', 'subtitle': \"The global mean surface temperature change as a result of a country or region's cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/contribution-to-temp-rise-by-gas', 'similarity_score': 0.8612645864486694, 'content': 'Contribution to global mean surface temperature rise by gas', 'reranking_score': 1.544259794172831e-05, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Contribution to global mean surface temperature rise by gas'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_384', 'returned_content': '', 'source': 'OWID', 'subtitle': \"The global mean surface temperature change as a result of a country or region's cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/warming-fossil-fuels-land-use', 'similarity_score': 0.8817370533943176, 'content': 'Global warming contributions from fossil fuels and land use', 'reranking_score': 1.4706844012835063e-05, 'query_used_for_retrieval': 'What are the impacts of radiative forcing on the climate?', 'sources_used': ['IEA', 'OWID']}, page_content='Global warming contributions from fossil fuels and land use')]\n", + "---- Retrieve documents ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:langchain_core.callbacks.manager:Error in LogStreamCallbackHandler.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LogStreamCallbackHandler.on_chain_end callback: TracerException('No indexed run ID fb7dec36-256b-4fd7-9a88-71f23a7c0d02.')\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_end callback: TracerException('No indexed run ID fb7dec36-256b-4fd7-9a88-71f23a7c0d02.')\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Retrieve documents ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:langchain_core.callbacks.manager:Error in LogStreamCallbackHandler.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LogStreamCallbackHandler.on_chain_end callback: TracerException('No indexed run ID 4812026a-1015-4c17-89cf-496db5498fad.')\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_end callback: TracerException('No indexed run ID 4812026a-1015-4c17-89cf-496db5498fad.')\n", + "WARNING:langchain_core.callbacks.manager:Error in LogStreamCallbackHandler.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LogStreamCallbackHandler.on_chain_end callback: TracerException('No indexed run ID 9fdebdaf-73d1-4e40-83d6-7ada560f3ebb.')\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_end callback: TracerException('No indexed run ID 9fdebdaf-73d1-4e40-83d6-7ada560f3ebb.')\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Answer RAG ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "Answer:\n", + "Radiative forcing is a key concept in understanding climate change. It refers to the balance between energy entering and leaving the Earth's atmosphere, which affects the temperature of our planet. When there is a positive radiative forcing, it means there is more energy coming in than going out, leading to warming. Conversely, a negative radiative forcing results in cooling.\n", + "\n", + "Human activities, such as the release of greenhouse gases and aerosols, have caused a significant increase in radiative forcing over the past century. This additional energy in the climate system has led to warming, with most of the heat being absorbed by the oceans. The warming of the climate system has been observed to increase over time, indicating a buildup of energy in the Earth's system.\n", + "\n", + "It's important to note that while greenhouse gases contribute to warming, aerosols have a cooling effect that partially offsets the warming caused by greenhouse gases. This balance between warming and cooling factors is crucial in understanding the overall impact of human activities on climate change.\n", + "\n", + "In response to changes in radiative forcing, the Earth's climate system undergoes adjustments to restore balance. These adjustments can lead to feedback mechanisms that either amplify or dampen the initial warming effect. For example, the melting of Arctic sea ice contributes to further warming by reducing the amount of sunlight reflected back into space.\n", + "\n", + "Overall, radiative forcing plays a significant role in driving climate change, with human activities being a major contributor to the changes observed in the Earth's climate system. By understanding and addressing the factors influencing radiative forcing, we can better comprehend and mitigate the impacts of climate change on our planet. [Doc 1, Doc 3, Doc 5, Doc 7]\n" + ] + } + ], + "source": [ + "from climateqa.engine.chains.prompts import audience_prompts\n", + "from front.utils import make_html_source,parse_output_llm_with_sources,serialize_docs,make_toolbox,generate_html_graphs\n", + "from gradio import ChatMessage\n", + "init_prompt = \"\"\n", + "\n", + "docs = []\n", + "docs_used = True\n", + "docs_html = \"\"\n", + "current_graphs = []\n", + "output_query = \"\"\n", + "output_language = \"\"\n", + "output_keywords = \"\"\n", + "gallery = []\n", + "updates = []\n", + "start_streaming = False\n", + "history = [ChatMessage(role=\"assistant\", content=init_prompt)]\n", + "steps_display = {\n", + " \"categorize_intent\":(\"🔄️ Analyzing user message\",True),\n", + " \"transform_query\":(\"🔄️ Thinking step by step to answer the question\",True),\n", + " \"retrieve_documents\":(\"🔄️ Searching in the knowledge base\",False),\n", + "}\n", + "query = \"what is the impact of radiative forcing\"\n", + "inputs = {\"user_input\": query,\"audience\": audience_prompts[\"general\"] ,\"sources\": [\"IPCC\", \"IPBES\", \"IPOS\"]}\n", + "\n", + "result = app.astream_events(inputs,version = \"v1\") #{\"callbacks\":[MyCustomAsyncHandler()]})\n", + "\n", + "async for event in result:\n", + " if \"langgraph_node\" in event[\"metadata\"]:\n", + " node = event[\"metadata\"][\"langgraph_node\"]\n", + "\n", + " if event[\"event\"] == \"on_chain_end\" and event[\"name\"] == \"retrieve_documents\" :# when documents are retrieved\n", + " try:\n", + " docs = event[\"data\"][\"output\"][\"documents\"]\n", + " docs_html = []\n", + " for i, d in enumerate(docs, 1):\n", + " docs_html.append(make_html_source(d, i))\n", + " \n", + " used_documents = used_documents + [d.metadata[\"name\"] for d in docs]\n", + " history[-1].content = \"Adding sources :\\n\\n - \" + \"\\n - \".join(np.unique(used_documents))\n", + " \n", + " docs_html = \"\".join(docs_html)\n", + " \n", + " except Exception as e:\n", + " print(f\"Error getting documents: {e}\")\n", + " print(event)\n", + "\n", + " elif event[\"name\"] in steps_display.keys() and event[\"event\"] == \"on_chain_start\": #display steps\n", + " event_description,display_output = steps_display[node]\n", + " if not hasattr(history[-1], 'metadata') or history[-1].metadata[\"title\"] != event_description: # if a new step begins\n", + " history.append(ChatMessage(role=\"assistant\", content = \"\", metadata={'title' :event_description}))\n", + "\n", + " elif event[\"name\"] != \"transform_query\" and event[\"event\"] == \"on_chat_model_stream\" and node in [\"answer_rag\", \"answer_search\"]:# if streaming answer\n", + " if start_streaming == False:\n", + " start_streaming = True\n", + " history.append(ChatMessage(role=\"assistant\", content = \"\"))\n", + " answer_message_content += event[\"data\"][\"chunk\"].content\n", + " answer_message_content = parse_output_llm_with_sources(answer_message_content)\n", + " history[-1] = ChatMessage(role=\"assistant\", content = answer_message_content)\n", + " \n", + " elif event[\"name\"] in [\"retrieve_graphs\", \"retrieve_graphs_ai\"] and event[\"event\"] == \"on_chain_end\":\n", + " try:\n", + " recommended_content = event[\"data\"][\"output\"][\"recommended_content\"]\n", + " # graphs = [\n", + " # {\n", + " # \"embedding\": x.metadata[\"returned_content\"],\n", + " # \"metadata\": {\n", + " # \"source\": x.metadata[\"source\"],\n", + " # \"category\": x.metadata[\"category\"]\n", + " # }\n", + " # } for x in recommended_content if x.metadata[\"source\"] == \"OWID\"\n", + " # ]\n", + " \n", + " unique_graphs = []\n", + " seen_embeddings = set()\n", + "\n", + " for x in recommended_content:\n", + " embedding = x.metadata[\"returned_content\"]\n", + " \n", + " # Check if the embedding has already been seen\n", + " if embedding not in seen_embeddings:\n", + " unique_graphs.append({\n", + " \"embedding\": embedding,\n", + " \"metadata\": {\n", + " \"source\": x.metadata[\"source\"],\n", + " \"category\": x.metadata[\"category\"]\n", + " }\n", + " })\n", + " # Add the embedding to the seen set\n", + " seen_embeddings.add(embedding)\n", + "\n", + "\n", + " categories = {}\n", + " for graph in unique_graphs:\n", + " category = graph['metadata']['category']\n", + " if category not in categories:\n", + " categories[category] = []\n", + " categories[category].append(graph['embedding'])\n", + "\n", + " # graphs_html = \"\"\n", + " for category, embeddings in categories.items():\n", + " # graphs_html += f\"

{category}

\"\n", + " # current_graphs.append(f\"

{category}

\")\n", + " for embedding in embeddings:\n", + " current_graphs.append([embedding, category])\n", + " # graphs_html += f\"
{embedding}
\"\n", + " \n", + " except Exception as e:\n", + " print(f\"Error getting graphs: {e}\")\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " # ### old\n", + " # if event[\"event\"] == \"on_chat_model_stream\" and event[\"metadata\"][\"langgraph_node\"] in [\"answer_rag\", \"answer_rag_no_docs\", \"answer_chitchat\", \"answer_ai_impact\"]:\n", + " # if start_streaming == False:\n", + " # start_streaming = True\n", + " # history.append(ChatMessage(role=\"assistant\", content = \"\"))\n", + "\n", + " # answer_message_content += event[\"data\"][\"chunk\"].content\n", + " # answer_message_content = parse_output_llm_with_sources(answer_message_content)\n", + " # history[-1] = ChatMessage(role=\"assistant\", content = answer_message_content)\n", + "\n", + "\n", + " # if docs_used is True and event[\"metadata\"][\"langgraph_node\"] in [\"answer_rag_no_docs\", \"answer_chitchat\", \"answer_ai_impact\"]:\n", + " # docs_used = False\n", + " \n", + " # elif docs_used is True and event[\"name\"] == \"retrieve_documents\" and event[\"event\"] == \"on_chain_end\":\n", + " # try:\n", + " # docs = event[\"data\"][\"output\"][\"documents\"]\n", + " # docs_html = []\n", + " # for i, d in enumerate(docs, 1):\n", + " # docs_html.append(make_html_source(d, i))\n", + " # docs_html = \"\".join(docs_html)\n", + "\n", + " # except Exception as e:\n", + " # print(f\"Error getting documents: {e}\")\n", + " # print(event)\n", + "\n", + " # elif event[\"name\"] == \"retrieve_documents\" and event[\"event\"] == \"on_chain_start\":\n", + " # print(event)\n", + " # questions = event[\"data\"][\"input\"][\"questions\"]\n", + " # questions = \"\\n\".join([f\"{i+1}. {q['question']} ({q['source']})\" for i,q in enumerate(questions)])\n", + " # answer_yet = \"🔄️ Searching in the knowledge base\\n{questions}\"\n", + " # history[-1] = (query,answer_yet)\n", + "\n", + " # elif event[\"name\"] in [\"retrieve_graphs\", \"retrieve_graphs_ai\"] and event[\"event\"] == \"on_chain_end\":\n", + " # try:\n", + " # recommended_content = event[\"data\"][\"output\"][\"recommended_content\"]\n", + " # # graphs = [\n", + " # # {\n", + " # # \"embedding\": x.metadata[\"returned_content\"],\n", + " # # \"metadata\": {\n", + " # # \"source\": x.metadata[\"source\"],\n", + " # # \"category\": x.metadata[\"category\"]\n", + " # # }\n", + " # # } for x in recommended_content if x.metadata[\"source\"] == \"OWID\"\n", + " # # ]\n", + " \n", + " # unique_graphs = []\n", + " # seen_embeddings = set()\n", + "\n", + " # for x in recommended_content:\n", + " # embedding = x.metadata[\"returned_content\"]\n", + " \n", + " # # Check if the embedding has already been seen\n", + " # if embedding not in seen_embeddings:\n", + " # unique_graphs.append({\n", + " # \"embedding\": embedding,\n", + " # \"metadata\": {\n", + " # \"source\": x.metadata[\"source\"],\n", + " # \"category\": x.metadata[\"category\"]\n", + " # }\n", + " # })\n", + " # # Add the embedding to the seen set\n", + " # seen_embeddings.add(embedding)\n", + "\n", + "\n", + " # categories = {}\n", + " # for graph in unique_graphs:\n", + " # category = graph['metadata']['category']\n", + " # if category not in categories:\n", + " # categories[category] = []\n", + " # categories[category].append(graph['embedding'])\n", + "\n", + " # # graphs_html = \"\"\n", + " # for category, embeddings in categories.items():\n", + " # # graphs_html += f\"

{category}

\"\n", + " # # current_graphs.append(f\"

{category}

\")\n", + " # for embedding in embeddings:\n", + " # current_graphs.append([embedding, category])\n", + " # # graphs_html += f\"
{embedding}
\"\n", + " \n", + " # except Exception as e:\n", + " # print(f\"Error getting graphs: {e}\")\n", + "\n", + " # elif event[\"name\"] in steps_display.keys() and event[\"event\"] == \"on_chain_start\": #display steps\n", + " # node = event[\"metadata\"][\"langgraph_node\"]\n", + " # event_description,display_output = steps_display[node]\n", + " # if not hasattr(history[-1], 'metadata') or history[-1].metadata[\"title\"] != event_description: # if a new step begins\n", + " # history.append(ChatMessage(role=\"assistant\", content = \"\", metadata={'title' :event_description}))\n", + "\n", + " # for event_name,(event_description,display_output) in steps_display.items():\n", + " # if event[\"name\"] == event_name:\n", + " # if event[\"event\"] == \"on_chain_start\":\n", + " # # answer_yet = f\"

{event_description}

\"\n", + " # # answer_yet = make_toolbox(event_description, \"\", checked = False)\n", + " # answer_yet = event_description\n", + "\n", + " # history[-1] = (query,answer_yet)\n", + " # elif event[\"event\"] == \"on_chain_end\":\n", + " # answer_yet = \"\"\n", + " # history[-1] = (query,answer_yet)\n", + " # if display_output:\n", + " # print(event[\"data\"][\"output\"])\n", + "\n", + " # if op['path'] == path_reformulation: # reforulated question\n", + " # try:\n", + " # output_language = op['value'][\"language\"] # str\n", + " # output_query = op[\"value\"][\"question\"]\n", + " # except Exception as e:\n", + " # raise gr.Error(f\"ClimateQ&A Error: {e} - The error has been noted, try another question and if the error remains, you can contact us :)\")\n", + " \n", + " # if op[\"path\"] == path_keywords:\n", + " # try:\n", + " # output_keywords = op['value'][\"keywords\"] # str\n", + " # output_keywords = \" AND \".join(output_keywords)\n", + " # except Exception as e:\n", + " # pass\n", + "\n", + "\n", + "\n", + " # history = [tuple(x) for x in history]" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Categorize_message ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "Output intent categorization: {'intent': 'search'}\n", + "\n", + "---- Transform query ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Retrieving graphs ----\n", + "Subquestion 0: What are the environmental impacts of being a vegetarian?\n", + "8 graphs retrieved for subquestion 1: [Document(metadata={'category': 'Meat & Dairy Production', 'doc_id': 'owid_1678', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Impacts are measured per liter of milk. These are based on a meta-analysis of food system impact studies across the supply chain which includes land use change, on-farm production, processing, transport, and packaging.', 'url': 'https://ourworldindata.org/grapher/environmental-footprint-milks', 'similarity_score': 0.6826351881027222, 'content': 'Environmental footprints of dairy and plant-based milks', 'reranking_score': 0.025419369339942932, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Environmental footprints of dairy and plant-based milks'), Document(metadata={'category': 'Animal Welfare', 'doc_id': 'owid_174', 'returned_content': '', 'source': 'OWID', 'subtitle': '– Flexitarian: mainly vegetarian, but occasionally eat meat or fish. – Pescetarian: eat fish but do not eat meat or poultry. – Vegetarian: do not eat any meat, poultry, game, fish, or shellfish. – Plant-based / Vegan: do not eat dairy products, eggs, or any other animal product.', 'url': 'https://ourworldindata.org/grapher/dietary-choices-uk', 'similarity_score': 0.7348645925521851, 'content': 'Vegans, vegetarians and meat-eaters: self-reported dietary choices, United Kingdom', 'reranking_score': 0.00022837991127744317, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Vegans, vegetarians and meat-eaters: self-reported dietary choices, United Kingdom'), Document(metadata={'category': 'Meat & Dairy Production', 'doc_id': 'owid_1688', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Expressed in tonnes of meat. Data from 1961-2013 is based on published FAO estimates; from 2013-2050 based on FAO projections. Projections are based on future population projections and the expected impacts of regional and national economic growth trends on meat consumption.', 'url': 'https://ourworldindata.org/grapher/global-meat-projections-to-2050', 'similarity_score': 0.7610733509063721, 'content': 'Global meat consumption', 'reranking_score': 5.71148339076899e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Global meat consumption'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_382', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions from the food system are broken down by their stage in the life-cycle, from land use and on-farm production through to consumer waste. Emissions are measured in tonnes of carbon dioxide-equivalents.', 'url': 'https://ourworldindata.org/grapher/food-emissions-life-cycle', 'similarity_score': 0.7992925047874451, 'content': 'Global emissions from food by life-cycle stage', 'reranking_score': 4.49202379968483e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Global emissions from food by life-cycle stage'), Document(metadata={'category': 'Plastic Pollution', 'doc_id': 'owid_1889', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Number of times a given grocery bag type would have to be reused to have an environmental impact as low as a standard single-use plastic bag.', 'url': 'https://ourworldindata.org/grapher/grocery-bag-environmental-impact', 'similarity_score': 0.824555516242981, 'content': 'Environmental impacts of different types of grocery bags', 'reranking_score': 2.8800952350138687e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Environmental impacts of different types of grocery bags'), Document(metadata={'category': 'Environmental Impacts of Food Production', 'doc_id': 'owid_1175', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions are measured in tonnes of carbon dioxide-equivalents.', 'url': 'https://ourworldindata.org/grapher/emissions-from-food', 'similarity_score': 0.8313338756561279, 'content': 'Greenhouse gas emissions from food systems', 'reranking_score': 1.8187101886724122e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Greenhouse gas emissions from food systems'), Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_483', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Food system emissions include agriculture, land-use change, and supply chain emissions (transport, packaging, food processing, retail, cooking, and waste). Emissions are quantified based on food production, not consumption. This means they do not account for international trade.', 'url': 'https://ourworldindata.org/grapher/share-global-food-emissions', 'similarity_score': 0.8323527574539185, 'content': 'Share of global greenhouse gas emissions from food', 'reranking_score': 1.6353857063222677e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Share of global greenhouse gas emissions from food'), Document(metadata={'category': 'Meat & Dairy Production', 'doc_id': 'owid_1673', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The percentage of global habitable land area needed for agriculture if the total world population was to adopt the average diet of any given country versus annual per capita beef consumption. Globally we use approximately 50% of habitable land for agriculture, as shown by the grey horizontal line.', 'url': 'https://ourworldindata.org/grapher/dietary-land-use-vs-beef-consumption', 'similarity_score': 0.8455410003662109, 'content': 'Dietary land use vs. beef consumption', 'reranking_score': 1.4984153494879138e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Dietary land use vs. beef consumption')]\n", + "Subquestion 1: What are the health benefits of being a vegetarian?\n", + "7 graphs retrieved for subquestion 2: [Document(metadata={'category': 'Animal Welfare', 'doc_id': 'owid_174', 'returned_content': '', 'source': 'OWID', 'subtitle': '– Flexitarian: mainly vegetarian, but occasionally eat meat or fish. – Pescetarian: eat fish but do not eat meat or poultry. – Vegetarian: do not eat any meat, poultry, game, fish, or shellfish. – Plant-based / Vegan: do not eat dairy products, eggs, or any other animal product.', 'url': 'https://ourworldindata.org/grapher/dietary-choices-uk', 'similarity_score': 0.7397687435150146, 'content': 'Vegans, vegetarians and meat-eaters: self-reported dietary choices, United Kingdom', 'reranking_score': 0.0008887002477422357, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Vegans, vegetarians and meat-eaters: self-reported dietary choices, United Kingdom'), Document(metadata={'category': 'Meat & Dairy Production', 'doc_id': 'owid_1688', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Expressed in tonnes of meat. Data from 1961-2013 is based on published FAO estimates; from 2013-2050 based on FAO projections. Projections are based on future population projections and the expected impacts of regional and national economic growth trends on meat consumption.', 'url': 'https://ourworldindata.org/grapher/global-meat-projections-to-2050', 'similarity_score': 0.8430077433586121, 'content': 'Global meat consumption', 'reranking_score': 3.41298509738408e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Global meat consumption'), Document(metadata={'category': 'Animal Welfare', 'doc_id': 'owid_168', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The survey measured attitudes towards animal farming with around 1,500 adults in the United States, census-balanced to be representative of age, gender, region, ethnicity, and income.', 'url': 'https://ourworldindata.org/grapher/survey-dietary-choices-sentience', 'similarity_score': 0.8580029010772705, 'content': 'Public attitudes to dietary choices and meat-eating in the United States', 'reranking_score': 1.3065436178294476e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Public attitudes to dietary choices and meat-eating in the United States'), Document(metadata={'category': 'Diet Compositions', 'doc_id': 'owid_849', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Recommended intakes of animal products in the EAT-Lancet diet are shown relative to average daily per capita supply by country. The EAT-Lancet diet is a diet recommended to balance the goals of healthy nutrition and environmental sustainability for a global population.', 'url': 'https://ourworldindata.org/grapher/eat-lancet-diet-animal-products', 'similarity_score': 0.8636244535446167, 'content': 'Consumption of animal products in the EAT-Lancet diet', 'reranking_score': 1.1884163541253656e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Consumption of animal products in the EAT-Lancet diet'), Document(metadata={'category': 'Food Supply', 'doc_id': 'owid_1310', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Daily meat consumption is shown relative to the expected EU average of 165g per person in 2030. This projection comes from the livestock antibiotic scenarios from Van Boeckel et al. (2017).', 'url': 'https://ourworldindata.org/grapher/daily-meat-consumption-per-person', 'similarity_score': 0.876916766166687, 'content': 'Daily meat consumption per person', 'reranking_score': 1.1853918294946197e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Daily meat consumption per person'), Document(metadata={'category': 'Meat & Dairy Production', 'doc_id': 'owid_1673', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The percentage of global habitable land area needed for agriculture if the total world population was to adopt the average diet of any given country versus annual per capita beef consumption. Globally we use approximately 50% of habitable land for agriculture, as shown by the grey horizontal line.', 'url': 'https://ourworldindata.org/grapher/dietary-land-use-vs-beef-consumption', 'similarity_score': 0.9062429666519165, 'content': 'Dietary land use vs. beef consumption', 'reranking_score': 1.1840336810564622e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Dietary land use vs. beef consumption'), Document(metadata={'category': 'Food Supply', 'doc_id': 'owid_1316', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Daily per capita protein supply is measured in grams per person per day. Protein of animal origin includes protein from all meat commodities, eggs and dairy products, and fish & seafood.', 'url': 'https://ourworldindata.org/grapher/daily-protein-supply-from-animal-and-plant-based-foods', 'similarity_score': 0.9169386029243469, 'content': 'Daily protein supply from animal and plant-based foods', 'reranking_score': 1.122933372244006e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Daily protein supply from animal and plant-based foods')]\n", + "---- Retrieve documents ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_end callback: TracerException('No indexed run ID b439ad93-10d3-4bae-9602-d52a39984115.')\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Retrieve documents ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_end callback: TracerException('No indexed run ID ba88b5a4-c204-4eeb-ac33-ff2f0645403f.')\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_start callback: ValidationError(model='Run', errors=[{'loc': ('__root__',), 'msg': \"argument of type 'NoneType' is not iterable\", 'type': 'type_error'}])\n", + "WARNING:langchain_core.callbacks.manager:Error in LangChainTracer.on_chain_end callback: TracerException('No indexed run ID ea4e9940-b59a-4468-9781-b8c56be151a7.')\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Answer RAG ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "Answer:\n", + "I could not find any specific passages in the IPCC/IPBES reports that directly address whether individuals should be vegetarian. This could be due to the search engine limitations, and not because the information is not there. \n", + "\n", + "However, from a climate science perspective, reducing meat consumption, especially red meat, can have positive environmental impacts. Livestock farming is a significant contributor to greenhouse gas emissions, deforestation, and water pollution. By choosing a plant-based diet or reducing meat consumption, individuals can help reduce their carbon footprint and lessen the pressure on natural resources.\n", + "\n", + "If you have specific questions related to the environmental impacts of meat consumption or sustainable diets, please reformulate your question to be more specific to the IPCC/IPBES reports. Remember that individual dietary choices can play a role in addressing climate change, but it is important to consider a variety of factors when making decisions about your diet.\n" + ] + }, + { + "data": { + "text/plain": [ + "{'user_input': 'should I be a vegetarian ?',\n", + " 'language': 'English',\n", + " 'intent': 'search',\n", + " 'query': 'should I be a vegetarian ?',\n", + " 'remaining_questions': [],\n", + " 'n_questions': 2,\n", + " 'answer': 'I could not find any specific passages in the IPCC/IPBES reports that directly address whether individuals should be vegetarian. This could be due to the search engine limitations, and not because the information is not there. \\n\\nHowever, from a climate science perspective, reducing meat consumption, especially red meat, can have positive environmental impacts. Livestock farming is a significant contributor to greenhouse gas emissions, deforestation, and water pollution. By choosing a plant-based diet or reducing meat consumption, individuals can help reduce their carbon footprint and lessen the pressure on natural resources.\\n\\nIf you have specific questions related to the environmental impacts of meat consumption or sustainable diets, please reformulate your question to be more specific to the IPCC/IPBES reports. Remember that individual dietary choices can play a role in addressing climate change, but it is important to consider a variety of factors when making decisions about your diet.',\n", + " 'documents': [Document(metadata={'chunk_type': 'text', 'document_id': 'document24', 'document_number': 24.0, 'element_id': 'N/A', 'figure_code': 'N/A', 'file_size': 'N/A', 'image_path': 'N/A', 'n_pages': 60.0, 'name': 'Summary for Policymakers. Global assessment report on biodiversity and ecosystem services of the IPBES (Version 1)', 'num_characters': 367.0, 'num_tokens': 99.0, 'num_tokens_approx': 110.0, 'num_words': 83.0, 'page_number': 24, 'release_date': 2019.0, 'report_type': 'SPM', 'section_header': 'BACKGROUND', 'short_name': 'IPBES GAR SPM', 'source': 'IPBES', 'toc_level0': 'N/A', 'toc_level1': 'N/A', 'toc_level2': 'N/A', 'toc_level3': 'N/A', 'url': 'https://zenodo.org/record/3553579/files/ipbes_global_assessment_report_summary_for_policymakers.pdf', 'similarity_score': 0.62691462, 'content': 'healthy diets (established but incomplete) {2.3.4.2}. Shifting diets towards a diversity of foods, including fish, fruit, nuts and vegetables, significantly reduces the risk of certain preventable non-communicable diseases, which are currently responsible for 20 per cent of premature mortality globally (well established) {2.3.4.2, 2.3.5.2 (NCP 2 and 12)}.', 'reranking_score': 0.06392419338226318, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IPCC', 'IPOS', 'IPBES'], 'question_used': 'What are the health benefits of being a vegetarian?', 'index_used': 'Vector'}, page_content='healthy diets (established but incomplete) {2.3.4.2}. Shifting diets towards a diversity of foods, including fish, fruit, nuts and vegetables, significantly reduces the risk of certain preventable non-communicable diseases, which are currently responsible for 20 per cent of premature mortality globally (well established) {2.3.4.2, 2.3.5.2 (NCP 2 and 12)}.'),\n", + " Document(metadata={'chunk_type': 'text', 'document_id': 'document24', 'document_number': 24.0, 'element_id': 'N/A', 'figure_code': 'N/A', 'file_size': 'N/A', 'image_path': 'N/A', 'n_pages': 60.0, 'name': 'Summary for Policymakers. Global assessment report on biodiversity and ecosystem services of the IPBES (Version 1)', 'num_characters': 213.0, 'num_tokens': 57.0, 'num_tokens_approx': 62.0, 'num_words': 47.0, 'page_number': 44, 'release_date': 2019.0, 'report_type': 'SPM', 'section_header': 'interventions, or levers, and eight leverage points that \\r\\nare key for achieving transformative change (Figure ', 'short_name': 'IPBES GAR SPM', 'source': 'IPBES', 'toc_level0': 'N/A', 'toc_level1': 'N/A', 'toc_level2': 'N/A', 'toc_level3': 'N/A', 'url': 'https://zenodo.org/record/3553579/files/ipbes_global_assessment_report_summary_for_policymakers.pdf', 'similarity_score': 0.615191042, 'content': 'reduce food waste, overconsumption, and the demand for animal products that are produced unsustainably, which could have synergistic benefits for human health (established but incomplete) {5.3.2.1, 6.3.2.1}.', 'reranking_score': 0.020161613821983337, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IPCC', 'IPOS', 'IPBES'], 'question_used': 'What are the health benefits of being a vegetarian?', 'index_used': 'Vector'}, page_content='reduce food waste, overconsumption, and the demand for animal products that are produced unsustainably, which could have synergistic benefits for human health (established but incomplete) {5.3.2.1, 6.3.2.1}.'),\n", + " Document(metadata={'chunk_type': 'text', 'document_id': 'document24', 'document_number': 24.0, 'element_id': 'N/A', 'figure_code': 'N/A', 'file_size': 'N/A', 'image_path': 'N/A', 'n_pages': 60.0, 'name': 'Summary for Policymakers. Global assessment report on biodiversity and ecosystem services of the IPBES (Version 1)', 'num_characters': 684.0, 'num_tokens': 202.0, 'num_tokens_approx': 237.0, 'num_words': 178.0, 'page_number': 24, 'release_date': 2019.0, 'report_type': 'SPM', 'section_header': 'BACKGROUND', 'short_name': 'IPBES GAR SPM', 'source': 'IPBES', 'toc_level0': 'N/A', 'toc_level1': 'N/A', 'toc_level2': 'N/A', 'toc_level3': 'N/A', 'url': 'https://zenodo.org/record/3553579/files/ipbes_global_assessment_report_summary_for_policymakers.pdf', 'similarity_score': 0.600360632, 'content': \"2 Many of nature's contributions to people are essential for human health (well established) and their decline thus threatens a good quality of life (established but incomplete) {2.3.4}. Nature provides a broad diversity of nutritious foods, medicines and clean water (well established) {2.3.5.2, 3.3.2.1, 3.3.2.2 (Sustainable Development Goal 3)}; can help to regulate disease and the immune system {2.3.4.2}; can reduce levels of certain air pollutants (established but incomplete) {2.3.4.2, 3.3.2.2}; and can improve mental and physical health through exposure to natural areas (inconclusive), among other contributions {2.3.2.2, 2.3.4.2, 3.3.2.2 (Sustainable\", 'reranking_score': 0.01197810098528862, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IPCC', 'IPOS', 'IPBES'], 'question_used': 'What are the health benefits of being a vegetarian?', 'index_used': 'Vector'}, page_content=\"2 Many of nature's contributions to people are essential for human health (well established) and their decline thus threatens a good quality of life (established but incomplete) {2.3.4}. Nature provides a broad diversity of nutritious foods, medicines and clean water (well established) {2.3.5.2, 3.3.2.1, 3.3.2.2 (Sustainable Development Goal 3)}; can help to regulate disease and the immune system {2.3.4.2}; can reduce levels of certain air pollutants (established but incomplete) {2.3.4.2, 3.3.2.2}; and can improve mental and physical health through exposure to natural areas (inconclusive), among other contributions {2.3.2.2, 2.3.4.2, 3.3.2.2 (Sustainable\"),\n", + " Document(metadata={'chunk_type': 'text', 'document_id': 'document30', 'document_number': 30.0, 'element_id': 'N/A', 'figure_code': 'N/A', 'file_size': 'N/A', 'image_path': 'N/A', 'n_pages': 44.0, 'name': 'Summary for Policymakers. Regional Assessment Report on Biodiversity and Ecosystem Services for the Americas', 'num_characters': 1017.0, 'num_tokens': 219.0, 'num_tokens_approx': 242.0, 'num_words': 182.0, 'page_number': 26, 'release_date': 2018.0, 'report_type': 'SPM', 'section_header': '* The Delphi method is a structured and iterative evaluation process that uses expert panels to establish consensus regarding the assessment of a specifi c topic.', 'short_name': 'IPBES RAR AM SPM', 'source': 'IPBES', 'toc_level0': 'N/A', 'toc_level1': 'N/A', 'toc_level2': 'N/A', 'toc_level3': 'N/A', 'url': 'https://zenodo.org/record/3236292/files/ipbes_assessment_spm_americas_EN.pdf', 'similarity_score': 0.593067527, 'content': 'Human health depends directly and indirectly on nature. Biodiversity is a source of medicines and other products that contribute to human health and have high potential for the development of pharmacological products (well established) {2.2.4, 2.4}. In some areas outside of North America, the commercial development of medicinal products has been weak. In the Americas, many opportunities remain for further development of products from nature that can contribute to human health, including through bioprospecting, in accordance with national legislation {2.2.4, 2.4}.\\nHealth benefits from biodiversity and access to nature are well documented (established but incomplete). Examples include diets based on diverse natural products improve health and nearness to green space has been linked to reduced childhood obesity in some urban areas {1.3.2, 2.3.4}. On the other hand, ecosystem contaminants and pollutants transferred to humans via food supplies have been linked to widespread', 'reranking_score': 0.011911126784980297, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IPCC', 'IPOS', 'IPBES'], 'question_used': 'What are the health benefits of being a vegetarian?', 'index_used': 'Vector'}, page_content='Human health depends directly and indirectly on nature. Biodiversity is a source of medicines and other products that contribute to human health and have high potential for the development of pharmacological products (well established) {2.2.4, 2.4}. In some areas outside of North America, the commercial development of medicinal products has been weak. In the Americas, many opportunities remain for further development of products from nature that can contribute to human health, including through bioprospecting, in accordance with national legislation {2.2.4, 2.4}.\\nHealth benefits from biodiversity and access to nature are well documented (established but incomplete). Examples include diets based on diverse natural products improve health and nearness to green space has been linked to reduced childhood obesity in some urban areas {1.3.2, 2.3.4}. On the other hand, ecosystem contaminants and pollutants transferred to humans via food supplies have been linked to widespread'),\n", + " Document(metadata={'chunk_type': 'text', 'document_id': 'document9', 'document_number': 9.0, 'element_id': 'N/A', 'figure_code': 'N/A', 'file_size': 'N/A', 'image_path': 'N/A', 'n_pages': 2258.0, 'name': 'Full Report. In: Climate Change 2022: Mitigation of Climate Change. Contribution of the WGIII to the AR6 of the IPCC', 'num_characters': 880.0, 'num_tokens': 215.0, 'num_tokens_approx': 212.0, 'num_words': 159.0, 'page_number': 816, 'release_date': 2022.0, 'report_type': 'Full Report', 'section_header': 'Agriculture, Forestry and Other Land Uses (AFOLU) ', 'short_name': 'IPCC AR6 WGIII FR', 'source': 'IPCC', 'toc_level0': '7.4 Assessment of AFOLU Mitigation Measures Including Trade-offs and Synergies', 'toc_level1': '7.4.5 Demand-side Measures', 'toc_level2': 'N/A', 'toc_level3': 'N/A', 'url': 'https://www.ipcc.ch/report/ar6/wg3/downloads/report/IPCC_AR6_WGIII_FullReport.pdf', 'similarity_score': 0.694379687, 'content': 'a transition towards more plant-based consumption and reduced consumption of animal-based foods, particularly from ruminant animals, could reduce pressure on forests and land used for feed, support the preservation of biodiversity and planetary health (FAO 2018c; Theurl et al. 2020), and contribute to preventing forms of malnutrition (i.e., undernutrition, micronutrient deficiency, and obesity) in developing countries (Section 12.4). Other co-benefits include lowering the risk of cardiovascular disease, type 2 diabetes, and reducing mortality from diet-related non-communicable diseases (Toumpanakis et al. 2018; Satija and Hu 2018; Faber et al. 2020; Magkos et al. 2020). However, transition towards sustainable healthy diets could have adverse impacts on the economic stability of the agricultural sector (MacDiarmid 2013; Aschemann-Witzel 2015;', 'reranking_score': 0.010761579498648643, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IPCC', 'IPOS', 'IPBES'], 'question_used': 'What are the health benefits of being a vegetarian?', 'index_used': 'Vector'}, page_content='a transition towards more plant-based consumption and reduced consumption of animal-based foods, particularly from ruminant animals, could reduce pressure on forests and land used for feed, support the preservation of biodiversity and planetary health (FAO 2018c; Theurl et al. 2020), and contribute to preventing forms of malnutrition (i.e., undernutrition, micronutrient deficiency, and obesity) in developing countries (Section 12.4). Other co-benefits include lowering the risk of cardiovascular disease, type 2 diabetes, and reducing mortality from diet-related non-communicable diseases (Toumpanakis et al. 2018; Satija and Hu 2018; Faber et al. 2020; Magkos et al. 2020). However, transition towards sustainable healthy diets could have adverse impacts on the economic stability of the agricultural sector (MacDiarmid 2013; Aschemann-Witzel 2015;'),\n", + " Document(metadata={'chunk_type': 'text', 'document_id': 'document33', 'document_number': 33.0, 'element_id': 'N/A', 'figure_code': 'N/A', 'file_size': 'N/A', 'image_path': 'N/A', 'n_pages': 894.0, 'name': 'Full Report. Regional Assessment Report on Biodiversity and Ecosystem Services for Europe and Central Asia', 'num_characters': 227.0, 'num_tokens': 59.0, 'num_tokens_approx': 61.0, 'num_words': 46.0, 'page_number': 524, 'release_date': 2018.0, 'report_type': 'Full Report', 'section_header': '4.6.1.3 Drivers of nutrient pollution', 'short_name': 'IPBES RAR ECA FR', 'source': 'IPBES', 'toc_level0': \"CHAPTER 4: DIRECT AND INDIRECT DRIVERS OF CHANGE IN BIODIVERSITY AND NATURE'S CONTRIBUTIONS PEOPLE\", 'toc_level1': '4.6 Drivers and effects of pollution ', 'toc_level2': '4.6.1 Nutrient pollution ', 'toc_level3': '4.6.1.3 Drivers of nutrient pollution', 'url': 'https://zenodo.org/record/3237429/files/ipbes_assessment_report_eca_EN.pdf', 'similarity_score': 0.667931199, 'content': 'Vegetarianism is a cultural driver with a high potential: a 50% reduction in the consumption of animal products would lead to at least a 10%-reduction in nitrogen pollution in the EU-27 (Van Grinsven et al., 2015).\\n466466', 'reranking_score': 0.010324961505830288, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IPCC', 'IPOS', 'IPBES'], 'question_used': 'What are the health benefits of being a vegetarian?', 'index_used': 'Vector'}, page_content='Vegetarianism is a cultural driver with a high potential: a 50% reduction in the consumption of animal products would lead to at least a 10%-reduction in nitrogen pollution in the EU-27 (Van Grinsven et al., 2015).\\n466466'),\n", + " Document(metadata={'chunk_type': 'text', 'document_id': 'document6', 'document_number': 6.0, 'element_id': 'N/A', 'figure_code': 'N/A', 'file_size': 'N/A', 'image_path': 'N/A', 'n_pages': 3068.0, 'name': 'Full Report. In: Climate Change 2022: Impacts, Adaptation and Vulnerability. Contribution of the WGII to the AR6 of the IPCC', 'num_characters': 916.0, 'num_tokens': 192.0, 'num_tokens_approx': 236.0, 'num_words': 177.0, 'page_number': 1059, 'release_date': 2022.0, 'report_type': 'Full Report', 'section_header': 'Observed Impacts', 'short_name': 'IPCC AR6 WGII FR', 'source': 'IPCC', 'toc_level0': 'Chapters and Cross-Chapter Papers ', 'toc_level1': 'Chapter 7 Health, Wellbeing and the Changing Structure of Communities', 'toc_level2': 'N/A', 'toc_level3': 'N/A', 'url': 'https://report.ipcc.ch/ar6/wg2/IPCC_AR6_WGII_FullReport.pdf', 'similarity_score': 0.666556418, 'content': 'Transitioning towards equitable, low-carbon societies has multiple benefits for health and well-being (very high confidence). Benefits for health and well-being can be gained from wide-spread, equitable access to affordable renewable energy (high confidence); active transport (e.g., walking and cycling) (high confidence); green buildings and nature-based solutions, such as green and blue urban infrastructure (high confidence); and by transitioning to a low-carbon, well-being-oriented and equity-oriented economy consistent with the aims of the SDGs (high confidence). Plant-rich diets consistent with international recommendations for healthy diets could contribute to lower GHG emissions while also generating health co-benefits, such as reducing ill health related to over-consumption of animal-based products (high confidence) {7.4.2; Cross-Chapter Box HEALTH in Chapter 7; 7.4.4}.', 'reranking_score': 0.010074242949485779, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IPCC', 'IPOS', 'IPBES'], 'question_used': 'What are the health benefits of being a vegetarian?', 'index_used': 'Vector'}, page_content='Transitioning towards equitable, low-carbon societies has multiple benefits for health and well-being (very high confidence). Benefits for health and well-being can be gained from wide-spread, equitable access to affordable renewable energy (high confidence); active transport (e.g., walking and cycling) (high confidence); green buildings and nature-based solutions, such as green and blue urban infrastructure (high confidence); and by transitioning to a low-carbon, well-being-oriented and equity-oriented economy consistent with the aims of the SDGs (high confidence). Plant-rich diets consistent with international recommendations for healthy diets could contribute to lower GHG emissions while also generating health co-benefits, such as reducing ill health related to over-consumption of animal-based products (high confidence) {7.4.2; Cross-Chapter Box HEALTH in Chapter 7; 7.4.4}.')],\n", + " 'recommended_content': [Document(metadata={'category': 'Meat & Dairy Production', 'doc_id': 'owid_1678', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Impacts are measured per liter of milk. These are based on a meta-analysis of food system impact studies across the supply chain which includes land use change, on-farm production, processing, transport, and packaging.', 'url': 'https://ourworldindata.org/grapher/environmental-footprint-milks', 'similarity_score': 0.6826351881027222, 'content': 'Environmental footprints of dairy and plant-based milks', 'reranking_score': 0.025419369339942932, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Environmental footprints of dairy and plant-based milks'),\n", + " Document(metadata={'category': 'Animal Welfare', 'doc_id': 'owid_174', 'returned_content': '', 'source': 'OWID', 'subtitle': '– Flexitarian: mainly vegetarian, but occasionally eat meat or fish. – Pescetarian: eat fish but do not eat meat or poultry. – Vegetarian: do not eat any meat, poultry, game, fish, or shellfish. – Plant-based / Vegan: do not eat dairy products, eggs, or any other animal product.', 'url': 'https://ourworldindata.org/grapher/dietary-choices-uk', 'similarity_score': 0.7397687435150146, 'content': 'Vegans, vegetarians and meat-eaters: self-reported dietary choices, United Kingdom', 'reranking_score': 0.0008887002477422357, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Vegans, vegetarians and meat-eaters: self-reported dietary choices, United Kingdom'),\n", + " Document(metadata={'category': 'Meat & Dairy Production', 'doc_id': 'owid_1688', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Expressed in tonnes of meat. Data from 1961-2013 is based on published FAO estimates; from 2013-2050 based on FAO projections. Projections are based on future population projections and the expected impacts of regional and national economic growth trends on meat consumption.', 'url': 'https://ourworldindata.org/grapher/global-meat-projections-to-2050', 'similarity_score': 0.7610733509063721, 'content': 'Global meat consumption', 'reranking_score': 5.71148339076899e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Global meat consumption'),\n", + " Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_382', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions from the food system are broken down by their stage in the life-cycle, from land use and on-farm production through to consumer waste. Emissions are measured in tonnes of carbon dioxide-equivalents.', 'url': 'https://ourworldindata.org/grapher/food-emissions-life-cycle', 'similarity_score': 0.7992925047874451, 'content': 'Global emissions from food by life-cycle stage', 'reranking_score': 4.49202379968483e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Global emissions from food by life-cycle stage'),\n", + " Document(metadata={'category': 'Plastic Pollution', 'doc_id': 'owid_1889', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Number of times a given grocery bag type would have to be reused to have an environmental impact as low as a standard single-use plastic bag.', 'url': 'https://ourworldindata.org/grapher/grocery-bag-environmental-impact', 'similarity_score': 0.824555516242981, 'content': 'Environmental impacts of different types of grocery bags', 'reranking_score': 2.8800952350138687e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Environmental impacts of different types of grocery bags'),\n", + " Document(metadata={'category': 'Environmental Impacts of Food Production', 'doc_id': 'owid_1175', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions are measured in tonnes of carbon dioxide-equivalents.', 'url': 'https://ourworldindata.org/grapher/emissions-from-food', 'similarity_score': 0.8313338756561279, 'content': 'Greenhouse gas emissions from food systems', 'reranking_score': 1.8187101886724122e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Greenhouse gas emissions from food systems'),\n", + " Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_483', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Food system emissions include agriculture, land-use change, and supply chain emissions (transport, packaging, food processing, retail, cooking, and waste). Emissions are quantified based on food production, not consumption. This means they do not account for international trade.', 'url': 'https://ourworldindata.org/grapher/share-global-food-emissions', 'similarity_score': 0.8323527574539185, 'content': 'Share of global greenhouse gas emissions from food', 'reranking_score': 1.6353857063222677e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Share of global greenhouse gas emissions from food'),\n", + " Document(metadata={'category': 'Meat & Dairy Production', 'doc_id': 'owid_1673', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The percentage of global habitable land area needed for agriculture if the total world population was to adopt the average diet of any given country versus annual per capita beef consumption. Globally we use approximately 50% of habitable land for agriculture, as shown by the grey horizontal line.', 'url': 'https://ourworldindata.org/grapher/dietary-land-use-vs-beef-consumption', 'similarity_score': 0.8455410003662109, 'content': 'Dietary land use vs. beef consumption', 'reranking_score': 1.4984153494879138e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Dietary land use vs. beef consumption'),\n", + " Document(metadata={'category': 'Animal Welfare', 'doc_id': 'owid_168', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The survey measured attitudes towards animal farming with around 1,500 adults in the United States, census-balanced to be representative of age, gender, region, ethnicity, and income.', 'url': 'https://ourworldindata.org/grapher/survey-dietary-choices-sentience', 'similarity_score': 0.8580029010772705, 'content': 'Public attitudes to dietary choices and meat-eating in the United States', 'reranking_score': 1.3065436178294476e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Public attitudes to dietary choices and meat-eating in the United States'),\n", + " Document(metadata={'category': 'Diet Compositions', 'doc_id': 'owid_849', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Recommended intakes of animal products in the EAT-Lancet diet are shown relative to average daily per capita supply by country. The EAT-Lancet diet is a diet recommended to balance the goals of healthy nutrition and environmental sustainability for a global population.', 'url': 'https://ourworldindata.org/grapher/eat-lancet-diet-animal-products', 'similarity_score': 0.8636244535446167, 'content': 'Consumption of animal products in the EAT-Lancet diet', 'reranking_score': 1.1884163541253656e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Consumption of animal products in the EAT-Lancet diet'),\n", + " Document(metadata={'category': 'Food Supply', 'doc_id': 'owid_1310', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Daily meat consumption is shown relative to the expected EU average of 165g per person in 2030. This projection comes from the livestock antibiotic scenarios from Van Boeckel et al. (2017).', 'url': 'https://ourworldindata.org/grapher/daily-meat-consumption-per-person', 'similarity_score': 0.876916766166687, 'content': 'Daily meat consumption per person', 'reranking_score': 1.1853918294946197e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Daily meat consumption per person'),\n", + " Document(metadata={'category': 'Food Supply', 'doc_id': 'owid_1316', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Daily per capita protein supply is measured in grams per person per day. Protein of animal origin includes protein from all meat commodities, eggs and dairy products, and fish & seafood.', 'url': 'https://ourworldindata.org/grapher/daily-protein-supply-from-animal-and-plant-based-foods', 'similarity_score': 0.9169386029243469, 'content': 'Daily protein supply from animal and plant-based foods', 'reranking_score': 1.122933372244006e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Daily protein supply from animal and plant-based foods')]}" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "output = await app.ainvoke({\"user_input\": \"should I be a vegetarian ?\"})\n", + "output" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Document(metadata={'category': 'Meat & Dairy Production', 'doc_id': 'owid_1678', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Impacts are measured per liter of milk. These are based on a meta-analysis of food system impact studies across the supply chain which includes land use change, on-farm production, processing, transport, and packaging.', 'url': 'https://ourworldindata.org/grapher/environmental-footprint-milks', 'similarity_score': 0.6826351881027222, 'content': 'Environmental footprints of dairy and plant-based milks', 'reranking_score': 0.025419369339942932, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Environmental footprints of dairy and plant-based milks'),\n", + " Document(metadata={'category': 'Animal Welfare', 'doc_id': 'owid_174', 'returned_content': '', 'source': 'OWID', 'subtitle': '– Flexitarian: mainly vegetarian, but occasionally eat meat or fish. – Pescetarian: eat fish but do not eat meat or poultry. – Vegetarian: do not eat any meat, poultry, game, fish, or shellfish. – Plant-based / Vegan: do not eat dairy products, eggs, or any other animal product.', 'url': 'https://ourworldindata.org/grapher/dietary-choices-uk', 'similarity_score': 0.7397687435150146, 'content': 'Vegans, vegetarians and meat-eaters: self-reported dietary choices, United Kingdom', 'reranking_score': 0.0008887002477422357, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Vegans, vegetarians and meat-eaters: self-reported dietary choices, United Kingdom'),\n", + " Document(metadata={'category': 'Meat & Dairy Production', 'doc_id': 'owid_1688', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Expressed in tonnes of meat. Data from 1961-2013 is based on published FAO estimates; from 2013-2050 based on FAO projections. Projections are based on future population projections and the expected impacts of regional and national economic growth trends on meat consumption.', 'url': 'https://ourworldindata.org/grapher/global-meat-projections-to-2050', 'similarity_score': 0.7610733509063721, 'content': 'Global meat consumption', 'reranking_score': 5.71148339076899e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Global meat consumption'),\n", + " Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_382', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions from the food system are broken down by their stage in the life-cycle, from land use and on-farm production through to consumer waste. Emissions are measured in tonnes of carbon dioxide-equivalents.', 'url': 'https://ourworldindata.org/grapher/food-emissions-life-cycle', 'similarity_score': 0.7992925047874451, 'content': 'Global emissions from food by life-cycle stage', 'reranking_score': 4.49202379968483e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Global emissions from food by life-cycle stage'),\n", + " Document(metadata={'category': 'Plastic Pollution', 'doc_id': 'owid_1889', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Number of times a given grocery bag type would have to be reused to have an environmental impact as low as a standard single-use plastic bag.', 'url': 'https://ourworldindata.org/grapher/grocery-bag-environmental-impact', 'similarity_score': 0.824555516242981, 'content': 'Environmental impacts of different types of grocery bags', 'reranking_score': 2.8800952350138687e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Environmental impacts of different types of grocery bags'),\n", + " Document(metadata={'category': 'Environmental Impacts of Food Production', 'doc_id': 'owid_1175', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions are measured in tonnes of carbon dioxide-equivalents.', 'url': 'https://ourworldindata.org/grapher/emissions-from-food', 'similarity_score': 0.8313338756561279, 'content': 'Greenhouse gas emissions from food systems', 'reranking_score': 1.8187101886724122e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Greenhouse gas emissions from food systems'),\n", + " Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_483', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Food system emissions include agriculture, land-use change, and supply chain emissions (transport, packaging, food processing, retail, cooking, and waste). Emissions are quantified based on food production, not consumption. This means they do not account for international trade.', 'url': 'https://ourworldindata.org/grapher/share-global-food-emissions', 'similarity_score': 0.8323527574539185, 'content': 'Share of global greenhouse gas emissions from food', 'reranking_score': 1.6353857063222677e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Share of global greenhouse gas emissions from food'),\n", + " Document(metadata={'category': 'Meat & Dairy Production', 'doc_id': 'owid_1673', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The percentage of global habitable land area needed for agriculture if the total world population was to adopt the average diet of any given country versus annual per capita beef consumption. Globally we use approximately 50% of habitable land for agriculture, as shown by the grey horizontal line.', 'url': 'https://ourworldindata.org/grapher/dietary-land-use-vs-beef-consumption', 'similarity_score': 0.8455410003662109, 'content': 'Dietary land use vs. beef consumption', 'reranking_score': 1.4984153494879138e-05, 'query_used_for_retrieval': 'What are the environmental impacts of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Dietary land use vs. beef consumption'),\n", + " Document(metadata={'category': 'Animal Welfare', 'doc_id': 'owid_168', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The survey measured attitudes towards animal farming with around 1,500 adults in the United States, census-balanced to be representative of age, gender, region, ethnicity, and income.', 'url': 'https://ourworldindata.org/grapher/survey-dietary-choices-sentience', 'similarity_score': 0.8580029010772705, 'content': 'Public attitudes to dietary choices and meat-eating in the United States', 'reranking_score': 1.3065436178294476e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Public attitudes to dietary choices and meat-eating in the United States'),\n", + " Document(metadata={'category': 'Diet Compositions', 'doc_id': 'owid_849', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Recommended intakes of animal products in the EAT-Lancet diet are shown relative to average daily per capita supply by country. The EAT-Lancet diet is a diet recommended to balance the goals of healthy nutrition and environmental sustainability for a global population.', 'url': 'https://ourworldindata.org/grapher/eat-lancet-diet-animal-products', 'similarity_score': 0.8636244535446167, 'content': 'Consumption of animal products in the EAT-Lancet diet', 'reranking_score': 1.1884163541253656e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Consumption of animal products in the EAT-Lancet diet'),\n", + " Document(metadata={'category': 'Food Supply', 'doc_id': 'owid_1310', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Daily meat consumption is shown relative to the expected EU average of 165g per person in 2030. This projection comes from the livestock antibiotic scenarios from Van Boeckel et al. (2017).', 'url': 'https://ourworldindata.org/grapher/daily-meat-consumption-per-person', 'similarity_score': 0.876916766166687, 'content': 'Daily meat consumption per person', 'reranking_score': 1.1853918294946197e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Daily meat consumption per person'),\n", + " Document(metadata={'category': 'Food Supply', 'doc_id': 'owid_1316', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Daily per capita protein supply is measured in grams per person per day. Protein of animal origin includes protein from all meat commodities, eggs and dairy products, and fish & seafood.', 'url': 'https://ourworldindata.org/grapher/daily-protein-supply-from-animal-and-plant-based-foods', 'similarity_score': 0.9169386029243469, 'content': 'Daily protein supply from animal and plant-based foods', 'reranking_score': 1.122933372244006e-05, 'query_used_for_retrieval': 'What are the health benefits of being a vegetarian?', 'sources_used': ['IEA', 'OWID']}, page_content='Daily protein supply from animal and plant-based foods')]" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "output[\"recommended_content\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [], + "source": [ + "# display(Markdown(_combine_recommended_content(output[\"recommended_content\"])))" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "data": { + "text/plain": [ + "{'graphs': [{'embedding': '',\n", + " 'category': 'Diet Compositions',\n", + " 'source': 'OWID'},\n", + " {'embedding': '',\n", + " 'category': 'Diet Compositions',\n", + " 'source': 'OWID'},\n", + " {'embedding': '',\n", + " 'category': 'Diet Compositions',\n", + " 'source': 'OWID'}]}" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + }, + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mThe Kernel crashed while executing code in the current cell or a previous cell. \n", + "\u001b[1;31mPlease review the code in the cell(s) to identify a possible cause of the failure. \n", + "\u001b[1;31mClick here for more info. \n", + "\u001b[1;31mView Jupyter log for further details." + ] + } + ], + "source": [ + "from climateqa.engine.chains.answer_rag_graph import make_rag_graph_chain, _format_graphs\n", + "\n", + "chain = make_rag_graph_chain(llm)\n", + "chain.invoke({\"query\": \"salade de fruits\", \"recommended_content\": output[\"recommended_content\"]})" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Title: Nationally determined contributions to climate change\\nEmbedding: \\nSource: OWID\\nCategory: Climate Change\\n\\nTitle: Contribution to global mean surface temperature rise from fossil sources\\nEmbedding: \\nSource: OWID\\nCategory: CO2 & Greenhouse Gas Emissions\\n\\nTitle: Global warming contributions by gas and source\\nEmbedding: \\nSource: OWID\\nCategory: CO2 & Greenhouse Gas Emissions\\n\\nTitle: Share of people who believe in climate change and think it\\'s a serious threat to humanity\\nEmbedding: \\nSource: OWID\\nCategory: Climate Change\\n\\nTitle: Global warming contributions from fossil fuels and land use\\nEmbedding: \\nSource: OWID\\nCategory: CO2 & Greenhouse Gas Emissions\\n\\nTitle: Opinions of young people on the threats of climate change\\nEmbedding: \\nSource: OWID\\nCategory: Climate Change\\n\\nTitle: Global warming: Contributions to the change in global mean surface temperature\\nEmbedding: \\nSource: OWID\\nCategory: CO2 & Greenhouse Gas Emissions\\n\\nTitle: People underestimate others\\' willingness to take climate action\\nEmbedding: \\nSource: OWID\\nCategory: Climate Change\\n\\nTitle: Share of people who support policies to tackle climate change\\nEmbedding: \\nSource: OWID\\nCategory: Climate Change\\n\\nTitle: Decadal temperature anomalies\\nEmbedding: \\nSource: OWID\\nCategory: Climate Change\\n'" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graphs = []\n", + "for x in output[\"recommended_content\"]:\n", + " embedding = x.metadata[\"returned_content\"]\n", + " \n", + " # Check if the embedding has already been seen\n", + " graphs.append({\n", + " \"title\": x.page_content,\n", + " \"embedding\": embedding,\n", + " \"metadata\": {\n", + " \"source\": x.metadata[\"source\"],\n", + " \"category\": x.metadata[\"category\"]\n", + " }\n", + " })\n", + "format_data(graphs)" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Setting defaults ----\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n", + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "---- Retrieving graphs ----\n", + "Subquestion 0: What are the ingredients of a fruit salad?\n", + "8 graphs retrieved for subquestion 1: [Document(page_content='Fruit consumption by type', metadata={'category': 'Diet Compositions', 'doc_id': 'owid_854', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Average fruit consumption per person, differentiated by fruit types, measured in kilograms per year.', 'url': 'https://ourworldindata.org/grapher/fruit-consumption-by-fruit-type', 'similarity_score': 0.8464472889900208, 'content': 'Fruit consumption by type', 'reranking_score': 3.988455864600837e-05, 'query_used_for_retrieval': 'What are the ingredients of a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Dietary compositions by commodity group', metadata={'category': 'Diet Compositions', 'doc_id': 'owid_852', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Average per capita dietary energy supply by commodity groups, measured in kilocalories per person per day.', 'url': 'https://ourworldindata.org/grapher/dietary-compositions-by-commodity-group', 'similarity_score': 0.8874290585517883, 'content': 'Dietary compositions by commodity group', 'reranking_score': 3.573522553779185e-05, 'query_used_for_retrieval': 'What are the ingredients of a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Dietary composition by country', metadata={'category': 'Diet Compositions', 'doc_id': 'owid_851', 'returned_content': '', 'source': 'OWID', 'subtitle': \"Share of dietary energy supplied by food commodity types in the average individual's diet in a given country, measured in kilocalories per person per day.\", 'url': 'https://ourworldindata.org/grapher/dietary-composition-by-country', 'similarity_score': 0.947216272354126, 'content': 'Dietary composition by country', 'reranking_score': 3.129038304905407e-05, 'query_used_for_retrieval': 'What are the ingredients of a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Fruit consumption per capita', metadata={'category': 'Diet Compositions', 'doc_id': 'owid_855', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Average fruit consumption per person, measured in kilograms per year.', 'url': 'https://ourworldindata.org/grapher/fruit-consumption-per-capita', 'similarity_score': 0.9761286973953247, 'content': 'Fruit consumption per capita', 'reranking_score': 2.5951983843697235e-05, 'query_used_for_retrieval': 'What are the ingredients of a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Average per capita fruit intake vs. minimum recommended guidelines', metadata={'category': 'Diet Compositions', 'doc_id': 'owid_845', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Countries shown in blue have an average per capita intake below 200g per person per day; countries in green are greater than 200g. National and World Health Organization (WHO) typically set a guideline of 200g per day.', 'url': 'https://ourworldindata.org/grapher/average-per-capita-fruit-intake-vs-minimum-recommended-guidelines', 'similarity_score': 0.9765768051147461, 'content': 'Average per capita fruit intake vs. minimum recommended guidelines', 'reranking_score': 2.5002520487760194e-05, 'query_used_for_retrieval': 'What are the ingredients of a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Cashew nut yields', metadata={'category': 'Crop Yields', 'doc_id': 'owid_802', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Yields are measured in tonnes per hectare.', 'url': 'https://ourworldindata.org/grapher/cashew-nut-yields', 'similarity_score': 1.038257122039795, 'content': 'Cashew nut yields', 'reranking_score': 2.4257407858385704e-05, 'query_used_for_retrieval': 'What are the ingredients of a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Daily protein supply from animal and plant-based foods', metadata={'category': 'Food Supply', 'doc_id': 'owid_1316', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Daily per capita protein supply is measured in grams per person per day. Protein of animal origin includes protein from all meat commodities, eggs and dairy products, and fish & seafood.', 'url': 'https://ourworldindata.org/grapher/daily-protein-supply-from-animal-and-plant-based-foods', 'similarity_score': 1.039305329322815, 'content': 'Daily protein supply from animal and plant-based foods', 'reranking_score': 2.3620234060217626e-05, 'query_used_for_retrieval': 'What are the ingredients of a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Daily caloric supply derived from carbohydrates, protein and fat', metadata={'category': 'Diet Compositions', 'doc_id': 'owid_850', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The average per capita supply of calories derived from carbohydrates, protein and fat, all measured in kilocalories per person per day.', 'url': 'https://ourworldindata.org/grapher/daily-caloric-supply-derived-from-carbohydrates-protein-and-fat', 'similarity_score': 1.0418040752410889, 'content': 'Daily caloric supply derived from carbohydrates, protein and fat', 'reranking_score': 2.3583004804095253e-05, 'query_used_for_retrieval': 'What are the ingredients of a fruit salad?', 'sources_used': ['IEA', 'OWID']})]\n", + "Subquestion 1: How to make a fruit salad?\n", + "7 graphs retrieved for subquestion 2: [Document(page_content='Fruit consumption by type', metadata={'category': 'Diet Compositions', 'doc_id': 'owid_854', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Average fruit consumption per person, differentiated by fruit types, measured in kilograms per year.', 'url': 'https://ourworldindata.org/grapher/fruit-consumption-by-fruit-type', 'similarity_score': 0.8765200972557068, 'content': 'Fruit consumption by type', 'reranking_score': 3.0426110242842697e-05, 'query_used_for_retrieval': 'How to make a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Average per capita fruit intake vs. minimum recommended guidelines', metadata={'category': 'Diet Compositions', 'doc_id': 'owid_845', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Countries shown in blue have an average per capita intake below 200g per person per day; countries in green are greater than 200g. National and World Health Organization (WHO) typically set a guideline of 200g per day.', 'url': 'https://ourworldindata.org/grapher/average-per-capita-fruit-intake-vs-minimum-recommended-guidelines', 'similarity_score': 0.9526513814926147, 'content': 'Average per capita fruit intake vs. minimum recommended guidelines', 'reranking_score': 2.9851042199879885e-05, 'query_used_for_retrieval': 'How to make a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Cashew nut production', metadata={'category': 'Agricultural Production', 'doc_id': 'owid_21', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Cashew nut production is measured in tonnes.', 'url': 'https://ourworldindata.org/grapher/cashew-nut-production', 'similarity_score': 0.9603457450866699, 'content': 'Cashew nut production', 'reranking_score': 2.8193233447382227e-05, 'query_used_for_retrieval': 'How to make a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Fruit consumption per capita', metadata={'category': 'Diet Compositions', 'doc_id': 'owid_855', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Average fruit consumption per person, measured in kilograms per year.', 'url': 'https://ourworldindata.org/grapher/fruit-consumption-per-capita', 'similarity_score': 0.9623799920082092, 'content': 'Fruit consumption per capita', 'reranking_score': 2.4916422262322158e-05, 'query_used_for_retrieval': 'How to make a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Avocado production', metadata={'category': 'Agricultural Production', 'doc_id': 'owid_15', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Avocado production is measured in tonnes.', 'url': 'https://ourworldindata.org/grapher/avocado-production', 'similarity_score': 0.96598219871521, 'content': 'Avocado production', 'reranking_score': 2.4747036150074564e-05, 'query_used_for_retrieval': 'How to make a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Banana production', metadata={'category': 'Agricultural Production', 'doc_id': 'owid_16', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Data source: Food and Agriculture Organization of the United Nations (2023)', 'url': 'https://ourworldindata.org/grapher/banana-production', 'similarity_score': 0.9927387237548828, 'content': 'Banana production', 'reranking_score': 2.4040627977228723e-05, 'query_used_for_retrieval': 'How to make a fruit salad?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Orange production', metadata={'category': 'Agricultural Production', 'doc_id': 'owid_57', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Orange production is measured in tonnes.', 'url': 'https://ourworldindata.org/grapher/orange-production', 'similarity_score': 1.0025488138198853, 'content': 'Orange production', 'reranking_score': 2.3612847144249827e-05, 'query_used_for_retrieval': 'How to make a fruit salad?', 'sources_used': ['IEA', 'OWID']})]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "DOCS USED: False\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "Answer:\n", + "Ce n'est pas lié aux questions environnementales, ce n'est pas de mon ressort.\n" + ] + } + ], + "source": [ + "docs_used = True\n", + "\n", + "async for event in app.astream_events({\"user_input\": \"salade de fruits\"}, version = \"v1\"):\n", + " if docs_used is True and \"metadata\" in event and \"langgraph_node\" in event[\"metadata\"]:\n", + " if event[\"metadata\"][\"langgraph_node\"] in [\"answer_rag_no_docs\", \"answer_chitchat\", \"answer_ai_impact\"]:\n", + " docs_used = False\n", + " print(f\"\\nDOCS USED: {docs_used}\\n\")\n", + " # if event[\"name\"] == \"retrieve_documents\" and event[\"event\"] == \"on_chain_end\":\n", + " # print(event)\n", + " # print(event)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/dora/anaconda3/envs/climateqa_huggingface/lib/python3.12/site-packages/langchain_core/_api/beta_decorator.py:87: LangChainBetaWarning: This API is in beta and may change in the future.\n", + " warn_beta(\n" + ] + } + ], + "source": [ + "inputs = {'user_input': 'impact of ai?', 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources': ['IPCC']}\n", + "result = app.astream_events(inputs,version = \"v1\")" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'event': 'on_chain_start', 'run_id': 'da753bb9-2339-4fc0-b1d7-86443019c4df', 'name': 'LangGraph', 'tags': [], 'metadata': {}, 'data': {'input': {'user_input': 'impact of ai?', 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources': ['IPCC']}}}\n", + "{'event': 'on_chain_start', 'name': '__start__', 'run_id': '07d726da-2d7c-48a3-ad2b-5c28e29729a9', 'tags': ['graph:step:0', 'langsmith:hidden'], 'metadata': {'langgraph_step': 0, 'langgraph_node': '__start__'}, 'data': {'input': {'user_input': 'impact of ai?', 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources': ['IPCC']}}}\n", + "{'event': 'on_chain_end', 'name': '__start__', 'run_id': '07d726da-2d7c-48a3-ad2b-5c28e29729a9', 'tags': ['graph:step:0', 'langsmith:hidden'], 'metadata': {'langgraph_step': 0, 'langgraph_node': '__start__'}, 'data': {'input': {'user_input': 'impact of ai?', 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources': ['IPCC']}, 'output': {'user_input': 'impact of ai?', 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources': ['IPCC']}}}\n", + "{'event': 'on_chain_start', 'name': 'set_defaults', 'run_id': '2f946975-07d9-403b-b617-7bca602d4419', 'tags': ['graph:step:1'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'set_defaults'}, 'data': {}}\n", + "---- Setting defaults ----\n", + "{'event': 'on_chain_start', 'name': 'ChannelWrite', 'run_id': '22442e33-6cb8-4796-8224-fb3107783979', 'tags': ['seq:step:2', 'langsmith:hidden'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'set_defaults'}, 'data': {'input': {'user_input': 'impact of ai?', 'language': None, 'intent': None, 'query': None, 'questions': None, 'answer': None, 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources_input': ['auto'], 'documents': None, 'recommended_content': None, 'graph_returned': None}}}\n", + "{'event': 'on_chain_end', 'name': 'ChannelWrite', 'run_id': '22442e33-6cb8-4796-8224-fb3107783979', 'tags': ['seq:step:2', 'langsmith:hidden'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'set_defaults'}, 'data': {'input': {'user_input': 'impact of ai?', 'language': None, 'intent': None, 'query': None, 'questions': None, 'answer': None, 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources_input': ['auto'], 'documents': None, 'recommended_content': None, 'graph_returned': None}, 'output': {'user_input': 'impact of ai?', 'language': None, 'intent': None, 'query': None, 'questions': None, 'answer': None, 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources_input': ['auto'], 'documents': None, 'recommended_content': None, 'graph_returned': None}}}\n", + "{'event': 'on_chain_stream', 'name': 'set_defaults', 'run_id': '2f946975-07d9-403b-b617-7bca602d4419', 'tags': ['graph:step:1'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'set_defaults'}, 'data': {'chunk': {'user_input': 'impact of ai?', 'language': None, 'intent': None, 'query': None, 'questions': None, 'answer': None, 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources_input': ['auto'], 'documents': None, 'recommended_content': None, 'graph_returned': None}}}\n", + "{'event': 'on_chain_end', 'name': 'set_defaults', 'run_id': '2f946975-07d9-403b-b617-7bca602d4419', 'tags': ['graph:step:1'], 'metadata': {'langgraph_step': 1, 'langgraph_node': 'set_defaults'}, 'data': {'input': {'user_input': 'impact of ai?', 'language': None, 'intent': None, 'query': None, 'questions': None, 'answer': None, 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources_input': ['auto'], 'documents': None, 'recommended_content': None, 'graph_returned': None}, 'output': {'user_input': 'impact of ai?', 'language': None, 'intent': None, 'query': None, 'questions': None, 'answer': None, 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources_input': ['auto'], 'documents': None, 'recommended_content': None, 'graph_returned': None}}}\n", + "{'event': 'on_chain_stream', 'run_id': 'da753bb9-2339-4fc0-b1d7-86443019c4df', 'tags': [], 'metadata': {}, 'name': 'LangGraph', 'data': {'chunk': {'set_defaults': {'user_input': 'impact of ai?', 'language': None, 'intent': None, 'query': None, 'questions': None, 'answer': None, 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources_input': ['auto'], 'documents': None, 'recommended_content': None, 'graph_returned': None}}}}\n", + "{'event': 'on_chain_start', 'name': 'categorize_intent', 'run_id': '66f31c85-1a4b-48b4-9e4f-ad884263809c', 'tags': ['graph:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {}}\n", + "{'event': 'on_chain_start', 'name': 'RunnableSequence', 'run_id': 'e5b8bbe4-eeb1-478a-a105-254d4f4a516b', 'tags': ['seq:step:1'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': {'input': 'impact of ai?'}}}\n", + "{'event': 'on_prompt_start', 'name': 'ChatPromptTemplate', 'run_id': '6fda6f8f-64ba-4b08-8c16-d7f77390f671', 'tags': ['seq:step:1'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': {'input': 'impact of ai?'}}}\n", + "{'event': 'on_prompt_end', 'name': 'ChatPromptTemplate', 'run_id': '6fda6f8f-64ba-4b08-8c16-d7f77390f671', 'tags': ['seq:step:1'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': {'input': 'impact of ai?'}, 'output': ChatPromptValue(messages=[SystemMessage(content='You are a helpful assistant, you will analyze, translate and reformulate the user input message using the function provided'), HumanMessage(content='input: impact of ai?')])}}\n", + "{'event': 'on_chat_model_start', 'name': 'ChatOpenAI', 'run_id': '2d9ccf59-3d78-42b1-8458-83a9c3479ef8', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent', 'ls_model_type': 'chat'}, 'data': {'input': {'messages': [[SystemMessage(content='You are a helpful assistant, you will analyze, translate and reformulate the user input message using the function provided'), HumanMessage(content='input: impact of ai?')]]}}}\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': '2d9ccf59-3d78-42b1-8458-83a9c3479ef8', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={'function_call': {'arguments': '', 'name': 'IntentCategorizer'}}, id='run-2d9ccf59-3d78-42b1-8458-83a9c3479ef8')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': '2d9ccf59-3d78-42b1-8458-83a9c3479ef8', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={'function_call': {'arguments': '{\"', 'name': ''}}, id='run-2d9ccf59-3d78-42b1-8458-83a9c3479ef8')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': '2d9ccf59-3d78-42b1-8458-83a9c3479ef8', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={'function_call': {'arguments': 'intent', 'name': ''}}, id='run-2d9ccf59-3d78-42b1-8458-83a9c3479ef8')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': '2d9ccf59-3d78-42b1-8458-83a9c3479ef8', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={'function_call': {'arguments': '\":\"', 'name': ''}}, id='run-2d9ccf59-3d78-42b1-8458-83a9c3479ef8')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': '2d9ccf59-3d78-42b1-8458-83a9c3479ef8', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={'function_call': {'arguments': 'ai', 'name': ''}}, id='run-2d9ccf59-3d78-42b1-8458-83a9c3479ef8')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': '2d9ccf59-3d78-42b1-8458-83a9c3479ef8', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={'function_call': {'arguments': '_imp', 'name': ''}}, id='run-2d9ccf59-3d78-42b1-8458-83a9c3479ef8')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': '2d9ccf59-3d78-42b1-8458-83a9c3479ef8', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={'function_call': {'arguments': 'act', 'name': ''}}, id='run-2d9ccf59-3d78-42b1-8458-83a9c3479ef8')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': '2d9ccf59-3d78-42b1-8458-83a9c3479ef8', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='', additional_kwargs={'function_call': {'arguments': '\"}', 'name': ''}}, id='run-2d9ccf59-3d78-42b1-8458-83a9c3479ef8')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': '2d9ccf59-3d78-42b1-8458-83a9c3479ef8', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='', response_metadata={'finish_reason': 'stop'}, id='run-2d9ccf59-3d78-42b1-8458-83a9c3479ef8')}}\n", + "{'event': 'on_chat_model_end', 'name': 'ChatOpenAI', 'run_id': '2d9ccf59-3d78-42b1-8458-83a9c3479ef8', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent', 'ls_model_type': 'chat'}, 'data': {'input': {'messages': [[SystemMessage(content='You are a helpful assistant, you will analyze, translate and reformulate the user input message using the function provided'), HumanMessage(content='input: impact of ai?')]]}, 'output': {'generations': [[{'text': '', 'generation_info': {'finish_reason': 'stop'}, 'type': 'ChatGeneration', 'message': AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"intent\":\"ai_impact\"}', 'name': 'IntentCategorizer'}}, response_metadata={'finish_reason': 'stop'}, id='run-2d9ccf59-3d78-42b1-8458-83a9c3479ef8')}]], 'llm_output': None, 'run': None}}}\n", + "{'event': 'on_parser_start', 'name': 'JsonOutputFunctionsParser', 'run_id': 'bca6f5e6-2496-46bb-b94c-397c844977a0', 'tags': ['seq:step:3'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"intent\":\"ai_impact\"}', 'name': 'IntentCategorizer'}}, response_metadata={'finish_reason': 'stop'}, id='run-2d9ccf59-3d78-42b1-8458-83a9c3479ef8')}}\n", + "{'event': 'on_parser_end', 'name': 'JsonOutputFunctionsParser', 'run_id': 'bca6f5e6-2496-46bb-b94c-397c844977a0', 'tags': ['seq:step:3'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"intent\":\"ai_impact\"}', 'name': 'IntentCategorizer'}}, response_metadata={'finish_reason': 'stop'}, id='run-2d9ccf59-3d78-42b1-8458-83a9c3479ef8'), 'output': {'intent': 'ai_impact'}}}\n", + "{'event': 'on_chain_end', 'name': 'RunnableSequence', 'run_id': 'e5b8bbe4-eeb1-478a-a105-254d4f4a516b', 'tags': ['seq:step:1'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': {'input': 'impact of ai?'}, 'output': {'intent': 'ai_impact'}}}\n", + "{'event': 'on_chain_start', 'name': 'ChannelWrite', 'run_id': 'e89033a5-67a4-4ec1-813a-484d9192de38', 'tags': ['seq:step:2', 'langsmith:hidden'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': {'intent': 'ai_impact', 'language': 'English', 'query': 'impact of ai?'}}}\n", + "{'event': 'on_chain_end', 'name': 'ChannelWrite', 'run_id': 'e89033a5-67a4-4ec1-813a-484d9192de38', 'tags': ['seq:step:2', 'langsmith:hidden'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': {'intent': 'ai_impact', 'language': 'English', 'query': 'impact of ai?'}, 'output': {'intent': 'ai_impact', 'language': 'English', 'query': 'impact of ai?'}}}\n", + "{'event': 'on_chain_start', 'name': 'route_intent', 'run_id': '824d4a79-cc72-4068-ad0f-d0723e49af5d', 'tags': ['seq:step:3'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': {'user_input': 'impact of ai?', 'language': 'English', 'intent': 'ai_impact', 'query': 'impact of ai?', 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources_input': ['auto']}}}\n", + "{'event': 'on_chain_end', 'name': 'route_intent', 'run_id': '824d4a79-cc72-4068-ad0f-d0723e49af5d', 'tags': ['seq:step:3'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': {'user_input': 'impact of ai?', 'language': 'English', 'intent': 'ai_impact', 'query': 'impact of ai?', 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources_input': ['auto']}, 'output': 'answer_ai_impact'}}\n", + "{'event': 'on_chain_start', 'name': 'ChannelWrite', 'run_id': '107efbf2-bde3-4722-83f6-cdba0b3efaf4', 'tags': ['seq:step:3', 'langsmith:hidden'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': {'intent': 'ai_impact', 'language': 'English', 'query': 'impact of ai?'}}}\n", + "{'event': 'on_chain_end', 'name': 'ChannelWrite', 'run_id': '107efbf2-bde3-4722-83f6-cdba0b3efaf4', 'tags': ['seq:step:3', 'langsmith:hidden'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': {'intent': 'ai_impact', 'language': 'English', 'query': 'impact of ai?'}, 'output': {'intent': 'ai_impact', 'language': 'English', 'query': 'impact of ai?'}}}\n", + "{'event': 'on_chain_stream', 'name': 'categorize_intent', 'run_id': '66f31c85-1a4b-48b4-9e4f-ad884263809c', 'tags': ['graph:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'chunk': {'intent': 'ai_impact', 'language': 'English', 'query': 'impact of ai?'}}}\n", + "{'event': 'on_chain_end', 'name': 'categorize_intent', 'run_id': '66f31c85-1a4b-48b4-9e4f-ad884263809c', 'tags': ['graph:step:2'], 'metadata': {'langgraph_step': 2, 'langgraph_node': 'categorize_intent'}, 'data': {'input': {'user_input': 'impact of ai?', 'language': None, 'intent': None, 'query': None, 'questions': None, 'answer': None, 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources_input': ['auto'], 'documents': None, 'recommended_content': None, 'graph_returned': None}, 'output': {'intent': 'ai_impact', 'language': 'English', 'query': 'impact of ai?'}}}\n", + "{'event': 'on_chain_stream', 'run_id': 'da753bb9-2339-4fc0-b1d7-86443019c4df', 'tags': [], 'metadata': {}, 'name': 'LangGraph', 'data': {'chunk': {'categorize_intent': {'language': 'English', 'intent': 'ai_impact', 'query': 'impact of ai?'}}}}\n", + "{'event': 'on_chain_start', 'name': 'answer_ai_impact', 'run_id': '07ee7e5d-b2a1-4149-a7ee-8512df8fe31f', 'tags': ['graph:step:3'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact'}, 'data': {}}\n", + "{'event': 'on_chain_start', 'name': 'ai_impact_chain', 'run_id': '421aeadf-3c89-4fde-95c1-fe5967773978', 'tags': ['seq:step:1'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact'}, 'data': {'input': {'question': 'impact of ai?'}}}\n", + "{'event': 'on_prompt_start', 'name': 'ChatPromptTemplate', 'run_id': '113204c2-80d8-4e39-9397-3b7845991f57', 'tags': ['seq:step:1'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact'}, 'data': {'input': {'question': 'impact of ai?'}}}\n", + "{'event': 'on_prompt_end', 'name': 'ChatPromptTemplate', 'run_id': '113204c2-80d8-4e39-9397-3b7845991f57', 'tags': ['seq:step:1'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact'}, 'data': {'input': {'question': 'impact of ai?'}, 'output': ChatPromptValue(messages=[SystemMessage(content=\"\\nYou are ClimateQ&A, an helpful AI Assistant specialized in answering climate-related questions using info from the IPCC and/or IPBES reports. \\nAlways stay true to climate and nature science and do not make up information. \\nIf you do not know the answer, just say you do not know.\\n\\n## Guidelines\\n- Explain that the environmental impact of AI is not covered by the IPCC or IPBES reports, but you can recommend info based on the sources below\\n- Answer the question in the original language of the question\\n\\n## Sources\\n- You can propose to visit this page https://climateqa.com/docs/carbon-footprint/ to learn more about ClimateQ&A's own carbon footprint\\n- You can recommend to look at the work of the AI & climate expert scientist Sasha Luccioni with in in particular those papers\\n - Power Hungry Processing: Watts Driving the Cost of AI Deployment? - https://arxiv.org/abs/2311.16863 - about the carbon footprint at the inference stage of AI models\\n - Counting Carbon: A Survey of Factors Influencing the Emissions of Machine Learning - https://arxiv.org/abs/2302.08476\\n - Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model - https://arxiv.org/abs/2211.02001 - about the carbon footprint of training a large language model \\n- You can also recommend the following tools to calculate the carbon footprint of AI models\\n - CodeCarbon - https://github.com/mlco2/codecarbon to measure the carbon footprint of your code\\n - Ecologits - https://ecologits.ai/ to measure the carbon footprint of using LLMs APIs such\\n\"), HumanMessage(content='impact of ai?')])}}\n", + "{'event': 'on_chat_model_start', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'input': {'messages': [[SystemMessage(content=\"\\nYou are ClimateQ&A, an helpful AI Assistant specialized in answering climate-related questions using info from the IPCC and/or IPBES reports. \\nAlways stay true to climate and nature science and do not make up information. \\nIf you do not know the answer, just say you do not know.\\n\\n## Guidelines\\n- Explain that the environmental impact of AI is not covered by the IPCC or IPBES reports, but you can recommend info based on the sources below\\n- Answer the question in the original language of the question\\n\\n## Sources\\n- You can propose to visit this page https://climateqa.com/docs/carbon-footprint/ to learn more about ClimateQ&A's own carbon footprint\\n- You can recommend to look at the work of the AI & climate expert scientist Sasha Luccioni with in in particular those papers\\n - Power Hungry Processing: Watts Driving the Cost of AI Deployment? - https://arxiv.org/abs/2311.16863 - about the carbon footprint at the inference stage of AI models\\n - Counting Carbon: A Survey of Factors Influencing the Emissions of Machine Learning - https://arxiv.org/abs/2302.08476\\n - Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model - https://arxiv.org/abs/2211.02001 - about the carbon footprint of training a large language model \\n- You can also recommend the following tools to calculate the carbon footprint of AI models\\n - CodeCarbon - https://github.com/mlco2/codecarbon to measure the carbon footprint of your code\\n - Ecologits - https://ecologits.ai/ to measure the carbon footprint of using LLMs APIs such\\n\"), HumanMessage(content='impact of ai?')]]}}}\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='The', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' environmental', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' impact', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' of', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' AI', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' is', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' not', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' covered', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' by', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' the', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' IPCC', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' or', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' IP', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='B', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='ES', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' reports', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='.', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' However', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=',', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' there', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' are', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' studies', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' and', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' tools', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' available', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' that', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' can', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' help', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' understand', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' the', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' carbon', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' footprint', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' of', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' AI', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' models', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='.', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' \\n\\n', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='For', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' more', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' information', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' on', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' the', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' carbon', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' footprint', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' of', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' AI', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' models', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=',', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' you', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' can', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' visit', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' this', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' page', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=':', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' [', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='Climate', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='Q', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='&A', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=\"'s\", id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' own', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' carbon', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' footprint', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='](', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='https', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='://', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='climate', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='qa', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='.com', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='/docs', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='/c', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='arbon', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='-foot', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='print', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='/', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=').\\n\\n', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='Additionally', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=',', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' you', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' may', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' want', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' to', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' look', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' into', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' the', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' work', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' of', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' AI', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' &', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' climate', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' expert', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' scientist', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Sasha', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Lu', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='ccion', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='i', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='.', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Some', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' of', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' their', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' papers', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=',', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' such', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' as', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' \"', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='Power', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Hung', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='ry', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Processing', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=':', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Watts', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Driving', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' the', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Cost', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' of', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' AI', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Deployment', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='?\"', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' and', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' \"', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='Est', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='imating', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' the', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Carbon', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Foot', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='print', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' of', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' B', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='LO', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='OM', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=',', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' a', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' ', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='176', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='B', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Parameter', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Language', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Model', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=',\"', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' provide', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' insights', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' into', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' the', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' carbon', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' footprint', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' of', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' AI', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' models', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='.\\n\\n', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='To', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' calculate', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' the', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' carbon', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' footprint', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' of', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' AI', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' models', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=',', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' tools', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' like', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Code', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='Carbon', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' and', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Ec', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='olog', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='its', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' can', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' be', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' used', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='.', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Code', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='Carbon', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' helps', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' measure', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' the', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' carbon', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' footprint', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' of', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' your', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' code', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=',', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' while', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Ec', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='olog', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='its', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' can', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' measure', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' the', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' carbon', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' footprint', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' of', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' using', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Large', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Language', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' Models', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' (', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='LL', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='Ms', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=')', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content=' APIs', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='.', id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_stream', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'chunk': AIMessageChunk(content='', response_metadata={'finish_reason': 'stop'}, id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_chat_model_end', 'name': 'ChatOpenAI', 'run_id': 'db848c5f-43af-45e1-8b97-345044f399d6', 'tags': ['seq:step:2'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact', 'ls_model_type': 'chat'}, 'data': {'input': {'messages': [[SystemMessage(content=\"\\nYou are ClimateQ&A, an helpful AI Assistant specialized in answering climate-related questions using info from the IPCC and/or IPBES reports. \\nAlways stay true to climate and nature science and do not make up information. \\nIf you do not know the answer, just say you do not know.\\n\\n## Guidelines\\n- Explain that the environmental impact of AI is not covered by the IPCC or IPBES reports, but you can recommend info based on the sources below\\n- Answer the question in the original language of the question\\n\\n## Sources\\n- You can propose to visit this page https://climateqa.com/docs/carbon-footprint/ to learn more about ClimateQ&A's own carbon footprint\\n- You can recommend to look at the work of the AI & climate expert scientist Sasha Luccioni with in in particular those papers\\n - Power Hungry Processing: Watts Driving the Cost of AI Deployment? - https://arxiv.org/abs/2311.16863 - about the carbon footprint at the inference stage of AI models\\n - Counting Carbon: A Survey of Factors Influencing the Emissions of Machine Learning - https://arxiv.org/abs/2302.08476\\n - Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model - https://arxiv.org/abs/2211.02001 - about the carbon footprint of training a large language model \\n- You can also recommend the following tools to calculate the carbon footprint of AI models\\n - CodeCarbon - https://github.com/mlco2/codecarbon to measure the carbon footprint of your code\\n - Ecologits - https://ecologits.ai/ to measure the carbon footprint of using LLMs APIs such\\n\"), HumanMessage(content='impact of ai?')]]}, 'output': {'generations': [[{'text': 'The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.', 'generation_info': {'finish_reason': 'stop'}, 'type': 'ChatGeneration', 'message': AIMessage(content='The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.', response_metadata={'finish_reason': 'stop'}, id='run-db848c5f-43af-45e1-8b97-345044f399d6')}]], 'llm_output': None, 'run': None}}}\n", + "{'event': 'on_parser_start', 'name': 'StrOutputParser', 'run_id': 'bd6980fe-1dc1-4733-a38e-a461801250a8', 'tags': ['seq:step:3'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact'}, 'data': {'input': AIMessage(content='The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.', response_metadata={'finish_reason': 'stop'}, id='run-db848c5f-43af-45e1-8b97-345044f399d6')}}\n", + "{'event': 'on_parser_end', 'name': 'StrOutputParser', 'run_id': 'bd6980fe-1dc1-4733-a38e-a461801250a8', 'tags': ['seq:step:3'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact'}, 'data': {'input': AIMessage(content='The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.', response_metadata={'finish_reason': 'stop'}, id='run-db848c5f-43af-45e1-8b97-345044f399d6'), 'output': 'The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.'}}\n", + "{'event': 'on_chain_end', 'name': 'ai_impact_chain', 'run_id': '421aeadf-3c89-4fde-95c1-fe5967773978', 'tags': ['seq:step:1'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact'}, 'data': {'input': {'question': 'impact of ai?'}, 'output': 'The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.'}}\n", + "{'event': 'on_chain_start', 'name': 'ChannelWrite', 'run_id': 'c3f2dc9c-e005-436a-91ff-6236b9359548', 'tags': ['seq:step:2', 'langsmith:hidden'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact'}, 'data': {'input': {'answer': 'The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.'}}}\n", + "{'event': 'on_chain_end', 'name': 'ChannelWrite', 'run_id': 'c3f2dc9c-e005-436a-91ff-6236b9359548', 'tags': ['seq:step:2', 'langsmith:hidden'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact'}, 'data': {'input': {'answer': 'The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.'}, 'output': {'answer': 'The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.'}}}\n", + "{'event': 'on_chain_stream', 'name': 'answer_ai_impact', 'run_id': '07ee7e5d-b2a1-4149-a7ee-8512df8fe31f', 'tags': ['graph:step:3'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact'}, 'data': {'chunk': {'answer': 'The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.'}}}\n", + "{'event': 'on_chain_end', 'name': 'answer_ai_impact', 'run_id': '07ee7e5d-b2a1-4149-a7ee-8512df8fe31f', 'tags': ['graph:step:3'], 'metadata': {'langgraph_step': 3, 'langgraph_node': 'answer_ai_impact'}, 'data': {'input': {'user_input': 'impact of ai?', 'language': 'English', 'intent': 'ai_impact', 'query': 'impact of ai?', 'questions': None, 'answer': None, 'audience': 'expert and climate scientists that are not afraid of technical terms', 'sources_input': ['auto'], 'documents': None, 'recommended_content': None, 'graph_returned': None}, 'output': {'answer': 'The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.'}}}\n", + "{'event': 'on_chain_stream', 'run_id': 'da753bb9-2339-4fc0-b1d7-86443019c4df', 'tags': [], 'metadata': {}, 'name': 'LangGraph', 'data': {'chunk': {'answer_ai_impact': {'answer': 'The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.'}}}}\n", + "{'event': 'on_chain_end', 'name': 'LangGraph', 'run_id': 'da753bb9-2339-4fc0-b1d7-86443019c4df', 'tags': [], 'metadata': {}, 'data': {'output': {'answer_ai_impact': {'answer': 'The environmental impact of AI is not covered by the IPCC or IPBES reports. However, there are studies and tools available that can help understand the carbon footprint of AI models. \\n\\nFor more information on the carbon footprint of AI models, you can visit this page: [ClimateQ&A\\'s own carbon footprint](https://climateqa.com/docs/carbon-footprint/).\\n\\nAdditionally, you may want to look into the work of AI & climate expert scientist Sasha Luccioni. Some of their papers, such as \"Power Hungry Processing: Watts Driving the Cost of AI Deployment?\" and \"Estimating the Carbon Footprint of BLOOM, a 176B Parameter Language Model,\" provide insights into the carbon footprint of AI models.\\n\\nTo calculate the carbon footprint of AI models, tools like CodeCarbon and Ecologits can be used. CodeCarbon helps measure the carbon footprint of your code, while Ecologits can measure the carbon footprint of using Large Language Models (LLMs) APIs.'}}}}\n" + ] + }, + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mThe Kernel crashed while executing code in the current cell or a previous cell. \n", + "\u001b[1;31mPlease review the code in the cell(s) to identify a possible cause of the failure. \n", + "\u001b[1;31mClick here for more info. \n", + "\u001b[1;31mView Jupyter log for further details." + ] + } + ], + "source": [ + "async for event in result:\n", + " print(event)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Gradio" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "from front.utils import make_html_source,parse_output_llm_with_sources,serialize_docs,make_toolbox\n", + "query = inputs[\"user_input\"]\n", + "steps_display = {\n", + "\"categorize_intent\":(\"🔄️ Analyzing user message\",True),\n", + "\"transform_query\":(\"🔄️ Thinking step by step to answer the question\",True),\n", + "\"retrieve_documents\":(\"🔄️ Searching in the knowledge base\",False),\n", + "}\n", + "history = [(query,None)]\n", + "start_streaming = False\n", + "intent = None\n", + "\n", + "\n", + "async for event in result:\n", + "\n", + " if event[\"event\"] == \"on_chat_model_stream\" and event[\"metadata\"][\"langgraph_node\"] in [\"answer_rag\", \"answer_chitchat\", \"answer_ai_impact\"]:\n", + " if start_streaming == False:\n", + " start_streaming = True\n", + " history[-1] = (query,\"\")\n", + "\n", + " new_token = event[\"data\"][\"chunk\"].content\n", + " # time.sleep(0.01)\n", + " previous_answer = history[-1][1]\n", + " previous_answer = previous_answer if previous_answer is not None else \"\"\n", + " answer_yet = previous_answer + new_token\n", + " answer_yet = parse_output_llm_with_sources(answer_yet)\n", + " history[-1] = (query,answer_yet)\n", + "\n", + " \n", + " elif event[\"name\"] == \"retrieve_documents\" and event[\"event\"] == \"on_chain_end\":\n", + " try:\n", + " docs = event[\"data\"][\"output\"][\"documents\"]\n", + " docs_html = []\n", + " for i, d in enumerate(docs, 1):\n", + " docs_html.append(make_html_source(d, i))\n", + " docs_html = \"\".join(docs_html)\n", + " except Exception as e:\n", + " print(f\"Error getting documents: {e}\")\n", + " print(event)\n", + "\n", + " # elif event[\"name\"] == \"retrieve_documents\" and event[\"event\"] == \"on_chain_start\":\n", + " # print(event)\n", + " # questions = event[\"data\"][\"input\"][\"questions\"]\n", + " # questions = \"\\n\".join([f\"{i+1}. {q['question']} ({q['source']})\" for i,q in enumerate(questions)])\n", + " # answer_yet = \"🔄️ Searching in the knowledge base\\n{questions}\"\n", + " # history[-1] = (query,answer_yet)\n", + "\n", + " elif event[\"name\"] == \"retrieve_graphs\" and event[\"event\"] == \"on_chain_end\":\n", + " try:\n", + " graphs = event[\"data\"][\"output\"][\"recommended_content\"]\n", + " except Exception as e:\n", + " print(f\"Error getting graphs: {e}\")\n", + " print(event)\n", + "\n", + "\n", + " for event_name,(event_description,display_output) in steps_display.items():\n", + " if event[\"name\"] == event_name:\n", + " if event[\"event\"] == \"on_chain_start\":\n", + " # answer_yet = f\"

{event_description}

\"\n", + " # answer_yet = make_toolbox(event_description, \"\", checked = False)\n", + " answer_yet = event_description\n", + " history[-1] = (query,answer_yet)\n", + " # elif event[\"event\"] == \"on_chain_end\":\n", + " # answer_yet = \"\"\n", + " # history[-1] = (query,answer_yet)\n", + " # if display_output:\n", + " # print(event[\"data\"][\"output\"])\n", + "\n", + " # if op['path'] == path_reformulation: # reforulated question\n", + " # try:\n", + " # output_language = op['value'][\"language\"] # str\n", + " # output_query = op[\"value\"][\"question\"]\n", + " # except Exception as e:\n", + " # raise gr.Error(f\"ClimateQ&A Error: {e} - The error has been noted, try another question and if the error remains, you can contact us :)\")\n", + " \n", + " # if op[\"path\"] == path_keywords:\n", + " # try:\n", + " # output_keywords = op['value'][\"keywords\"] # str\n", + " # output_keywords = \" AND \".join(output_keywords)\n", + " # except Exception as e:\n", + " # pass\n", + "\n", + "\n", + "\n", + " history = [tuple(x) for x in history]\n", + " # yield history,docs_html,output_query,output_language,gallery,output_query,output_keywords" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_383', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The global mean surface temperature change as a result of the cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.', 'url': 'https://ourworldindata.org/grapher/global-warming-by-gas-and-source', 'similarity_score': 0.5550143122673035, 'content': 'Global warming contributions by gas and source', 'reranking_score': 0.651607871055603, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}, page_content='Global warming contributions by gas and source'),\n", + " Document(metadata={'category': 'Climate Change', 'doc_id': 'owid_764', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The global mean surface temperature change as a result of the cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.', 'url': 'https://ourworldindata.org/grapher/global-warming-by-gas-and-source', 'similarity_score': 0.5550143122673035, 'content': 'Global warming contributions by gas and source', 'reranking_score': 0.651607871055603, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}, page_content='Global warming contributions by gas and source'),\n", + " Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_384', 'returned_content': '', 'source': 'OWID', 'subtitle': \"The global mean surface temperature change as a result of a country or region's cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/warming-fossil-fuels-land-use', 'similarity_score': 0.6049439907073975, 'content': 'Global warming contributions from fossil fuels and land use', 'reranking_score': 0.22002366185188293, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}, page_content='Global warming contributions from fossil fuels and land use'),\n", + " Document(metadata={'category': 'Climate Change', 'doc_id': 'owid_765', 'returned_content': '', 'source': 'OWID', 'subtitle': \"The global mean surface temperature change as a result of a country or region's cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/warming-fossil-fuels-land-use', 'similarity_score': 0.6049439907073975, 'content': 'Global warming contributions from fossil fuels and land use', 'reranking_score': 0.22002366185188293, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}, page_content='Global warming contributions from fossil fuels and land use'),\n", + " Document(metadata={'appears_in': 'Global Methane Tracker 2024', 'appears_in_url': 'https://www.iea.org/reports/global-methane-tracker-2024', 'doc_id': 'iea_133', 'returned_content': 'https://www.iea.org/data-and-statistics/charts/main-sources-of-methane-emissions', 'source': 'IEA', 'sources': 'Methane emissions and abatement potential for oil, gas, and coal are based on the IEA (2023) Global Methane Tracker (https://www.iea.org/data-and-statistics/data-tools/methane-tracker-data-explorer) ; agriculture and waste is based on UNEP (2023), Global Methane Assessment (https://www.unep.org/resources/report/global-methane-assessment-benefits-and-costs-mitigating-methane-emissions). Emissions from biomass and bioenergy burning, which total around 10 Mt (https://essd.copernicus.org/articles/12/1561/2020/) of methane per year each, are not shown.', 'similarity_score': 0.6158384084701538, 'content': 'Main sources of methane emissions', 'reranking_score': 0.0806397795677185, 'query_used_for_retrieval': 'What are the main causes of global warming?', 'sources_used': ['IEA', 'OWID']}, page_content='Main sources of methane emissions'),\n", + " Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_386', 'returned_content': '', 'source': 'OWID', 'subtitle': \"This is shown as a country or region's share of the global mean surface temperature change as a result of its cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/contributions-global-temp-change', 'similarity_score': 0.6807445883750916, 'content': 'Global warming: Contributions to the change in global mean surface temperature', 'reranking_score': 0.03409431874752045, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}, page_content='Global warming: Contributions to the change in global mean surface temperature'),\n", + " Document(metadata={'category': 'Climate Change', 'doc_id': 'owid_766', 'returned_content': '', 'source': 'OWID', 'subtitle': \"This is shown as a country or region's share of the global mean surface temperature change as a result of its cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/contributions-global-temp-change', 'similarity_score': 0.6807445883750916, 'content': 'Global warming: Contributions to the change in global mean surface temperature', 'reranking_score': 0.03409431874752045, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}, page_content='Global warming: Contributions to the change in global mean surface temperature'),\n", + " Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_342', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions factors quantify the average CO₂ output per unit of energy. They are measured in kilograms of CO₂ per megawatt-hour (MWh) of energy from various fossil fuel sources.', 'url': 'https://ourworldindata.org/grapher/carbon-dioxide-emissions-factor', 'similarity_score': 0.6963810324668884, 'content': 'Carbon dioxide emissions factors', 'reranking_score': 0.007733839564025402, 'query_used_for_retrieval': 'What are the main causes of global warming?', 'sources_used': ['IEA', 'OWID']}, page_content='Carbon dioxide emissions factors'),\n", + " Document(metadata={'category': 'Fossil Fuels', 'doc_id': 'owid_1408', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions factors quantify the average CO₂ output per unit of energy. They are measured in kilograms of CO₂ per megawatt-hour (MWh) of energy from various fossil fuel sources.', 'url': 'https://ourworldindata.org/grapher/carbon-dioxide-emissions-factor', 'similarity_score': 0.6963810324668884, 'content': 'Carbon dioxide emissions factors', 'reranking_score': 0.007733839564025402, 'query_used_for_retrieval': 'What are the main causes of global warming?', 'sources_used': ['IEA', 'OWID']}, page_content='Carbon dioxide emissions factors'),\n", + " Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_359', 'returned_content': '', 'source': 'OWID', 'subtitle': \"The global mean surface temperature change as a result of a country or region's cumulative emissions of carbon dioxide, methane, and nitrous oxide. This is for land use and agriculture only.\", 'url': 'https://ourworldindata.org/grapher/global-warming-land', 'similarity_score': 0.7010847330093384, 'content': 'Contribution to global mean surface temperature rise from agriculture and land use', 'reranking_score': 0.006090907845646143, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}, page_content='Contribution to global mean surface temperature rise from agriculture and land use'),\n", + " Document(metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_387', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Greenhouse gas emissions include carbon dioxide, methane and nitrous oxide from all sources, including land-use change. They are measured in tonnes of carbon dioxide-equivalents over a 100-year timescale.', 'url': 'https://ourworldindata.org/grapher/total-ghg-emissions', 'similarity_score': 0.711588978767395, 'content': 'Greenhouse gas emissions', 'reranking_score': 0.001999091589823365, 'query_used_for_retrieval': 'What are the main causes of global warming?', 'sources_used': ['IEA', 'OWID']}, page_content='Greenhouse gas emissions')]" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from langchain_core.documents import Document\n", + "\n", + "graphs = [Document(page_content='Global warming contributions by gas and source', metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_383', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The global mean surface temperature change as a result of the cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.', 'url': 'https://ourworldindata.org/grapher/global-warming-by-gas-and-source', 'similarity_score': 0.5550143122673035, 'content': 'Global warming contributions by gas and source', 'reranking_score': 0.651607871055603, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Global warming contributions by gas and source', metadata={'category': 'Climate Change', 'doc_id': 'owid_764', 'returned_content': '', 'source': 'OWID', 'subtitle': 'The global mean surface temperature change as a result of the cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.', 'url': 'https://ourworldindata.org/grapher/global-warming-by-gas-and-source', 'similarity_score': 0.5550143122673035, 'content': 'Global warming contributions by gas and source', 'reranking_score': 0.651607871055603, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Global warming contributions from fossil fuels and land use', metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_384', 'returned_content': '', 'source': 'OWID', 'subtitle': \"The global mean surface temperature change as a result of a country or region's cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/warming-fossil-fuels-land-use', 'similarity_score': 0.6049439907073975, 'content': 'Global warming contributions from fossil fuels and land use', 'reranking_score': 0.22002366185188293, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Global warming contributions from fossil fuels and land use', metadata={'category': 'Climate Change', 'doc_id': 'owid_765', 'returned_content': '', 'source': 'OWID', 'subtitle': \"The global mean surface temperature change as a result of a country or region's cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/warming-fossil-fuels-land-use', 'similarity_score': 0.6049439907073975, 'content': 'Global warming contributions from fossil fuels and land use', 'reranking_score': 0.22002366185188293, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Main sources of methane emissions', metadata={'appears_in': 'Global Methane Tracker 2024', 'appears_in_url': 'https://www.iea.org/reports/global-methane-tracker-2024', 'doc_id': 'iea_133', 'returned_content': 'https://www.iea.org/data-and-statistics/charts/main-sources-of-methane-emissions', 'source': 'IEA', 'sources': 'Methane emissions and abatement potential for oil, gas, and coal are based on the IEA (2023) Global Methane Tracker (https://www.iea.org/data-and-statistics/data-tools/methane-tracker-data-explorer) ; agriculture and waste is based on UNEP (2023), Global Methane Assessment (https://www.unep.org/resources/report/global-methane-assessment-benefits-and-costs-mitigating-methane-emissions). Emissions from biomass and bioenergy burning, which total around 10 Mt (https://essd.copernicus.org/articles/12/1561/2020/) of methane per year each, are not shown.', 'similarity_score': 0.6158384084701538, 'content': 'Main sources of methane emissions', 'reranking_score': 0.0806397795677185, 'query_used_for_retrieval': 'What are the main causes of global warming?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Global warming: Contributions to the change in global mean surface temperature', metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_386', 'returned_content': '', 'source': 'OWID', 'subtitle': \"This is shown as a country or region's share of the global mean surface temperature change as a result of its cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/contributions-global-temp-change', 'similarity_score': 0.6807445883750916, 'content': 'Global warming: Contributions to the change in global mean surface temperature', 'reranking_score': 0.03409431874752045, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Global warming: Contributions to the change in global mean surface temperature', metadata={'category': 'Climate Change', 'doc_id': 'owid_766', 'returned_content': '', 'source': 'OWID', 'subtitle': \"This is shown as a country or region's share of the global mean surface temperature change as a result of its cumulative emissions of three gases – carbon dioxide, methane, and nitrous oxide.\", 'url': 'https://ourworldindata.org/grapher/contributions-global-temp-change', 'similarity_score': 0.6807445883750916, 'content': 'Global warming: Contributions to the change in global mean surface temperature', 'reranking_score': 0.03409431874752045, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Carbon dioxide emissions factors', metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_342', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions factors quantify the average CO₂ output per unit of energy. They are measured in kilograms of CO₂ per megawatt-hour (MWh) of energy from various fossil fuel sources.', 'url': 'https://ourworldindata.org/grapher/carbon-dioxide-emissions-factor', 'similarity_score': 0.6963810324668884, 'content': 'Carbon dioxide emissions factors', 'reranking_score': 0.007733839564025402, 'query_used_for_retrieval': 'What are the main causes of global warming?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Carbon dioxide emissions factors', metadata={'category': 'Fossil Fuels', 'doc_id': 'owid_1408', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Emissions factors quantify the average CO₂ output per unit of energy. They are measured in kilograms of CO₂ per megawatt-hour (MWh) of energy from various fossil fuel sources.', 'url': 'https://ourworldindata.org/grapher/carbon-dioxide-emissions-factor', 'similarity_score': 0.6963810324668884, 'content': 'Carbon dioxide emissions factors', 'reranking_score': 0.007733839564025402, 'query_used_for_retrieval': 'What are the main causes of global warming?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Contribution to global mean surface temperature rise from agriculture and land use', metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_359', 'returned_content': '', 'source': 'OWID', 'subtitle': \"The global mean surface temperature change as a result of a country or region's cumulative emissions of carbon dioxide, methane, and nitrous oxide. This is for land use and agriculture only.\", 'url': 'https://ourworldindata.org/grapher/global-warming-land', 'similarity_score': 0.7010847330093384, 'content': 'Contribution to global mean surface temperature rise from agriculture and land use', 'reranking_score': 0.006090907845646143, 'query_used_for_retrieval': 'How do human activities contribute to global warming?', 'sources_used': ['IEA', 'OWID']}), Document(page_content='Greenhouse gas emissions', metadata={'category': 'CO2 & Greenhouse Gas Emissions', 'doc_id': 'owid_387', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Greenhouse gas emissions include carbon dioxide, methane and nitrous oxide from all sources, including land-use change. They are measured in tonnes of carbon dioxide-equivalents over a 100-year timescale.', 'url': 'https://ourworldindata.org/grapher/total-ghg-emissions', 'similarity_score': 0.711588978767395, 'content': 'Greenhouse gas emissions', 'reranking_score': 0.001999091589823365, 'query_used_for_retrieval': 'What are the main causes of global warming?', 'sources_used': ['IEA', 'OWID']})]\n", + "graphs" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'embedding': '',\n", + " 'metadata': {'source': 'OWID',\n", + " 'category': 'CO2 & Greenhouse Gas Emissions'}},\n", + " {'embedding': '',\n", + " 'metadata': {'source': 'OWID', 'category': 'Climate Change'}},\n", + " {'embedding': '',\n", + " 'metadata': {'source': 'OWID',\n", + " 'category': 'CO2 & Greenhouse Gas Emissions'}},\n", + " {'embedding': '',\n", + " 'metadata': {'source': 'OWID', 'category': 'Climate Change'}},\n", + " {'embedding': '',\n", + " 'metadata': {'source': 'OWID',\n", + " 'category': 'CO2 & Greenhouse Gas Emissions'}},\n", + " {'embedding': '',\n", + " 'metadata': {'source': 'OWID', 'category': 'Climate Change'}},\n", + " {'embedding': '',\n", + " 'metadata': {'source': 'OWID',\n", + " 'category': 'CO2 & Greenhouse Gas Emissions'}},\n", + " {'embedding': '',\n", + " 'metadata': {'source': 'OWID', 'category': 'Fossil Fuels'}},\n", + " {'embedding': '',\n", + " 'metadata': {'source': 'OWID',\n", + " 'category': 'CO2 & Greenhouse Gas Emissions'}},\n", + " {'embedding': '',\n", + " 'metadata': {'source': 'OWID',\n", + " 'category': 'CO2 & Greenhouse Gas Emissions'}}]" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "graphs = [\n", + " {\n", + " \"embedding\": x.metadata[\"returned_content\"],\n", + " \"metadata\": {\n", + " \"source\": x.metadata[\"source\"],\n", + " \"category\": x.metadata[\"category\"]\n", + " }\n", + " } for x in graphs if x.metadata[\"source\"] == \"OWID\"\n", + " ]\n", + "\n", + "graphs" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "from collections import defaultdict\n", + "\n", + "def generate_html(graphs):\n", + " # Organize graphs by category\n", + " categories = defaultdict(list)\n", + " for graph in graphs:\n", + " category = graph['metadata']['category']\n", + " categories[category].append(graph['embedding'])\n", + "\n", + " # Begin constructing the HTML\n", + " html_code = '''\n", + "\n", + "\n", + "\n", + " \n", + " \n", + " Graphs by Category\n", + " \n", + " \n", + "\n", + "\n", + "
\n", + "'''\n", + "\n", + " # Add buttons for each category\n", + " for i, category in enumerate(categories.keys()):\n", + " active_class = 'active' if i == 0 else ''\n", + " html_code += f''\n", + "\n", + " html_code += '
'\n", + "\n", + " # Add content for each category\n", + " for i, (category, embeds) in enumerate(categories.items()):\n", + " active_class = 'active' if i == 0 else ''\n", + " html_code += f'
'\n", + " for embed in embeds:\n", + " html_code += embed\n", + " html_code += '
'\n", + "\n", + " html_code += '''\n", + "\n", + "\n", + "'''\n", + "\n", + " return html_code\n" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'\\n\\n\\n\\n \\n \\n Graphs by Category\\n \\n \\n\\n\\n
\\n
\\n\\n\\n'" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "generate_html(graphs)" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Document(metadata={'category': 'Water Use & Stress', 'doc_id': 'owid_2184', 'returned_content': '', 'source': 'OWID', 'subtitle': 'Water quality is assessed by means of core physical and chemical parameters that reflect natural water quality. A water body is classified as \"good\" quality if at least 80% of monitoring values meet target quality levels.', 'url': 'https://ourworldindata.org/grapher/water-bodies-good-water-quality'}, page_content='Share of water bodies with good ambient water quality')" + ] + }, + "execution_count": 65, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "vectorstore_graphs.similarity_search_with_relevance_scores(\"What is the trend of clean water?\")[0][0]" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['',\n", + " '',\n", + " '',\n", + " '']" + ] + }, + "execution_count": 66, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "test_graphs = [x[0].metadata[\"returned_content\"] for x in vectorstore_graphs.similarity_search_with_relevance_scores(\"What is the trend of clean water?\")]\n", + "test_graphs" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:httpx:HTTP Request: GET https://api.gradio.app/pkg-version \"HTTP/1.1 200 OK\"\n", + "INFO:httpx:HTTP Request: GET http://127.0.0.1:7868/gradio_api/startup-events \"HTTP/1.1 200 OK\"\n", + "INFO:httpx:HTTP Request: HEAD http://127.0.0.1:7868/ \"HTTP/1.1 200 OK\"\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Running on local URL: http://127.0.0.1:7868\n", + "\n", + "To create a public link, set `share=True` in `launch()`.\n" + ] + }, + { + "data": { + "text/html": [ + "
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# simple gradio\n", + "import gradio as gr\n", + "with gr.Blocks() as blocks:\n", + " state_test = gr.State([])\n", + " \n", + " button = gr.Button(\"abc\")\n", + " button.click(lambda : graphs, inputs = [], outputs = state_test)\n", + " with gr.Column():\n", + " # gr.HTML(generate_html(graphs), elem_id=\"graphs-placeholder\")\n", + " gr.HTML(test_graphs)\n", + " # gr.HTML(generate_html(state_test), elem_id=\"graphs-placeholder\")\n", + "\n", + "blocks.launch()\n", + "\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:sentence_transformers.SentenceTransformer:Use pytorch device_name: cpu\n", + "INFO:sentence_transformers.SentenceTransformer:Load pretrained SentenceTransformer: BAAI/bge-base-en-v1.5\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading embeddings model: BAAI/bge-base-en-v1.5\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/dora/anaconda3/envs/climateqa_huggingface/lib/python3.12/site-packages/huggingface_hub/file_download.py:1132: FutureWarning: `resume_download` is deprecated and will be removed in version 1.0.0. Downloads always resume when possible. If you want to force a new download, use `force_download=True`.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading FlashRankRanker model ms-marco-TinyBERT-L-2-v2\n", + "Loading model FlashRank model ms-marco-TinyBERT-L-2-v2...\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:chromadb.telemetry.posthog:Anonymized telemetry enabled. See https://docs.trychroma.com/telemetry for more information.\n" + ] + }, + { + "ename": "NameError", + "evalue": "name 'make_graph_agent' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[18], line 10\u001b[0m\n\u001b[1;32m 7\u001b[0m vectorstore_graphs \u001b[38;5;241m=\u001b[39m Chroma(persist_directory\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m/home/dora/climate-question-answering/data/vectorstore\u001b[39m\u001b[38;5;124m\"\u001b[39m, embedding_function\u001b[38;5;241m=\u001b[39membeddings_function)\n\u001b[1;32m 9\u001b[0m \u001b[38;5;66;03m# agent = make_graph_agent(llm,vectorstore,reranker)\u001b[39;00m\n\u001b[0;32m---> 10\u001b[0m agent \u001b[38;5;241m=\u001b[39m \u001b[43mmake_graph_agent\u001b[49m(llm\u001b[38;5;241m=\u001b[39mllm, vectorstore_ipcc\u001b[38;5;241m=\u001b[39mvectorstore, vectorstore_graphs\u001b[38;5;241m=\u001b[39mvectorstore_graphs, reranker\u001b[38;5;241m=\u001b[39mreranker)\n\u001b[1;32m 12\u001b[0m \u001b[38;5;28;01masync\u001b[39;00m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mchat\u001b[39m(query,history,audience,sources,reports):\n\u001b[1;32m 13\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"taking a query and a message history, use a pipeline (reformulation, retriever, answering) to yield a tuple of:\u001b[39;00m\n\u001b[1;32m 14\u001b[0m \u001b[38;5;124;03m (messages in gradio format, messages in langchain format, source documents)\"\"\"\u001b[39;00m\n", + "\u001b[0;31mNameError\u001b[0m: name 'make_graph_agent' is not defined" + ] + } + ], + "source": [ + "embeddings_function = get_embeddings_function()\n", + "llm = get_llm(provider=\"openai\",max_tokens = 1024,temperature = 0.0)\n", + "reranker = get_reranker(\"nano\")\n", + "\n", + "# Create vectorstore and retriever\n", + "vectorstore = get_pinecone_vectorstore(embeddings_function)\n", + "vectorstore_graphs = Chroma(persist_directory=f\"{ROOT_DIR}/data/vectorstore\", embedding_function=embeddings_function)\n", + "\n", + "# agent = make_graph_agent(llm,vectorstore,reranker)\n", + "agent = make_graph_agent(llm=llm, vectorstore_ipcc=vectorstore, vectorstore_graphs=vectorstore_graphs, reranker=reranker)\n", + "\n", + "async def chat(query,history,audience,sources,reports):\n", + " \"\"\"taking a query and a message history, use a pipeline (reformulation, retriever, answering) to yield a tuple of:\n", + " (messages in gradio format, messages in langchain format, source documents)\"\"\"\n", + "\n", + " date_now = datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")\n", + " print(f\">> NEW QUESTION ({date_now}) : {query}\")\n", + "\n", + " if audience == \"Children\":\n", + " audience_prompt = audience_prompts[\"children\"]\n", + " elif audience == \"General public\":\n", + " audience_prompt = audience_prompts[\"general\"]\n", + " elif audience == \"Experts\":\n", + " audience_prompt = audience_prompts[\"experts\"]\n", + " else:\n", + " audience_prompt = audience_prompts[\"experts\"]\n", + "\n", + " # Prepare default values\n", + " if len(sources) == 0:\n", + " sources = [\"IPCC\"]\n", + "\n", + " if len(reports) == 0:\n", + " reports = []\n", + " \n", + " inputs = {\"user_input\": query,\"audience\": audience_prompt,\"sources\":sources}\n", + " print(f\"\\n\\nInputs:\\n {inputs}\\n\\n\")\n", + " result = agent.astream_events(inputs,version = \"v1\") #{\"callbacks\":[MyCustomAsyncHandler()]})\n", + " # result = rag_chain.stream(inputs)\n", + "\n", + " # path_reformulation = \"/logs/reformulation/final_output\"\n", + " # path_keywords = \"/logs/keywords/final_output\"\n", + " # path_retriever = \"/logs/find_documents/final_output\"\n", + " # path_answer = \"/logs/answer/streamed_output_str/-\"\n", + "\n", + " docs = []\n", + " graphs_html = \"\"\n", + " docs_html = \"\"\n", + " output_query = \"\"\n", + " output_language = \"\"\n", + " output_keywords = \"\"\n", + " gallery = []\n", + " updates = {}\n", + " start_streaming = False\n", + "\n", + " steps_display = {\n", + " \"categorize_intent\":(\"🔄️ Analyzing user message\",True),\n", + " \"transform_query\":(\"🔄️ Thinking step by step to answer the question\",True),\n", + " \"retrieve_documents\":(\"🔄️ Searching in the knowledge base\",False),\n", + " }\n", + "\n", + " try:\n", + " async for event in result:\n", + "\n", + " if event[\"event\"] == \"on_chat_model_stream\" and event[\"metadata\"][\"langgraph_node\"] in [\"answer_rag\", \"answer_chitchat\", \"answer_ai_impact\"]:\n", + " if start_streaming == False:\n", + " start_streaming = True\n", + " history[-1] = (query,\"\")\n", + "\n", + " new_token = event[\"data\"][\"chunk\"].content\n", + " # time.sleep(0.01)\n", + " previous_answer = history[-1][1]\n", + " previous_answer = previous_answer if previous_answer is not None else \"\"\n", + " answer_yet = previous_answer + new_token\n", + " answer_yet = parse_output_llm_with_sources(answer_yet)\n", + " history[-1] = (query,answer_yet)\n", + " \n", + " elif event[\"name\"] == \"retrieve_documents\" and event[\"event\"] == \"on_chain_end\":\n", + " try:\n", + " docs = event[\"data\"][\"output\"][\"documents\"]\n", + " docs_html = []\n", + " for i, d in enumerate(docs, 1):\n", + " docs_html.append(make_html_source(d, i))\n", + " docs_html = \"\".join(docs_html)\n", + "\n", + " print(docs_html)\n", + " except Exception as e:\n", + " print(f\"Error getting documents: {e}\")\n", + " print(event)\n", + "\n", + " # elif event[\"name\"] == \"retrieve_documents\" and event[\"event\"] == \"on_chain_start\":\n", + " # print(event)\n", + " # questions = event[\"data\"][\"input\"][\"questions\"]\n", + " # questions = \"\\n\".join([f\"{i+1}. {q['question']} ({q['source']})\" for i,q in enumerate(questions)])\n", + " # answer_yet = \"🔄️ Searching in the knowledge base\\n{questions}\"\n", + " # history[-1] = (query,answer_yet)\n", + "\n", + " elif event[\"name\"] == \"retrieve_graphs\" and event[\"event\"] == \"on_chain_end\":\n", + " try:\n", + " recommended_content = event[\"data\"][\"output\"][\"recommended_content\"]\n", + " graphs = [\n", + " {\n", + " \"embedding\": x.metadata[\"returned_content\"],\n", + " \"metadata\": {\n", + " \"source\": x.metadata[\"source\"],\n", + " \"category\": x.metadata[\"category\"]\n", + " }\n", + " } for x in recommended_content if x.metadata[\"source\"] == \"OWID\"\n", + " ]\n", + " \n", + " graphs_by_category = defaultdict(list)\n", + " \n", + " # Organize graphs by category\n", + " for graph in graphs:\n", + " category = graph['metadata']['category']\n", + " graphs_by_category[category].append(graph['embedding']) \n", + "\n", + " \n", + " for category, graphs in graphs_by_category.items():\n", + " embeddings = \"\\n\".join(graphs)\n", + " updates[graph_displays[category]] = embeddings\n", + " \n", + " print(f\"\\n\\nUpdates:\\n {updates}\\n\\n\")\n", + " \n", + " except Exception as e:\n", + " print(f\"Error getting graphs: {e}\")\n", + "\n", + " for event_name,(event_description,display_output) in steps_display.items():\n", + " if event[\"name\"] == event_name:\n", + " if event[\"event\"] == \"on_chain_start\":\n", + " # answer_yet = f\"

{event_description}

\"\n", + " # answer_yet = make_toolbox(event_description, \"\", checked = False)\n", + " answer_yet = event_description\n", + " history[-1] = (query,answer_yet)\n", + " # elif event[\"event\"] == \"on_chain_end\":\n", + " # answer_yet = \"\"\n", + " # history[-1] = (query,answer_yet)\n", + " # if display_output:\n", + " # print(event[\"data\"][\"output\"])\n", + "\n", + " # if op['path'] == path_reformulation: # reforulated question\n", + " # try:\n", + " # output_language = op['value'][\"language\"] # str\n", + " # output_query = op[\"value\"][\"question\"]\n", + " # except Exception as e:\n", + " # raise gr.Error(f\"ClimateQ&A Error: {e} - The error has been noted, try another question and if the error remains, you can contact us :)\")\n", + " \n", + " # if op[\"path\"] == path_keywords:\n", + " # try:\n", + " # output_keywords = op['value'][\"keywords\"] # str\n", + " # output_keywords = \" AND \".join(output_keywords)\n", + " # except Exception as e:\n", + " # pass\n", + "\n", + "\n", + "\n", + " history = [tuple(x) for x in history]\n", + " yield history,docs_html,output_query,output_language,gallery,updates#,output_query,output_keywords\n", + "\n", + "\n", + " except Exception as e:\n", + " raise gr.Error(f\"{e}\")\n", + "\n", + "\n", + " try:\n", + " # Log answer on Azure Blob Storage\n", + " if os.getenv(\"GRADIO_ENV\") != \"local\":\n", + " timestamp = str(datetime.now().timestamp())\n", + " file = timestamp + \".json\"\n", + " prompt = history[-1][0]\n", + " logs = {\n", + " \"user_id\": str(user_id),\n", + " \"prompt\": prompt,\n", + " \"query\": prompt,\n", + " \"question\":output_query,\n", + " \"sources\":sources,\n", + " \"docs\":serialize_docs(docs),\n", + " \"answer\": history[-1][1],\n", + " \"time\": timestamp,\n", + " }\n", + " log_on_azure(file, logs, share_client)\n", + " except Exception as e:\n", + " print(f\"Error logging on Azure Blob Storage: {e}\")\n", + " raise gr.Error(f\"ClimateQ&A Error: {str(e)[:100]} - The error has been noted, try another question and if the error remains, you can contact us :)\")\n", + "\n", + " image_dict = {}\n", + " for i,doc in enumerate(docs):\n", + " \n", + " if doc.metadata[\"chunk_type\"] == \"image\":\n", + " try:\n", + " key = f\"Image {i+1}\"\n", + " image_path = doc.metadata[\"image_path\"].split(\"documents/\")[1]\n", + " img = get_image_from_azure_blob_storage(image_path)\n", + "\n", + " # Convert the image to a byte buffer\n", + " buffered = BytesIO()\n", + " img.save(buffered, format=\"PNG\")\n", + " img_str = base64.b64encode(buffered.getvalue()).decode()\n", + "\n", + " # Embedding the base64 string in Markdown\n", + " markdown_image = f\"![Alt text](data:image/png;base64,{img_str})\"\n", + " image_dict[key] = {\"img\":img,\"md\":markdown_image,\"caption\":doc.page_content,\"key\":key,\"figure_code\":doc.metadata[\"figure_code\"]}\n", + " except Exception as e:\n", + " print(f\"Skipped adding image {i} because of {e}\")\n", + "\n", + " if len(image_dict) > 0:\n", + "\n", + " gallery = [x[\"img\"] for x in list(image_dict.values())]\n", + " img = list(image_dict.values())[0]\n", + " img_md = img[\"md\"]\n", + " img_caption = img[\"caption\"]\n", + " img_code = img[\"figure_code\"]\n", + " if img_code != \"N/A\":\n", + " img_name = f\"{img['key']} - {img['figure_code']}\"\n", + " else:\n", + " img_name = f\"{img['key']}\"\n", + "\n", + " answer_yet = history[-1][1] + f\"\\n\\n{img_md}\\n

{img_name} - {img_caption}

\"\n", + " history[-1] = (history[-1][0],answer_yet)\n", + " history = [tuple(x) for x in history]\n", + "\n", + " print(f\"\\n\\nImages:\\n{gallery}\")\n", + "\n", + " # gallery = [x.metadata[\"image_path\"] for x in docs if (len(x.metadata[\"image_path\"]) > 0 and \"IAS\" in x.metadata[\"image_path\"])]\n", + " # if len(gallery) > 0:\n", + " # gallery = list(set(\"|\".join(gallery).split(\"|\")))\n", + " # gallery = [get_image_from_azure_blob_storage(x) for x in gallery]\n", + "\n", + " yield history,docs_html,output_query,output_language,gallery,updates#,output_query,output_keywords\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "climateqa", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}