From bbcd02f4480035c81e3f2c364602dbca87337f88 Mon Sep 17 00:00:00 2001 From: wwwttt001 Date: Wed, 9 Jul 2025 09:31:10 +0800 Subject: [PATCH 1/4] ragsdk --- RAGSDK/MainRepo/Dockerfile/ubuntu/Dockerfile | 173 +++++ RAGSDK/MainRepo/Dockerfile/ubuntu/urls.conf | 5 + RAGSDK/MainRepo/README.md | 37 + RAGSDK/MainRepo/Samples/RagDemo/README.md | 50 ++ .../fastapi_multi_demo/fastapi_multithread.py | 142 ++++ .../fastapi_multi_demo/fastapi_request.py | 66 ++ .../RagDemo/langchain_chains/README.md | 9 + .../langchain_chains/llm_chain_stream.py | 133 ++++ .../Samples/RagDemo/rag_demo_cache_qa.py | 163 +++++ .../Samples/RagDemo/rag_demo_knowledge.py | 120 +++ .../Samples/RagDemo/rag_demo_query.py | 143 ++++ RAGSDK/MainRepo/langgraph/README.md | 609 ++++++++++++++++ RAGSDK/MainRepo/langgraph/image-1.png | Bin 0 -> 14517 bytes RAGSDK/MainRepo/langgraph/image.png | Bin 0 -> 94690 bytes RAGSDK/MainRepo/langgraph/image_new.png | Bin 0 -> 128266 bytes RAGSDK/MainRepo/langgraph/langgraph_demo.py | 498 +++++++++++++ RAGSDK/MainRepo/langgraph/requirements.txt | 2 + RAGSDK/MainRepo/sd_samples/README.md | 151 ++++ ...able_diffusion_pipeline_parallel_web.patch | 277 +++++++ .../stable_diffusion_pipeline_web.patch | 279 +++++++ RAGSDK/PocValidation/README.md | 8 + RAGSDK/PocValidation/chat_with_ascend/app.py | 682 ++++++++++++++++++ .../chat_with_ascend/images/demo.png | Bin 0 -> 75898 bytes .../PocValidation/chat_with_ascend/readme.md | 46 ++ .../code_with_ascend/.eslintrc.json | 33 + .../code_with_ascend/.vscode/extensions.json | 8 + .../code_with_ascend/.vscode/launch.json | 21 + .../code_with_ascend/.vscode/settings.json | 13 + .../code_with_ascend/.vscode/tasks.json | 20 + .../code_with_ascend/.vscodeignore | 11 + .../PocValidation/code_with_ascend/README.md | 63 ++ .../code_with_ascend/images/logo.png | Bin 0 -> 6625 bytes .../code_with_ascend/package.json | 139 ++++ .../src/autocomplete/autoCompletion.ts | 177 +++++ .../src/autocomplete/charStream.ts | 39 + .../src/autocomplete/completionProvider.ts | 123 ++++ .../code_with_ascend/src/autocomplete/ide.ts | 72 ++ .../src/autocomplete/index.ts | 57 ++ .../src/autocomplete/languages.ts | 252 +++++++ .../src/autocomplete/lineStream.ts | 100 +++ .../src/autocomplete/templates.ts | 103 +++ .../code_with_ascend/src/autocomplete/util.ts | 34 + .../code_with_ascend/src/commands.ts | 130 ++++ .../code_with_ascend/src/extension.ts | 24 + .../code_with_ascend/src/llm/httpClient.ts | 115 +++ .../code_with_ascend/src/llm/index.ts | 176 +++++ .../src/sidebar/chatWebview.ts | 49 ++ .../src/sidebar/htmlWebview.ts | 128 ++++ .../src/sidebar/htmlcode.html | 133 ++++ .../code_with_ascend/src/util/prompt.ts | 22 + .../code_with_ascend/src/util/templete.ts | 46 ++ .../code_with_ascend/src/util/util.ts | 78 ++ .../code_with_ascend/tsconfig.json | 20 + .../embedding_finetune/README.md | 305 ++++++++ .../embedding_finetune/finetune.py | 232 ++++++ .../PocValidation/rag_recursive_tree_demo.py | 102 +++ RAGSDK/README.md | 7 + README.md | 6 +- README.zh.md | 6 +- 59 files changed, 6431 insertions(+), 6 deletions(-) create mode 100644 RAGSDK/MainRepo/Dockerfile/ubuntu/Dockerfile create mode 100644 RAGSDK/MainRepo/Dockerfile/ubuntu/urls.conf create mode 100644 RAGSDK/MainRepo/README.md create mode 100644 RAGSDK/MainRepo/Samples/RagDemo/README.md create mode 100644 RAGSDK/MainRepo/Samples/RagDemo/fastapi_multi_demo/fastapi_multithread.py create mode 100644 RAGSDK/MainRepo/Samples/RagDemo/fastapi_multi_demo/fastapi_request.py create mode 100644 RAGSDK/MainRepo/Samples/RagDemo/langchain_chains/README.md create mode 100644 RAGSDK/MainRepo/Samples/RagDemo/langchain_chains/llm_chain_stream.py create mode 100644 RAGSDK/MainRepo/Samples/RagDemo/rag_demo_cache_qa.py create mode 100644 RAGSDK/MainRepo/Samples/RagDemo/rag_demo_knowledge.py create mode 100644 RAGSDK/MainRepo/Samples/RagDemo/rag_demo_query.py create mode 100644 RAGSDK/MainRepo/langgraph/README.md create mode 100644 RAGSDK/MainRepo/langgraph/image-1.png create mode 100644 RAGSDK/MainRepo/langgraph/image.png create mode 100644 RAGSDK/MainRepo/langgraph/image_new.png create mode 100644 RAGSDK/MainRepo/langgraph/langgraph_demo.py create mode 100644 RAGSDK/MainRepo/langgraph/requirements.txt create mode 100644 RAGSDK/MainRepo/sd_samples/README.md create mode 100644 RAGSDK/MainRepo/sd_samples/stable_diffusion_pipeline_parallel_web.patch create mode 100644 RAGSDK/MainRepo/sd_samples/stable_diffusion_pipeline_web.patch create mode 100644 RAGSDK/PocValidation/README.md create mode 100644 RAGSDK/PocValidation/chat_with_ascend/app.py create mode 100644 RAGSDK/PocValidation/chat_with_ascend/images/demo.png create mode 100644 RAGSDK/PocValidation/chat_with_ascend/readme.md create mode 100644 RAGSDK/PocValidation/code_with_ascend/.eslintrc.json create mode 100644 RAGSDK/PocValidation/code_with_ascend/.vscode/extensions.json create mode 100644 RAGSDK/PocValidation/code_with_ascend/.vscode/launch.json create mode 100644 RAGSDK/PocValidation/code_with_ascend/.vscode/settings.json create mode 100644 RAGSDK/PocValidation/code_with_ascend/.vscode/tasks.json create mode 100644 RAGSDK/PocValidation/code_with_ascend/.vscodeignore create mode 100644 RAGSDK/PocValidation/code_with_ascend/README.md create mode 100644 RAGSDK/PocValidation/code_with_ascend/images/logo.png create mode 100644 RAGSDK/PocValidation/code_with_ascend/package.json create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/autocomplete/autoCompletion.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/autocomplete/charStream.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/autocomplete/completionProvider.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/autocomplete/ide.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/autocomplete/index.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/autocomplete/languages.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/autocomplete/lineStream.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/autocomplete/templates.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/autocomplete/util.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/commands.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/extension.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/llm/httpClient.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/llm/index.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/sidebar/chatWebview.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/sidebar/htmlWebview.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/sidebar/htmlcode.html create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/util/prompt.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/util/templete.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/src/util/util.ts create mode 100644 RAGSDK/PocValidation/code_with_ascend/tsconfig.json create mode 100644 RAGSDK/PocValidation/embedding_finetune/README.md create mode 100644 RAGSDK/PocValidation/embedding_finetune/finetune.py create mode 100644 RAGSDK/PocValidation/rag_recursive_tree_demo.py create mode 100644 RAGSDK/README.md diff --git a/RAGSDK/MainRepo/Dockerfile/ubuntu/Dockerfile b/RAGSDK/MainRepo/Dockerfile/ubuntu/Dockerfile new file mode 100644 index 000000000..a495a2c39 --- /dev/null +++ b/RAGSDK/MainRepo/Dockerfile/ubuntu/Dockerfile @@ -0,0 +1,173 @@ +FROM ubuntu:20.04 + +WORKDIR /tmp + +ARG ARCH=aarch64 +ARG PYTHON_VERSION=python3.11 +ARG TORCH_VERSION=2.1.0 +# 设置时区禁用交互式配置 +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install -y software-properties-common && add-apt-repository -y ppa:deadsnakes/ppa && apt-get update +RUN apt-get update && apt-get install -y vim tar zip unzip git curl wget dos2unix make gcc g++ ccache gfortran libssl-dev libpq-dev swig ffmpeg + +RUN apt-get update && apt-get install -y build-essential ${PYTHON_VERSION} ${PYTHON_VERSION}-dev ${PYTHON_VERSION}-distutils ${PYTHON_VERSION}-venv +COPY ./package/urls.conf /tmp/urls.conf +RUN . /tmp/urls.conf && curl -k $PYPI_URL | ${PYTHON_VERSION} && update-alternatives --install /usr/bin/python3 python3 /usr/bin/${PYTHON_VERSION} 1 + +#配置 python3-config +RUN ln -sf /usr/bin/${PYTHON_VERSION}-config /usr/local/bin/python3-config + +# 安装cmake +RUN . /tmp/urls.conf && wget $CMAKE_URL && \ + tar -zxf cmake-3.24.3.tar.gz && \ + cd cmake-3.24.3 && \ + ./bootstrap && make -j && make install + +# 请根据在服务器上执行npu-smi info 命令进行查询,将查询到的"Name"字段最后一位数字删除后值修改PLATFORM字段 +ARG PLATFORM=310P + +#解决blinker无法卸载的问题 +RUN apt-get remove -y python3-blinker && apt-get autoremove -y + +# 安装cann 依赖 +RUN pip3 install --upgrade setuptools && pip3 install numpy==1.26.4 decorator==5.1.1 sympy==1.12 cffi==1.16.0 pyyaml==6.0.1 pathlib2==2.3.7.post1 protobuf==5.26.0 scipy==1.12.0 requests==2.31.0 psutil==5.9.8 absl-py==2.1.0 attrs==23.2.0 + +# 安装torch for x86 +# RUN pip3 install torch=="${TORCH_VERSION}" --index-url https://download.pytorch.org/whl/cpu +# 安装torch-npu +# RUN pip3 install torch-npu=="${TORCH_VERSION}".post3 + +# 安装cann-toolkit和kernel +COPY ./package/Ascend-cann*_linux-${ARCH}.run /tmp/ +RUN useradd -d /home/HwHiAiUser -u 1000 -m -s /bin/bash HwHiAiUser +RUN bash /tmp/Ascend-cann-toolkit*_linux-${ARCH}.run --install --install-for-all --quiet +RUN bash /tmp/Ascend-cann-kernels*_linux-${ARCH}.run --install --install-for-all --quiet +#安装 nnal +RUN bash -c "source /usr/local/Ascend/ascend-toolkit/set_env.sh && bash /tmp/Ascend-cann-nnal*_linux-${ARCH}.run --install --quiet" + +ENV ASCEND_HOME_PATH=/usr/local/Ascend/ascend-toolkit/latest +ENV TOOLCHAIN_HOME=/usr/local/Ascend/ascend-toolkit/latest/toolkit +ENV ASCEND_TOOLKIT_HOME=/usr/local/Ascend/ascend-toolkit/latest +ENV ASCEND_OPP_PATH=/usr/local/Ascend/ascend-toolkit/latest/opp +ENV ASCEND_AICPU_PATH=/usr/local/Ascend/ascend-toolkit/latest +ENV LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64:/usr/local/Ascend/driver/lib64/common:/usr/local/Ascend/driver/lib64/driver:$LD_LIBRARY_PATH + +RUN pip3 install build wheel + + +# 安装openblas +ARG OPENBLAS_INSTALL_PATH=/usr/local/Ascend/OpenBLAS +RUN . /tmp/urls.conf && cd /tmp && \ + git clone $OPENBLAS_URL && \ + cd OpenBLAS && \ + git checkout v0.3.10 && \ + make FC=gfortran USE_OPENMP=1 -j && \ + make PREFIX=${OPENBLAS_INSTALL_PATH} install +ENV LD_LIBRARY_PATH=${OPENBLAS_INSTALL_PATH}/lib:$LD_LIBRARY_PATH + + +# 安装faiss +ARG FAISS_INSTALL_PATH=/usr/local/faiss/faiss1.7.4 +RUN . /tmp/urls.conf && wget $FAISS_URL && \ + tar -xf v1.7.4.tar.gz && \ + cd faiss-1.7.4/faiss && \ + sed -i "131 i virtual void search_with_filter (idx_t n, const float *x, idx_t k, float *distances, idx_t *lables, const void *mask = nullptr) const{}" Index.h && \ + sed -i "38 i template IndexIDMapTemplate::IndexIDMapTemplate (IndexT *index, std::vector &ids): index (index), own_fields (false) { this->is_trained = index->is_trained; this->metric_type = index->metric_type; this->verbose = index->verbose; this->d = index->d; id_map = ids; }" IndexIDMap.cpp && \ + sed -i "29 i explicit IndexIDMapTemplate (IndexT *index, std::vector &ids);" IndexIDMap.h && \ + sed -i "199 i utils/sorting.h" CMakeLists.txt && \ + cd .. && cmake -B build . -DFAISS_ENABLE_GPU=OFF -DPython_EXECUTABLE=/usr/bin/python3 -DBUILD_TESTING=OFF -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${FAISS_INSTALL_PATH} && \ + make -C build -j faiss && \ + make -C build -j swigfaiss && \ + cd build/faiss/python && python3 setup.py bdist_wheel && \ + cd ../../.. && make -C build install && \ + cd build/faiss/python && cp libfaiss_python_callbacks.so ${FAISS_INSTALL_PATH}/lib && \ + cd dist && \ + pip3 install faiss-1.7.4*.whl + +# 安装index +COPY ./package/Ascend-mindxsdk-mxindex*_linux-${ARCH}.run /tmp/ +RUN bash /tmp/Ascend-mindxsdk-mxindex*_linux-${ARCH}.run --quiet --install --install-path=/usr/local/Ascend --platform=${PLATFORM} +ENV MX_INDEX_MODELPATH=/home/ascend/modelpath +RUN cd /usr/local/Ascend/mxIndex/ops && ./custom_opp_${ARCH}.run && mkdir -p /home/ascend/modelpath + +# 安装ascendfaiss,到这里了 +ARG FAISS_INSTALL_PATH=/usr/local/faiss/faiss1.7.4 +ARG MXINDEX_INSTALL_PATH=/usr/local/Ascend/mxIndex +ARG PYTHON_HEADER=/usr/include/${PYTHON_VERSION}/ +ARG ASCEND_INSTALL_PATH=/usr/local/Ascend/ascend-toolkit/latest +ARG DRIVER_INSTALL_PATH=/usr/local/Ascend + +COPY ./package/driver /usr/local/Ascend/driver +RUN . /tmp/urls.conf && wget $ASCENDFAISS_URL + + +RUN unzip master.zip && \ + cd mindsdk-referenceapps-master/IndexSDK/faiss-python && \ + swig -python -c++ -Doverride= -module swig_ascendfaiss -I${PYTHON_HEADER} -I${FAISS_INSTALL_PATH}/include -I${MXINDEX_INSTALL_PATH}/include -DSWIGWORDSIZE64 -o swig_ascendfaiss.cpp swig_ascendfaiss.swig && \ + g++ -std=c++11 -DFINTEGER=int -fopenmp -I/usr/local/include -I${ASCEND_INSTALL_PATH}/acllib/include -I${ASCEND_INSTALL_PATH}/runtime/include -I${DRIVER_INSTALL_PATH}/driver/kernel/inc/driver -I${DRIVER_INSTALL_PATH}/driver/kernel/libc_sec/include -fPIC -fstack-protector-all -Wall -Wreturn-type -D_FORTIFY_SOURCE=2 -g -O3 -Wall -Wextra -I${PYTHON_HEADER} -I/usr/local/lib/${PYTHON_VERSION}/dist-packages/numpy/core/include -I${FAISS_INSTALL_PATH}/include -I${MXINDEX_INSTALL_PATH}/include -c swig_ascendfaiss.cpp -o swig_ascendfaiss.o && \ + g++ -std=c++11 -shared -fopenmp -L${ASCEND_INSTALL_PATH}/lib64 -L${ASCEND_INSTALL_PATH}/acllib/lib64 -L${ASCEND_INSTALL_PATH}/runtime/lib64 -L${DRIVER_INSTALL_PATH}/driver/lib64 -L${DRIVER_INSTALL_PATH}/driver/lib64/common -L${DRIVER_INSTALL_PATH}/driver/lib64/driver -L${FAISS_INSTALL_PATH}/lib -L${MXINDEX_INSTALL_PATH}/lib -Wl,-rpath-link=${ASCEND_INSTALL_PATH}/acllib/lib64:${ASCEND_INSTALL_PATH}/runtime/lib64:${DRIVER_INSTALL_PATH}/driver/lib64:${DRIVER_INSTALL_PATH}/driver/lib64/common:${DRIVER_INSTALL_PATH}/driver/lib64/driver -L/usr/local/lib -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -s -o _swig_ascendfaiss.so swig_ascendfaiss.o -L.. -lascendfaiss -lfaiss -lascend_hal -lacl_retr -lascendcl -lc_sec -lacl_op_compiler && \ + ${PYTHON_VERSION} -m build && \ + cd dist && pip3 install ascendfaiss*.whl + + +#ENV LD_LIBRARY_PATH=/usr/local/Ascend/mxIndex/lib:/usr/local/faiss/faiss1.7.4/lib:$LD_LIBRARY_PATH + + +# 安装toch_npu +#RUN pip3 install torch-${TORCH_VERSION}*_${ARCH}.whl && pip3 install torch_npu-${TORCH_VERSION}*_${ARCH}.whl +RUN pip3 install torch-npu=="${TORCH_VERSION}".post8 + +# 安装mxrag +COPY ./package/Ascend-mindxsdk-mxrag_*_linux-${ARCH}.run /tmp/ +RUN bash /tmp/Ascend-mindxsdk-mxrag_*_linux-${ARCH}.run --install --install-path=/usr/local/Ascend --quiet --platform=${PLATFORM} +RUN pip3 install -r /usr/local/Ascend/mxRag/requirements.txt + +# 安装mxrag第三方依赖 +RUN pip3 install ragas==0.1.9 rank_bm25==0.2.2 readability_lxml==0.8.1 html_text==0.6.2 gradio==3.50.2 +#清理临时目录 +RUN rm -rf ./* && rm -rf /usr/local/Ascend/driver + +# 添加环境变量 +RUN sed -i '$a\export PYTHONPATH=/root/.local/lib/$PYTHON_VERSION/site-packages/mx_rag/libs/:$PYTHONPATH' /root/.bashrc && \ + sed -i '$a\export LD_PRELOAD=$(ls /usr/local/lib/$PYTHON_VERSION/dist-packages/scikit_learn.libs/libgomp-*):$LD_PRELOAD' /root/.bashrc && \ + sed -i '$a\source /usr/local/Ascend/ascend-toolkit/set_env.sh' /root/.bashrc && \ + sed -i '$a\source /usr/local/Ascend/nnal/atb/set_env.sh' /root/.bashrc && \ + sed -i '$a\source /usr/local/Ascend/mxRag/script/set_env.sh' /root/.bashrc && \ + sed -i '$a\export LD_LIBRARY_PATH=/usr/local/Ascend/mxIndex/lib:/usr/local/faiss/faiss1.7.4/lib:$LD_LIBRARY_PATH' /root/.bashrc && \ + sed -i '$a\export PATH=/usr/local/bin:$PATH' /root/.bashrc && \ + sed -i 's/$PYTHON_VERSION/'"$PYTHON_VERSION"'/g' /root/.bashrc && \ + sed -i '$a\export LOGURU_FORMAT="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message!r}"' /root/.bashrc + + +USER HwHiAiUser:HwHiAiUser + +# 安装index for HwHiAiUser +COPY ./package/Ascend-mindxsdk-mxindex*_linux-${ARCH}.run /tmp/ +RUN bash /tmp/Ascend-mindxsdk-mxindex*_linux-${ARCH}.run --quiet --install --install-path=/home/HwHiAiUser/Ascend --platform=${PLATFORM} + +# 安装mxrag for HwHiAiUser +COPY ./package/Ascend-mindxsdk-mxrag_*_linux-${ARCH}.run /tmp/ +RUN bash /tmp/Ascend-mindxsdk-mxrag_*_linux-${ARCH}.run --install --install-path=/home/HwHiAiUser/Ascend --quiet --platform=${PLATFORM} + +# 添加环境变量 for HwHiAiUser用户 +RUN sed -i '$a\export PYTHONPATH=/home/HwHiAiUser/.local/lib/$PYTHON_VERSION/site-packages/mx_rag/libs/:$PYTHONPATH' /home/HwHiAiUser/.bashrc && \ + sed -i '$a\export LD_PRELOAD=$(ls /usr/local/lib/$PYTHON_VERSION/dist-packages/scikit_learn.libs/libgomp-*):$LD_PRELOAD' /home/HwHiAiUser/.bashrc && \ + sed -i '$a\source /usr/local/Ascend/ascend-toolkit/set_env.sh' /home/HwHiAiUser/.bashrc && \ + sed -i '$a\source /usr/local/Ascend/nnal/atb/set_env.sh' /home/HwHiAiUser/.bashrc && \ + sed -i '$a\source /home/HwHiAiUser/Ascend/mxRag/script/set_env.sh' /home/HwHiAiUser/.bashrc && \ + sed -i '$a\export LD_LIBRARY_PATH=/home/HwHiAiUser/Ascend/mxIndex/lib:/usr/local/faiss/faiss1.7.4/lib:$LD_LIBRARY_PATH' /home/HwHiAiUser/.bashrc && \ + sed -i '$a\export PATH=/usr/local/bin:$PATH' /home/HwHiAiUser/.bashrc && \ + sed -i 's/$PYTHON_VERSION/'"$PYTHON_VERSION"'/g' /home/HwHiAiUser/.bashrc && \ + sed -i '$a\export LOGURU_FORMAT="{time:YYYY-MM-DD HH:mm:ss.SSS} | {level: <8} | {name}:{function}:{line} - {message!r}"' /home/HwHiAiUser/.bashrc + +ENV MX_INDEX_MULTITHREAD=1 +ENV MX_INDEX_FINALIZE=0 + +USER root +RUN chmod +r /usr/local/Ascend/ascend-toolkit/latest/opp/vendors/config.ini +RUN rm -rf /tmp/* +USER HwHiAiUser:HwHiAiUser + +WORKDIR /home/HwHiAiUser + diff --git a/RAGSDK/MainRepo/Dockerfile/ubuntu/urls.conf b/RAGSDK/MainRepo/Dockerfile/ubuntu/urls.conf new file mode 100644 index 000000000..ba90bb23b --- /dev/null +++ b/RAGSDK/MainRepo/Dockerfile/ubuntu/urls.conf @@ -0,0 +1,5 @@ +PYPI_URL=https://bootstrap.pypa.io/get-pip.py +CMAKE_URL=https://cmake.org/files/v3.24/cmake-3.24.3.tar.gz +OPENBLAS_URL=https://github.com/OpenMathLib/OpenBLAS.git +FAISS_URL=https://github.com/facebookresearch/faiss/archive/v1.7.4.tar.gz +ASCENDFAISS_URL=https://gitee.com/ascend/mindsdk-referenceapps/repository/archive/master.zip diff --git a/RAGSDK/MainRepo/README.md b/RAGSDK/MainRepo/README.md new file mode 100644 index 000000000..25103285a --- /dev/null +++ b/RAGSDK/MainRepo/README.md @@ -0,0 +1,37 @@ +# RAG SDK + +RAG SDK是昇腾面向大语言模型的知识增强开发套件,为解决大模型知识更新缓慢以及垂直领域知识问答弱的问题,面向大模型知识库提供垂域调优、生成增强、知识管理等特性,帮助用户搭建专属的高性能、准确度高的大模型问答系统。 + +## 版本配套说明 + +本版本配套RAG SDK 7.1.RC1版本使用,依赖的其他配套软件版本为: + +| 软件包简称 | 配套版本 | +|-----------------------|---------| +| CANN软件包 | 8.2.RC1 | +| 二进制算子包Kernels | 8.2.RC1 | +| npu-drive驱动包 | 25.2.0 | +| npu-firmware固件包 | 25.2.0 | +| Index SDK检索软件包 | 7.1.RC1 | +| MindIE推理引擎软件包 | 2.0.RC2 | +| Ascend Docker Runtime | 7.0.RC1 | + +## 支持的硬件和运行环境 + +| 产品系列 | 产品型号 | +|-------------------|---------------------| +| Atlas 推理系列产品 | Atlas 300I Duo 推理卡 | +| Atlas 800I A2推理产品 | Atlas 800I A2 推理服务器 | + +支持的软件运行环境为:Ubuntu 22.04,Python3.11 + +## 目录结构与说明 + +| 目录 | 说明 | +|------------|--------------------------------------------------------------| +| Dockerfile | 部署RAG SDK容器,用户若自行准备镜像文件的参考样例,对应用户手册《安装RAG SDK》章节。 | +| Samples | RAG SDK完整开发流程的开发参考样例,包含"创建知识库"、"在线问答"、"MxRAGCache缓存和自动生成QA"。 | +| langgraph | Agentic RAG样例。 | +| patches | RAG SDK补丁安装文件,包括支持融合算子、支持TEI、支持whisper模型。 | +| sd_samples | 安装并运行stable_diffusion模型参考样例。 | + diff --git a/RAGSDK/MainRepo/Samples/RagDemo/README.md b/RAGSDK/MainRepo/Samples/RagDemo/README.md new file mode 100644 index 000000000..fb57eded4 --- /dev/null +++ b/RAGSDK/MainRepo/Samples/RagDemo/README.md @@ -0,0 +1,50 @@ +# RAG SDK Demo运行说明 + +## 前提条件 + +执行Demo前请先阅读《RAG SDK 用户指南》,并按照其中"安装部署"章节的要求完成必要软、硬件安装。 +本章节为"应用开发"章节提供开发样例代码,便于开发者快速开发。 + +## 样例说明 + +详细的样例介绍请参考《RAG SDK 用户指南》"应用开发"章节说明。 其中: + +1.rag_demo_knowledge.py为"创建知识库"样例代码; rag_demo_query为"在线问答"样例代码。 + +2."创建知识库"样例和"在线问答" +样例是以FLATL2检索方式为例,当参数tei_emb为False时表示本地启动embedding模型,需传入参数embedding_path,当参数tei_emb为True时,表示启动服务化模型,需传入参数embedding_url;reranker同理,其中reranker为可选过程,默认不使用。 + +3.rag_demo_cache_qa.py对应"MxRAGCache缓存和自动生成QA"样例。 + +4.fastapi_demo目录下为fastapi多线程并发调用在线问答的样例。 + +5.langchain_chains目录下为使用langchain llm chain支持双向认证样例。 + +注意: +1.创建知识库过程和在线问答过程使用的embedding模型、关系数据库路径、向量数据库路径需对应保持一致。其中关系数据库和向量数据库路径在样例代码中已经默认设置成一致,embedding模型需用户手动设置成一致。 + +## 运行及参数说明 + +1.调用示例 + +```commandline +# 上传知识库,支持多线程上传 +python3 rag_demo_knowledge.py --file_path "/home/data/MindIE.docx" --file_path "/home/data/gaokao.docx" + +# 在线问答,支持多线程问答 +python3 rag_demo_query.py --query "请描述2024年高考作为题目" --query "请问2025年一共有多少天法定节假日" + +# fastapi多线程并发调用,需要安装fastapi和uvicorn +python3 fastapi_multithread.py --llm_url http://x.x.x.x:port/v1/chat/completions 为启动fastapi服务端在线问答,python3 fastapi_request.py为客户端多线程并发请求在线问答的样例,若想单次请求也可以使用curl指令,请求示例如下: +curl -X 'POST' 'http://127.0.0.1:8000/query/' -H 'Content-Type: application/json' -d '{"question": "介绍一下2024年高考题目"}' +``` + +说明: +调用示例前请先根据用户实际情况完成参数配置,确保embedding模型路径正确,大模型能正常访问,文件路径正确等,参数可以通过修改样例代码,也可通过命令行的方式传入,运行fastapi_multithread.py时需要安装fastapi和uvicorn包。 + +2.参数说明 + +```commandline +以"创建知识库"为例,用户可以通过以下命令查看参数情况;如需开发其他样例,请详细参考《RAG SDK用户指南》"接口参考"章节。 +python3 rag_demo_knowledge.py --help +``` \ No newline at end of file diff --git a/RAGSDK/MainRepo/Samples/RagDemo/fastapi_multi_demo/fastapi_multithread.py b/RAGSDK/MainRepo/Samples/RagDemo/fastapi_multi_demo/fastapi_multithread.py new file mode 100644 index 000000000..4025ac306 --- /dev/null +++ b/RAGSDK/MainRepo/Samples/RagDemo/fastapi_multi_demo/fastapi_multithread.py @@ -0,0 +1,142 @@ +import argparse +import os +import threading +from concurrent.futures import ThreadPoolExecutor +from typing import Optional +from pathlib import Path +from fastapi import FastAPI, HTTPException +from langchain.text_splitter import RecursiveCharacterTextSplitter +from mx_rag.chain import SingleText2TextChain +from mx_rag.document import LoaderMng +from mx_rag.document.loader import DocxLoader +from mx_rag.embedding.local import TextEmbedding +from mx_rag.embedding.service import TEIEmbedding +from mx_rag.knowledge import KnowledgeDB +from mx_rag.knowledge.handler import upload_files +from mx_rag.knowledge.knowledge import KnowledgeStore +from mx_rag.llm import Text2TextLLM +from mx_rag.reranker.local import LocalReranker +from mx_rag.reranker.service import TEIReranker +from mx_rag.retrievers import Retriever +from mx_rag.storage.document_store import SQLiteDocstore +from mx_rag.storage.vectorstore import MindFAISS +from mx_rag.utils import ClientParam +from paddle.base import libpaddle + + + + +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter): + def _get_default_metavar_for_optional(self, action): + return action.type.__name__ + + def _get_default_metavar_for_positional(self, action): + return action.type.__name__ + + +text_retriever = any +llm = any +reranker = any + + +def rag_init(): + parse = argparse.ArgumentParser(formatter_class=CustomFormatter) + parse.add_argument("--embedding_path", type=str, default="/home/mxaiagent/data/acge_text_embedding", + help="embedding模型本地路径") + parse.add_argument("--embedding_url", type=str, default="http://127.0.0.1:8080/embed", + help="使用TEI服务化的embedding模型url地址") + parse.add_argument("--tei_emb", type=bool, default=False, help="是否使用TEI服务化的embedding模型") + parse.add_argument("--llm_url", type=str, default="http://127.0.0.1:1025/v1/chat/completions", help="大模型url地址") + parse.add_argument("--model_name", type=str, default="Llama3-8B-Chinese-Chat", help="大模型名称") + parse.add_argument("--score_threshold", type=float, default=0.5, + help="相似性得分的阈值,大于阈值认为检索的信息与问题越相关,取值范围[0,1]") + parse.add_argument("--reranker_path", type=str, + default="/home/mxaiagent/data/bge-reranker-v2-m3", help="reranker模型本地路径") + parse.add_argument("--reranker_url", type=str, default="http://127.0.0.1:8080/rerank", + help="使用TEI服务化的embedding模型url地址") + parse.add_argument("--tei_reranker", type=bool, default=False, help="是否使用TEI服务化的reranker模型") + parse.add_argument("--white_path", type=str, nargs='+', default=["/home"], help="文件白名单路径") + parse.add_argument("--up_files", type=str, nargs='+', default=None, help="要上传的文件路径,需在白名单路径下") + parse.add_argument("--sql_path", type=str, nargs='+', default="./sql.db", help="关系数据库文件保存路径") + parse.add_argument("--vector_path", type=str, nargs='+', default="./faiss.index", help="向量数据库文件保存路径") + parse.add_argument("--question", type=str, default="描述一下地球的内部结构", help="用户问题") + args = parse.parse_args().__dict__ + embedding_path: str = args.pop('embedding_path') + embedding_url: str = args.pop('embedding_url') + tei_emb: bool = args.pop('tei_emb') + llm_url: str = args.pop('llm_url') + model_name: str = args.pop('model_name') + score_threshold: int = args.pop('score_threshold') + reranker_path: str = args.pop('reranker_path') + reranker_url: str = args.pop('reranker_url') + tei_reranker: bool = args.pop('tei_reranker') + white_path: str = args.pop('white_path') + up_files: list[str] = args.pop('up_files') + sql_path: str = args.pop('sql_path') + vector_path: str = args.pop('vector_path') + question: str = args.pop('question') + + dev = 0 + if tei_emb: + emb = TEIEmbedding(url=embedding_url, client_param=ClientParam(use_http=True)) + else: + emb = TextEmbedding(model_path=embedding_path, dev_id=dev) + chunk_store = SQLiteDocstore(db_path=sql_path) + vector_store = MindFAISS(1024, [dev], load_local_index=vector_path) + global text_retriever + text_retriever = Retriever(vector_store=vector_store, document_store=chunk_store, + embed_func=emb.embed_documents, k=1, score_threshold=score_threshold) + + # 创建知识管理 + knowledge_store = KnowledgeStore(db_path=sql_path) + knowledge_store.add_knowledge("test", "Default01", "admin") + knowledge_db = KnowledgeDB(knowledge_store=knowledge_store, chunk_store=chunk_store, vector_store=vector_store, + knowledge_name="test", white_paths=white_path, user_id="Default01") + + # 上传文档到知识库 + if up_files: + loader_mng = LoaderMng() + loader_mng.register_loader(DocxLoader, [".docx"]) + loader_mng.register_splitter(RecursiveCharacterTextSplitter, [".xlsx", ".docx", ".pdf"], + {"chunk_size": 750, "chunk_overlap": 150, "keep_separator": False}) + upload_files(knowledge_db, up_files, loader_mng=loader_mng, embed_func=emb.embed_documents, force=True) + # 上传文档结束 + + global reranker + if tei_reranker: + reranker = TEIReranker(url=reranker_url, client_param=ClientParam(use_http=True)) + else: + reranker = LocalReranker(reranker_path, dev_id=dev) + global llm + llm = Text2TextLLM(base_url=llm_url, model_name=model_name, client_param=ClientParam(use_http=True)) + + +app = FastAPI() + + +def fun(input_string: str) -> str: + text2text_chain = SingleText2TextChain(retriever=text_retriever, llm=llm, reranker=reranker) + res = text2text_chain.query(input_string) + return f"{res}" + + +# 创建一个线程池执行器 +thread_pool_executor = ThreadPoolExecutor(max_workers=10) + + +@app.post("/query/") +async def call_fun(items: dict): + # 使用线程池异步调用 fun 函数 + future = thread_pool_executor.submit(fun, items['question']) + try: + result = future.result() + return {"result": result} + except Exception as e: + raise HTTPException(status_code=500) from e + + +if __name__ == "__main__": + rag_init() + import uvicorn + + uvicorn.run(app, host="127.0.0.1", port=8000) diff --git a/RAGSDK/MainRepo/Samples/RagDemo/fastapi_multi_demo/fastapi_request.py b/RAGSDK/MainRepo/Samples/RagDemo/fastapi_multi_demo/fastapi_request.py new file mode 100644 index 000000000..c6069237b --- /dev/null +++ b/RAGSDK/MainRepo/Samples/RagDemo/fastapi_multi_demo/fastapi_request.py @@ -0,0 +1,66 @@ +import json +import logging +import random +import threading + +import requests + +logging.basicConfig(level=logging.INFO) +SERVICE_URL = 'http://127.0.0.1:8000/query/' + +QUESTION = [ + "请描述2024年高考作文", + "中国的绿色发展有哪些好处", + "描述一下可持续发展战略", + "解释一下极昼极夜", + "介绍一下台风", + "解释一下地球的内部结构", + "黄土高原的环境问题该怎么解决", + "介绍一下巴西", + "介绍一下爪哇岛", + "高技术工业特区有什么特点", + "台风来了怎么办", + "台风的发生条件?", + "洋流有几种", + "地球上为什么会产生昼夜更替", + "坚持以人民为中心的内涵是什么", + "圣诞节这一天,哈尔滨的白昼为什么最短", + "西北太平洋热带气旋出现的纬度?", + "东部地区重要的地理界线是什么?", + "印尼五大岛屿分别是哪些?", + "描述一下地球的内部结构" +] + +DATA_TEMPLATE = { + 'question': 'value1', +} + + +# 定义一个函数来发送POST请求 +def send_post_request(post_data, thread_id): + try: + headers = {'Content-Type': 'application/json'} + response = requests.post(SERVICE_URL, data=json.dumps(post_data), headers=headers) + logging.info('\nThread %d: Status Code %d, Response Body: %s', thread_id, response.status_code, response.text) + except Exception as e: + logging.debug('Thread %d encountered an error: %s', thread_id, e) + + +# 创建线程列表 +threads = [] + +# 创建并启动多个线程 +for i in range(20): + # 为每个线程准备不同的数据 + data = DATA_TEMPLATE.copy() + data['question'] = f'{QUESTION[random.randint(0, 19)]}' + + # 创建线程 + thread = threading.Thread(target=send_post_request, args=(data, i)) + thread.start() + threads.append(thread) + +for thread in threads: + thread.join() + +logging.info('All threads have finished execution') diff --git a/RAGSDK/MainRepo/Samples/RagDemo/langchain_chains/README.md b/RAGSDK/MainRepo/Samples/RagDemo/langchain_chains/README.md new file mode 100644 index 000000000..5eba6c557 --- /dev/null +++ b/RAGSDK/MainRepo/Samples/RagDemo/langchain_chains/README.md @@ -0,0 +1,9 @@ +# 使用说明 + +默认不使用双向认证,ssl为True时,需要传递ca_path,cert_path,key_path,pwd等字段 + + 不使用认证 + python3 llm_chain_stream.py --base_url http://127.0.0.1:1025/v1 --model_name Llama3-8B-Chinese-Chat + + 使用双向认证: + python3 llm_chain_stream.py --base_url https://127.0.0.1:1025/v1 --model_name Llama3-8B-Chinese-Chat --ssl True --ca_path xxx --cert_path xxx --key_path xxx --pwd xxx diff --git a/RAGSDK/MainRepo/Samples/RagDemo/langchain_chains/llm_chain_stream.py b/RAGSDK/MainRepo/Samples/RagDemo/langchain_chains/llm_chain_stream.py new file mode 100644 index 000000000..de2f82417 --- /dev/null +++ b/RAGSDK/MainRepo/Samples/RagDemo/langchain_chains/llm_chain_stream.py @@ -0,0 +1,133 @@ +import sys +import argparse +import threading +from queue import Queue +from typing import Any +import httpx +import openai +from langchain.chains import LLMChain +from langchain_core.callbacks import BaseCallbackHandler +from langchain_core.outputs import LLMResult +from langchain_core.prompts import PromptTemplate +from langchain_openai import ChatOpenAI +from loguru import logger + + + +class EventData: + + def __init__(self, data, finish_reason): + self.data = data + self.finish_reason = finish_reason + + +class StreamingLLMCallbackHandler(BaseCallbackHandler): + def __init__(self): + self._is_done = False + self._queue = Queue() + + def clear(self): + with self._queue.mutex: + self._queue.queue.clear() + self._is_done = False + + def on_llm_new_token(self, token: str, **kwargs: Any) -> None: + self._queue.put(EventData(data=token, finish_reason="0")) + + def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None: + self._queue.put(EventData(data="", finish_reason="done")) + self._is_done = True + + def on_llm_error(self, error: BaseException, **kwargs: Any) -> None: + logger.error(f" error happend:{error}") + self._queue.put(EventData(data=f"{error}", finish_reason="done")) + self._is_done = True + + @property + def stream_gen(self): + while not self._queue.empty() or not self._is_done: + try: + delta = self._queue.get() + yield str(delta.data) + except Exception as e: + logger.error(f"Exception:{e}") + + +def create_llm_chain(base_url, model_name, handler, ssl, ca_path, cert_path, key_path, pwd): + if not ssl: + http_client = httpx.Client() + else: + http_client = httpx.Client( + cert=(cert_path, key_path, pwd), + verify=ca_path + ) + root_client = openai.OpenAI( + base_url=base_url, + api_key="sk_fake", + http_client=http_client + ) + + client = root_client.chat.completions + + llm = ChatOpenAI( + api_key="sk_fake", + client=client, + model_name=model_name, + temperature=0.5, + streaming=True, + callbacks=[handler] + ) + + template = """<指令>你是一个旅游专家,请简明扼要回答用户问题。<指令>\n用户问题:{question}""" + prompt = PromptTemplate.from_template(template) + + # chain = LLMChain( + # llm=llm, + # prompt=prompt + # ) + return prompt | llm + + +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter): + def _get_default_metavar_for_optional(self, action): + return action.type.__name__ + + def _get_default_metavar_for_positional(self, action): + return action.type.__name__ + + +if __name__ == "__main__": + parse = argparse.ArgumentParser(formatter_class=CustomFormatter) + parse.add_argument("--base_url", type=str, default="http://127.0.0.1:1025/v1", help="大模型url base地址") + parse.add_argument("--model_name", type=str, default="Llama3-8B-Chinese-Chat", help="大模型名称") + parse.add_argument("--ssl", type=bool, default=False, help="是否开启认证") + parse.add_argument("--ca_path", type=str, default="", help="ca证书") + parse.add_argument("--cert_path", type=str, default="", help="客户端证书") + parse.add_argument("--key_path", type=str, default="", help="客户端私钥") + parse.add_argument("--pwd", type=str, default="", help="私钥解密口令") + + args = parse.parse_args() + + streaming_llm_callback_handler = StreamingLLMCallbackHandler() + streaming_llm_callback_handler.clear() + + + def get_llm_result(handler): + for chunk in handler.stream_gen: + sys.stdout.write(chunk) + sys.stdout.flush() + + + thread = threading.Thread(target=get_llm_result, args=(streaming_llm_callback_handler,)) + thread.start() + + llm_chain = create_llm_chain(base_url=args.base_url, + model_name=args.model_name, + handler=streaming_llm_callback_handler, + ssl=args.ssl, + ca_path=args.ca_path, + cert_path=args.cert_path, + key_path=args.key_path, + pwd=args.pwd + ) + llm_chain.invoke({"question": "介绍北京风景区"}) diff --git a/RAGSDK/MainRepo/Samples/RagDemo/rag_demo_cache_qa.py b/RAGSDK/MainRepo/Samples/RagDemo/rag_demo_cache_qa.py new file mode 100644 index 000000000..6d9fafbb6 --- /dev/null +++ b/RAGSDK/MainRepo/Samples/RagDemo/rag_demo_cache_qa.py @@ -0,0 +1,163 @@ +# -*- coding: utf-8 -*- +# Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + +import argparse +import json +import os +import time +import traceback +from loguru import logger +from langchain.text_splitter import RecursiveCharacterTextSplitter +from langchain_community.document_loaders import TextLoader +from mx_rag.cache import CacheConfig, SimilarityCacheConfig, MxRAGCache, CacheChainChat, \ + MarkDownParser, QAGenerationConfig, QAGenerate +from mx_rag.chain import SingleText2TextChain +from mx_rag.document import LoaderMng +from mx_rag.embedding.local import TextEmbedding +from mx_rag.knowledge import KnowledgeStore, KnowledgeDB, upload_files +from mx_rag.llm import Text2TextLLM +from mx_rag.retrievers import Retriever +from mx_rag.storage.document_store import SQLiteDocstore +from mx_rag.storage.vectorstore import MindFAISS +from mx_rag.utils import ClientParam +from paddle.base import libpaddle +from transformers import AutoTokenizer + + +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter): + def _get_default_metavar_for_optional(self, action): + return action.type.__name__ + + def _get_default_metavar_for_positional(self, action): + return action.type.__name__ + + +def rag_cache_demo(): + parse = argparse.ArgumentParser(formatter_class=CustomFormatter) + parse.add_argument("--embedding_path", type=str, default="/home/data/acge_text_embedding", + help="embedding模型本地路径") + parse.add_argument("--embedding_dim", type=int, default=1024, help="embedding模型向量维度") + parse.add_argument("--reranker_path", type=str, default="home/data/bge-reranker-large", help="reranker模型本地路径") + parse.add_argument("--white_path", type=str, nargs='+', default=["/home"], help="白名单路径,文件需在白名单路径下") + parse.add_argument("--file_path", type=str, default="/home/HwHiAiUser/gaokao.md", + help="要上传的文件路径,需在白名单路径下") + parse.add_argument("--cache_save_path", type=str, default="/home/HwHiAiUser/cache_save_dir", help="缓存地址") + parse.add_argument("--llm_url", type=str, default="http://127.0.0.1:1025/v1/chat/completions", help="大模型url地址") + parse.add_argument("--model_name", type=str, default="Llama3-8B-Chinese-Chat", help="大模型名称") + parse.add_argument("--score_threshold", type=float, default=0.5, + help="相似性得分的阈值,大于阈值认为检索的信息与问题越相关,取值范围[0,1]") + parse.add_argument("--query", type=str, default="请描述2024年高考作文题目", help="用户问题") + parse.add_argument("--tokenizer_path", type=str, default="/home/data/Llama3-8B-Chinese-Chat/", + help="大模型tokenizer参数路径") + parse.add_argument("--npu_device_id", type=int, default=0, help="NPU设备ID") + args = parse.parse_args() + + try: + # memory cache缓存作为L1缓存 + cache_config = CacheConfig(cache_size=100, data_save_folder=args.cache_save_path) + # similarity cache缓存作为L2缓存 + similarity_config = SimilarityCacheConfig( + vector_config={"vector_type": "npu_faiss_db", + "x_dim": args.embedding_dim, + "devs": [args.npu_device_id]}, + cache_config="sqlite", + emb_config={"embedding_type": "local_text_embedding", + "x_dim": args.embedding_dim, + "model_path": args.embedding_path, + "dev_id": args.npu_device_id + }, + similarity_config={ + "similarity_type": "local_reranker", + "model_path": args.embedding_path, + "dev_id": args.npu_device_id + }, + retrieval_top_k=5, + cache_size=1000, + similarity_threshold=0.8, + data_save_folder=args.cache_save_path) + + # 构造memory cache实例 + memory_cache = MxRAGCache("memory_cache", cache_config) + # 构造similarity cache实例 + similarity_cache = MxRAGCache("similarity_cache", similarity_config) + # memory_cache和similarity_cache串联形成多级缓存入口是memory cache + memory_cache.join(similarity_cache) + # 定义用于生成QA的大模型 + client_param = ClientParam(use_http=True, timeout=600) + llm = Text2TextLLM(base_url=args.llm_url, model_name=args.model_name, client_param=client_param) + # 返回markdown的标题和内容,标题要和内容相关 + titles, contents = MarkDownParser(os.path.dirname(args.file_path)).parse() + # 使用大模型计算token大小 + tokenizer = AutoTokenizer.from_pretrained(args.tokenizer_path, local_files_only=True) + # 组装生成QA的配置参数,qas_num为每个文件要生成的QA数量 + config = QAGenerationConfig(titles, contents, tokenizer, llm, qas_num=3) + # 调用大模型生成QA对 + qas = QAGenerate(config).generate_qa() + logger.info(f"qas:{qas}") + # 将QA存入缓存,答案部分需按照json格式保存 + for query, answer in qas.items(): + memory_cache.update(query, json.dumps({"result": answer})) + + # 离线构建知识库,首先注册文档处理器 + loader_mng = LoaderMng() + # 加载文档加载器,可以使用mxrag自有的,也可以使用langchain的 + loader_mng.register_loader(loader_class=TextLoader, file_types=[".txt", ".md", ".docx"]) + # 加载文档切分器,使用langchain的 + loader_mng.register_splitter(splitter_class=RecursiveCharacterTextSplitter, + file_types=[".txt", ".md", ".docx"], + splitter_params={"chunk_size": 750, + "chunk_overlap": 150, + "keep_separator": False + } + ) + + # 初始化向量数据库 + vector_store = MindFAISS(x_dim=args.embedding_dim, + devs=[args.npu_device_id], + load_local_index=os.path.join(args.cache_save_path, "./faiss.index")) + + # 加载embedding模型,请根据模型具体路径适配 + emb = TextEmbedding(model_path=args.embedding_path, dev_id=args.npu_device_id) + + # 初始化文档chunk关系数据库 + chunk_store = SQLiteDocstore(db_path="./sql.db") + # <可选>初始化知识管理关系数据库 + knowledge_store = KnowledgeStore(db_path="./sql.db") + knowledge_store.add_knowledge("rag", "Default01", "admin") + # <可选>初始化知识库管理 + knowledge_db = KnowledgeDB(knowledge_store=knowledge_store, + chunk_store=chunk_store, + vector_store=vector_store, + knowledge_name="test", + white_paths=args.white_path, + user_id="Default01" + ) + # <可选> 完成离线知识库构建,上传领域知识gaokao.md文档。 + upload_files(knowledge=knowledge_db, + files=[args.file_path], + loader_mng=loader_mng, + embed_func=emb.embed_documents, + force=True + ) + + # 初始化Retriever检索器 + text_retriever = Retriever(vector_store=vector_store, + document_store=chunk_store, + embed_func=emb.embed_documents, + k=3, + score_threshold=args.score_threshold + ) + + # 构造cache_chain, 缓存memory cache作为入口 + cache_chain = CacheChainChat(chain=SingleText2TextChain(llm, text_retriever), cache=memory_cache) + # 提问和网页相关的问题,如果与已生成的QA近似,则会命中返回 + now_time = time.time() + logger.info(cache_chain.query(args.query)) + logger.info(f"耗时:{time.time() - now_time}s") + except Exception as e: + stack_trace = traceback.format_exc() + logger.error(stack_trace) + + +if __name__ == '__main__': + rag_cache_demo() diff --git a/RAGSDK/MainRepo/Samples/RagDemo/rag_demo_knowledge.py b/RAGSDK/MainRepo/Samples/RagDemo/rag_demo_knowledge.py new file mode 100644 index 000000000..021ff870b --- /dev/null +++ b/RAGSDK/MainRepo/Samples/RagDemo/rag_demo_knowledge.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +# Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + +import argparse +import threading +import traceback +from loguru import logger +from langchain.text_splitter import RecursiveCharacterTextSplitter +from langchain_community.document_loaders import TextLoader +from mx_rag.document import LoaderMng +from mx_rag.document.loader import DocxLoader, PdfLoader +from mx_rag.embedding.local import TextEmbedding +from mx_rag.embedding.service import TEIEmbedding +from mx_rag.knowledge import KnowledgeDB +from mx_rag.knowledge.handler import upload_files +from mx_rag.knowledge.knowledge import KnowledgeStore +from mx_rag.storage.document_store import SQLiteDocstore +from mx_rag.storage.vectorstore import MindFAISS +from mx_rag.utils import ClientParam +from paddle.base import libpaddle + + +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter): + def _get_default_metavar_for_optional(self, action): + return action.type.__name__ + + def _get_default_metavar_for_positional(self, action): + return action.type.__name__ + + +def rag_demo_upload(): + parse = argparse.ArgumentParser(formatter_class=CustomFormatter) + parse.add_argument("--embedding_path", type=str, default="/home/data/acge_text_embedding", + help="embedding模型本地路径") + parse.add_argument("--tei_emb", type=bool, default=False, help="是否使用TEI服务化的embedding模型") + parse.add_argument("--embedding_url", type=str, default="http://127.0.0.1:8080/embed", + help="使用TEI服务化的embedding模型url地址") + parse.add_argument("--embedding_dim", type=int, default=1024, help="embedding模型向量维度") + parse.add_argument("--white_path", type=str, nargs='+', default=["/home"], help="文件白名单路径") + parse.add_argument("--file_path", type=str, action='append', help="要上传的文件路径,需在白名单路径下") + parse.add_argument("--num_threads", type=int, default=2, help="可以根据实际情况调整线程数量") + + args = parse.parse_args().__dict__ + embedding_path: str = args.pop('embedding_path') + embedding_url: str = args.pop('embedding_url') + tei_emb: bool = args.pop('tei_emb') + embedding_dim: int = args.pop('embedding_dim') + white_path: list[str] = args.pop('white_path') + file_path: list[str] = args.pop('file_path') + num_threads: int = args.pop('num_threads') + + try: + # 离线构建知识库,首先注册文档处理器 + loader_mng = LoaderMng() + # 加载文档加载器,可以使用mxrag自有的,也可以使用langchain的 + loader_mng.register_loader(loader_class=TextLoader, file_types=[".txt", ".md"]) + loader_mng.register_loader(loader_class=PdfLoader, file_types=[".pdf"]) + loader_mng.register_loader(loader_class=DocxLoader, file_types=[".docx"]) + # 加载文档切分器,使用langchain的 + loader_mng.register_splitter(splitter_class=RecursiveCharacterTextSplitter, + file_types=[".pdf", ".docx", ".txt", ".md"], + splitter_params={"chunk_size": 750, + "chunk_overlap": 150, + "keep_separator": False + } + ) + # 设置向量检索使用的npu卡,具体可以用的卡可执行npu-smi info查询获取 + dev = 0 + # 加载embedding模型,请根据模型具体路径适配 + if tei_emb: + emb = TEIEmbedding(url=embedding_url, client_param=ClientParam(use_http=True)) + else: + emb = TextEmbedding(model_path=embedding_path, dev_id=dev) + # 初始化向量数据库 + vector_store = MindFAISS(x_dim=embedding_dim, + devs=[dev], + load_local_index="./faiss.index", + auto_save=True + ) + # 初始化文档chunk关系数据库 + chunk_store = SQLiteDocstore(db_path="./sql.db") + # 初始化知识管理关系数据库 + knowledge_store = KnowledgeStore(db_path="./sql.db") + # 添加知识库 + knowledge_store.add_knowledge("test", "Default", "admin") + # 初始化知识库管理 + knowledge_db = KnowledgeDB(knowledge_store=knowledge_store, + chunk_store=chunk_store, + vector_store=vector_store, + knowledge_name="test", + white_paths=white_path, + user_id="Default" + ) + + # 多线程上传文件 + batch_size = len(file_path) // num_threads + if len(file_path) % num_threads != 0: + batch_size += 1 + file_batchs = [file_path[i:i + batch_size] for i in range(0, len(file_path), batch_size)] + + threads = [] + for batch in file_batchs: + thread = threading.Thread(target=upload_files, + args=(knowledge_db, batch, loader_mng, emb.embed_documents, True)) + threads.append(thread) + thread.start() + + for thread in threads: + thread.join() + + # 检验文件是否上传成功 + documents = [document.document_name for document in knowledge_db.get_all_documents()] + logger.info(documents) + except Exception as e: + stack_trace = traceback.format_exc() + logger.error(stack_trace) + + +if __name__ == '__main__': + rag_demo_upload() diff --git a/RAGSDK/MainRepo/Samples/RagDemo/rag_demo_query.py b/RAGSDK/MainRepo/Samples/RagDemo/rag_demo_query.py new file mode 100644 index 000000000..ff5e747e2 --- /dev/null +++ b/RAGSDK/MainRepo/Samples/RagDemo/rag_demo_query.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- +# Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + +import argparse +import threading +import traceback +from loguru import logger +from mx_rag.chain import SingleText2TextChain +from mx_rag.embedding.local import TextEmbedding +from mx_rag.embedding.service import TEIEmbedding +from mx_rag.llm import Text2TextLLM +from mx_rag.reranker.local import LocalReranker +from mx_rag.reranker.service import TEIReranker +from mx_rag.retrievers import Retriever +from mx_rag.storage.document_store import SQLiteDocstore +from mx_rag.storage.vectorstore import MindFAISS +from mx_rag.utils import ClientParam +from paddle.base import libpaddle + + +class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter): + def _get_default_metavar_for_optional(self, action): + return action.type.__name__ + + def _get_default_metavar_for_positional(self, action): + return action.type.__name__ + + +class ThreadWithResult(threading.Thread): + def __init__(self, group=None, target=None, name=None, args=None, kwargs=None, *, daemon=None): + def function(): + self.result = target(*args, **kwargs) + + super().__init__(group=group, target=function, name=name, daemon=daemon) + + +def rag_demo_query(): + parse = argparse.ArgumentParser(formatter_class=CustomFormatter) + parse.add_argument("--embedding_path", type=str, default="/home/data/acge_text_embedding", + help="embedding模型本地路径") + parse.add_argument("--tei_emb", type=bool, default=False, help="是否使用TEI服务化的embedding模型") + parse.add_argument("--embedding_url", type=str, default="http://127.0.0.1:8080/embed", + help="使用TEI服务化的embedding模型url地址") + parse.add_argument("--embedding_dim", type=int, default=1024, help="embedding模型向量维度") + parse.add_argument("--llm_url", type=str, default="http://127.0.0.1:1025/v1/chat/completions", help="大模型url地址") + parse.add_argument("--model_name", type=str, default="Llama3-8B-Chinese-Chat", help="大模型名称") + parse.add_argument("--score_threshold", type=float, default=0.5, + help="相似性得分的阈值,大于阈值认为检索的信息与问题越相关,取值范围[0,1]") + parse.add_argument("--tei_reranker", type=bool, default=False, help="是否使用TEI服务化的reranker模型") + parse.add_argument("--reranker_path", type=str, default=None, help="reranker模型本地路径") + parse.add_argument("--reranker_url", type=str, default=None, help="使用TEI服务化的embedding模型url地址") + parse.add_argument("--query", type=str, action='append', help="用户问题") + parse.add_argument("--num_threads", type=int, default=2, help="可以根据实际情况调整线程数量") + + args = parse.parse_args().__dict__ + embedding_path: str = args.pop('embedding_path') + embedding_url: str = args.pop('embedding_url') + tei_emb: bool = args.pop('tei_emb') + embedding_dim: int = args.pop('embedding_dim') + llm_url: str = args.pop('llm_url') + model_name: str = args.pop('model_name') + score_threshold: int = args.pop('score_threshold') + query: list[str] = args.pop('query') + num_threads: int = args.pop('num_threads') + + try: + # 设置向量检索使用的npu卡,具体可以用的卡可执行npu-smi info查询获取 + dev = 0 + # 加载embedding模型,请根据模型具体路径适配 + if tei_emb: + emb = TEIEmbedding(url=embedding_url, client_param=ClientParam(use_http=True)) + else: + emb = TextEmbedding(model_path=embedding_path, dev_id=dev) + + # 初始化向量数据库 + vector_store = MindFAISS(x_dim=embedding_dim, + devs=[dev], + load_local_index="./faiss.index", + auto_save=True + ) + # 初始化文档chunk关系数据库 + chunk_store = SQLiteDocstore(db_path="./sql.db") + + # Step2在线问题答复,初始化检索器 + text_retriever = Retriever(vector_store=vector_store, + document_store=chunk_store, + embed_func=emb.embed_documents, + k=1, + score_threshold=score_threshold + ) + # 配置reranker,请根据模型具体路径适配 + reranker_path = args.get("reranker_path") + reranker_url = args.get("reranker_url") + tei_reranker = args.get("tei_reranker") + if tei_reranker: + reranker = TEIReranker(url=reranker_url, client_param=ClientParam(use_http=True)) + elif reranker_path is not None: + reranker = LocalReranker(model_path=reranker_path, dev_id=dev) + else: + reranker = None + # 配置text生成text大模型chain,具体ip端口请根据实际情况适配修改 + llm = Text2TextLLM(base_url=llm_url, model_name=model_name, client_param=ClientParam(use_http=True, timeout=60)) + + def process_query(input_string: str) -> str: + text2text_chain = SingleText2TextChain(retriever=text_retriever, llm=llm, reranker=reranker) + # 知识问答 + res = text2text_chain.query(input_string) + # 打印结果 + logger.info(res) + return f"{res}" + + results = [] + batch_size = len(query) // num_threads + if len(query) % num_threads != 0: + batch_size += 1 + batchs = [query[i:i + batch_size] for i in range(0, len(query), batch_size)] + + threads = [] + for batch in batchs: + def process_batch(batch): + batch_results = [] + for s in batch: + batch_results.append(process_query(s)) + return batch_results + + thread = ThreadWithResult(target=process_batch, args=(batch,)) + threads.append(thread) + thread.start() + + for thread in threads: + thread.join() + results.extend(thread.result) + + return results + + except Exception as e: + stack_trace = traceback.format_exc() + logger.error(stack_trace) + raise e + + +if __name__ == '__main__': + rag_demo_query() diff --git a/RAGSDK/MainRepo/langgraph/README.md b/RAGSDK/MainRepo/langgraph/README.md new file mode 100644 index 000000000..612b0977d --- /dev/null +++ b/RAGSDK/MainRepo/langgraph/README.md @@ -0,0 +1,609 @@ +# RAG SDK基于LangGraph知识检索增强应用使能方案 + +## 1 背景 + +### 1.0 LangGraph介绍 + +[LangGraph官方介绍](https://blog.langchain.dev/langgraph/) +> LangGraph是Langchain新出的一个成员,是 LangChain 的 LangChain Expression Language +> (LCEL)的扩展。能够利用有向无环图的方式,去协调多个LLM或者状态,使用起来比 LCEL +> 会复杂,但是逻辑会更清晰。前期大家都学习了langchain,现在再上手学习langGraph就会容易许多,这也是我上面提到过的学习成本。我们可以把它也当做langchain扩展出来的Agent框架,langchain原有agent +> 的实现在LangGraph中都得到了重新实现,所以对于原来使用Langchain的系统去接入更容易。 + +### 1.1 RAG SDK介绍 + +RAG SDK 详细资料参考 [昇腾社区](https://www.hiascend.com/software/mindx-sdk) +> RAG SDK 是昇腾面向大语言模型的知识增强开发套件,为解决大模型知识更新缓慢以及垂直领域知识问答弱的问题,面向大模型知识库提供垂域调优、生成增强、知识管理等特性。 + +### 1.2 昇腾mis介绍 + +> mis: mind inference microservice +> +昇腾提供基于昇腾硬件加速的reranker和embedding mis服务,通过快速部署就可以支撑RAG应用。 +
+ +
+ +embedding tei [安装地址](https://www.hiascend.com/developer/ascendhub/detail/07a016975cc341f3a5ae131f2b52399d) +reranker tei [安装地址](https://www.hiascend.com/developer/ascendhub/detail/07a016975cc341f3a5ae131f2b52399d) + +## 2 环境安装 + +参考 RAG SDK环境安装手册,分别安装cann、rag SDK、以及部署embedding, reranker, mindie Service服务,安装langgraph包:pip3 +install langgraph==0.2.19 + +## 3 总体介绍 + +基于langgraph和rag sdk搭建RAG应用, 根据langgraph的定义需要包含node和graph,node中使用rag sdk完成相应的功能。 + +**RAG 节点(Node)定义** + +* cache search node:用户问题缓存查询节点 +* query decompose node:用户问题拆分子问题节点 +* hybrid Retrieve node:用户问题混合检索文档节点 +* rerank node:重排检索文档节点 +* generate node:大模型生成节点 +* halluciation check node:生成内容幻觉检查节点 +* query rewrite node: 用户问题重写节点 +* cache update node: 用户问题缓存更新节点 + +**RAG 图(GRAPH)定义** +图定义如下: +![alt text](image_new.png) + +状态转换如下表所示: +name | type |next hop | input | output +-|-|-|-|- +**cache search**| node| if cache hit return generation to user else go **query decompose** | (qustion) | if hit ( +question, generation) else (qustion) +**query decompose** | node | **hybrid retrieve** | (question) | (question, sub_qustion) +**hybrid retrieve** | node | **rerank** | (question, sub_qustion) | (question, sub_qustion, contexts) +**rerank** | node | **generate** | (question, sub_qustion, contexts) | (question, sub_qustion, contexts) +**query rewrite** | node | **cache search** | (question, sub_qustion, contexts) or (question, sub_qustion, contexts, +generate) | (question) +**generate**| node | **halluciation check** | (question, sub_qustion, contexts) | (question, sub_qustion, contexts, +generate) +**halluciation check** | node | if halluciation check pass go **cache update** else go **query rewrite** | (question, +sub_qustion, contexts, generate) | (question, sub_qustion, contexts, generate) +**cache update** | node | END | (question, sub_qustion, contexts, generate) | (question, sub_qustion, contexts, +generate) + +## 4 RAG SDK 功能初始化 + +完整的代码样例请参考[langgraph_demo.py](langgraph_demo.py) + +### 4.1 RAG文档加载和切分 + +以下是初始化一个docx的文件加载器和文件切分器,并且按照chunk_size=200,chunk_overlap=50进行切分,详细的API文档请参考RAG +SDK的使用手册。 + +```python +def create_loader_and_spliter(mxrag_component: Dict[str, Any], + chunk_size:int = 200, + chunk_overlap:int = 50): + from langchain.text_splitter import RecursiveCharacterTextSplitter + + from mx_rag.knowledge.doc_loader_mng import LoaderMng + from mx_rag.document.loader import DocxLoader + + loader_mng = LoaderMng() + loader_mng.register_loader(DocxLoader, [".docx"]) + loader_mng.register_splitter(RecursiveCharacterTextSplitter, [".docx"], + {"chunk_size": chunk_size, "chunk_overlap": chunk_overlap, "keep_separator": False}) + mxrag_component["loader_mng"] = loader_mng +``` + +### 4.2 RAG远端服务 + +以下是分别初始化mindie Service,AIM embedding,AIM reranker服务,用户需要传入相应的地址。 + +```python +def create_remote_connector(mxrag_component: Dict[str, Any], + reranker_url: str, + embedding_url: str, + llm_url: str, + llm_model_name: str): + from mx_rag.llm.text2text import Text2TextLLM + from mx_rag.embedding import EmbeddingFactory + from mx_rag.reranker.reranker_factory import RerankerFactory + + reranker = RerankerFactory.create_reranker(similarity_type="tei_reranker", + url=reranker_url, + client_param=ClientParam,(use_http=True), + k=3) + mxrag_component['reranker_connector'] = reranker + + embedding = EmbeddingFactory.create_embedding(embedding_type="tei_embedding", + url=embedding_url, + client_param=ClientParam(use_http=True)) + mxrag_component['embedding_connector'] = embedding + + llm = Text2TextLLM(base_url=llm_url, model_name=llm_model_name, + client_param=ClientParam(use_http=True), + llm_config=LLMParameterConfig(max_tokens=4096)) + mxrag_component['llm_connector'] = llm +``` + +### 4.3 RAG知识库 + +以下是存放用户知识文档的样例,这里使用mxindex(MindFaiss)作为矢量检索,knowledge_files是用户需要传入包含文件路径的文件名列表。 + +```python +def create_knowledge_storage(mxrag_component: Dict[str, Any], knowledge_files: List[str]): + from mx_rag.knowledge.knowledge import KnowledgeStore + from mx_rag.knowledge import KnowledgeDB + from mx_rag.knowledge.handler import upload_files + from mx_rag.storage.document_store import SQLiteDocstore + + npu_dev_id = 0 + + # faiss_index_save_file is your faiss index save dir + faiss_index_save_file:str = "/home/HwHiAiUser/rag_npu_faiss.index" + vector_store = MindFAISS(x_dim=1024, + devs=[npu_dev_id], + load_local_index=faiss_index_save_file) + mxrag_component["vector_store"] = vector_store + + + # sqlite_save_file is your sqlite save dir + sqlite_save_file:str = "/home/HwHiAiUser/rag_sql.db" + chunk_store = SQLiteDocstore(db_path=sqlite_save_file) + mxrag_component["chunk_store"] = chunk_store + + # your knowledge file white paths if docx not in white paths will raise exception + white_paths=["/home/HwHiAiUser/"] + knowledge_store = KnowledgeStore(db_path=sqlite_save_file) + knowledge_store.add_knowledge("rag", "Default01", "admin") + Knowledge_db = KnowledgeDB(knowledge_store=knowledge_store, chunk_store=chunk_store, vector_store=vector_store, + knowledge_name="rag", white_paths=white_paths, user_id="Default01") + + upload_files(Knowledge_db, knowledge_files, loader_mng=mxrag_component.get("loader_mng"), + embed_func=mxrag_component.get("embedding_connector").embed_documents, + force=True) +``` + +### 4.4 RAG缓存系统 + +定义语义缓存系统,用于缓存用户已经提供过的答案,当用户再次提问相似的问题可以很快 +返回结果,不需要再进行大模型推理,加速E2E性能。 +语义缓存一般包含矢量数据库,标量数据库以及相应的embedding和相似度计算方法。 + +```python +def create_cache(mxrag_component: Dict[str, Any], + reranker_url: str, + embedding_url: str): + from mx_rag.cache import SimilarityCacheConfig + from mx_rag.cache import EvictPolicy + from mx_rag.cache import MxRAGCache + + npu_dev_id = 0 + # data_save_folder is your cache file when you next run your rag applicate it will read form disk + cache_data_save_folder = "/home/HwHiAiUser/mx_rag/cache_save_folder/" + + similarity_config = SimilarityCacheConfig( + vector_config={ + "vector_type": "npu_faiss_db", + "x_dim": 1024, + "devs": [npu_dev_id], + }, + cache_config="sqlite", + emb_config={ + "embedding_type": "tei_embedding", + "url": embedding_url, + "client_param": ClientParam(use_http=True) + }, + similarity_config={ + "similarity_type": "tei_reranker", + "url": reranker_url, + "client_param": ClientParam(use_http=True) + }, + retrieval_top_k=3, + cache_size=100, + auto_flush=100, + similarity_threshold=0.70, + data_save_folder=cache_data_save_folder, + disable_report=True, + eviction_policy=EvictPolicy.LRU + ) + + similarity_cache = MxRAGCache("similarity_cache", similarity_config) + mxrag_component["cache"] = similarity_cache +``` + +### 4.5 RAG评估系统 + +以下是初始化评估系统,这里使用大模型进行评估 + +```python +def create_evaluate(mxrag_component): + from mx_rag.evaluate import Evaluate + + llm = mxrag_component.get("llm_connector") + embedding = mxrag_component.get("embedding_connector") + mxrag_component["evaluator"] = Evaluate(llm=llm, embedding=embedding) +``` + +### 4.6 RAG混合检索 + +以下是构建混合检索的样例,这里使用了矢量检索和BM25检索,并按照RRF算法设置权重进行排序得到最后的检索文档。 + +```python +def create_hybrid_search_retriever(mxrag_component: Dict[str, Any]): + from langchain.retrievers import EnsembleRetriever + + from mx_rag.retrievers.retriever import Retriever + from mx_rag.retrievers import BMRetriever + + chunk_store = mxrag_component.get("chunk_store") + vector_store = mxrag_component.get("vector_store") + embedding = mxrag_component.get("embedding_connector") + + npu_faiss_retriever = Retriever(vector_store=vector_store, document_store=chunk_store, + embed_func=embedding.embed_documents, k=10, score_threshold=0.4) + + hybrid_retriever = EnsembleRetriever( + retrievers=[npu_faiss_retriever], weights=[1.0] + ) + + mxrag_component["retriever"] = hybrid_retriever +``` + +## 5 langgraph 图定义和编译运行 + +完整的代码样例请参考[langgraph_demo.py](langgraph_demo.py) + +### 5.1 Node定义 + +#### 5.1.1 Cache Search + +使用用户的问题,访问rag cache,如果命中generation不为None + +```python +def cache_search(cache): + def cache_search_process(state): + logger.info("---QUERY SEARCH ---") + question = state["question"] + generation = cache.search(question) + return {"question": question, "generation": generation} + + return cache_search_process +``` + +判决cache search 是否hit,根据generation 是否为None进行判断,如果为None则表示 +cache miss,如果不为None则cache hit + +```python +def decide_to_decompose(state): + logger.info("---DECIDE TO DECOMPOSE---") + cache_generation = state["generation"] + + if cache_generation is None: + logger.warning( + "---DECISION: CACHE MISS GO DECOMPOSE---" + ) + return "cache_miss" + + logger.info("---DECISION: CACHE HIT END---") + return "cache_hit" +``` + +#### 5.1.2 Query Decompose + +使用提示词工程进行问题拆解,拆解为子问题 + +```python +def decompose(llm): + sub_question_key_words = "Q:" + prompt = PromptTemplate( + template=""" + 请你参考如下示例,拆分用户的问题为独立子问题,如果无法拆分则返回原始问题: + 示例一: + 用户问题: 今天的天气如何, 你今天过的怎么样? + + {sub_question_key_words}今天的天气如何? + {sub_question_key_words}你今天过的怎么样? + + 示例二: + 用户问题: 汉堡好吃吗? + + {sub_question_key_words}汉堡好吃吗? + + 现在请你参考示例拆分以下用户问题: + 用户的问题:{question} + """, + input_variables=["question", "sub_question_key_words"] + ) + + sub_question_generator = LLMChain(llm=llm, prompt=prompt) + + def decompose_process(state): + logger.info("---QUERY DECOMPOSITION ---") + question = state["question"] + + sub_queries = sub_question_generator.predict(question=question, sub_question_key_words=sub_question_key_words) + if sub_question_key_words not in sub_queries: + sub_queries = None + else: + sub_queries = sub_queries.split(sub_question_key_words) + sub_queries = sub_queries[1:] + + return {"sub_questions": sub_queries, "question": question} + + return decompose_process +``` + +#### 5.1.3 Hybrid Retrive + +以下是进行混合检索,如果sub_question为None则使用quesiton进行检索,如果sub_question不为None则使用sub_question进行检索。 + +```python +def retrieve(retriever: BaseRetriever): + def retrieve_process(state): + logger.info("---RETRIEVE---") + sub_questions = state["sub_questions"] + question = state["question"] + + documents = [] + docs = [] + if sub_questions is None: + docs = retriever.get_relevant_documents(question) + else: + for query in sub_questions: + docs.extend(retriever.get_relevant_documents(query)) + + for doc in docs: + if doc.page_content not in documents: + documents.append(doc.page_content) + + return {"documents": documents, "question": question} + + return retrieve_process +``` + +#### 5.1.4 Rerank + +将用户的检索文档根据语义进行重排序 + +```python +def rerank(reranker): + def rerank_process(state): + logger.info("---RERANK---") + question = state["question"] + documents = state["documents"] + + scores = reranker.rerank(query=question, texts=documents) + documents = reranker.rerank_top_k(objs=documents, scores=scores) + + return {"documents": documents, "question": question} + + return rerank_process +``` + +#### 5.1.6 Generate + +使用提示词工程访问进行大模型推理过程得到生成结果。 + +```python +def generate(llm): + prompt = PromptTemplate( + template="""{context} + + 根据上述已知信息,简洁和专业的来回答用户问题。如果无法从中已知信息中得到答案,请根据自身经验做出回答 + + {question} + """, + input_variables=["context", "question"] + ) + + rag_chain = LLMChain(llm=llm, prompt=prompt) + + def generate_process(state): + logger.info("---GENERATE---") + question = state["question"] + documents = state["documents"] + + generation = rag_chain.predict(context=documents, question=question) + return {"documents": documents, "question": question, "generation": generation} + + return generate_process +``` + +#### 5.1.7 Halluciation Check + +利用大模型评估进行判断生成质量是否符合用户需求。 + +```python +def grade_generation_v_documents_and_question(evaluate, + context_score_threshold: float = 0.6, + answer_score_threshold: float = 0.6): + generate_evalutor = evaluate_creator(evaluate, "generate_relevancy") + + def grade_generation_v_documents_and_question_process(state): + logger.info("---CHECK HALLUCINATIONS---") + + answer_score, context_score = generate_evalutor(state) + + answer_score = answer_score[0] + logger.info("---GRADE GENERATION vs QUESTION---") + if answer_score < answer_score_threshold: + logger.warning(f"---DECISION: GENERATION DOES NOT ADDRESS QUESTION," + f" RE-TRY--- answer_score:{answer_score}," + f"answer_score_threshold:{answer_score_threshold}") + return "not useful" + + logger.info(f"---DECISION: GENERATION ADDRESSES QUESTION--- " + f"answer_score:{answer_score}," + f"answer_score_threshold:{answer_score_threshold}") + + context_score = context_score[0] + logger.info("---GRADE GENERATION vs DOCUMENTS---") + if context_score < context_score_threshold: + logger.warning(f"---DECISION: GENERATION IS NOT GROUNDED IN DOCUMENTS, " + f" RE-TRY--- context_score:{context_score}," + f"context_score_threshold:{context_score_threshold}") + return "not useful" + + logger.info(f"---DECISION: GENERATION GROUNDED IN DOCUMENTS---" + f"context_score:{context_score}," + f"context_score_threshold:{context_score_threshold}") + return "useful" + + return grade_generation_v_documents_and_question_process +``` + +#### 5.1.8 CacheUpdate + +如果大模型生成质量符合要求,则更新缓存 + +```python +def cache_update(cache): + def cache_update_process(state): + logger.info("---QUERY UPDATE ---") + question = state["question"] + generation = state["generation"] + + cache.update(question, generation) + + return state + + return cache_update_process +``` + +#### 5.1.9 Query Rewrite + +利用提示词工程进行问答重写 + +```python +def transform_query(llm): + prompt = PromptTemplate( + template=""" + 你是一个用户问题重写员, 请仔细理解用户问题的内容和语义和检索的文档,在不修改用户问题 + 语义的前提下,将用户问题重写为可以更好被矢量检索的形式 + + 用户问题:{question} + """, + input_variables=["question"] + ) + + question_rewriter = LLMChain(llm=llm, prompt=prompt) + + def transform_query_process(state): + logger.info("---TRANSFORM QUERY---") + question = state["question"] + documents = state["documents"] + + better_question = question_rewriter.predict(question=question) + + return {"documents": documents, "question": better_question} + + return transform_query_process +``` + +### 5.2 图编译 + +```python +def build_mxrag_application(mxrag_component): + from langgraph.graph import END, START, StateGraph + + class GraphState(TypedDict): + question: str + sub_questions: List[str] + generation: str + documents: List[str] + + llm = mxrag_component.get("llm_connector") + retriever = mxrag_component.get("retriever") + reranker = mxrag_component.get("reranker_connector") + cache = mxrag_component.get("cache") + evaluate = mxrag_component.get("evaluator") + + workflow = StateGraph(GraphState) + workflow.add_node("cache_search", cache_search(cache)) + workflow.add_node("cache_update", cache_update(cache)) + workflow.add_node("decompose", decompose(llm)) + workflow.add_node("retrieve", retrieve(retriever)) + workflow.add_node("rerank", rerank(reranker)) + workflow.add_node("generate", generate(llm)) + workflow.add_node("transform_query", transform_query(llm)) + + workflow.add_edge(START, "cache_search") + + workflow.add_conditional_edges( + "cache_search", + decide_to_decompose, + { + "cache_hit": END, + "cache_miss": "decompose", + }, + ) + + workflow.add_edge("decompose", "retrieve") + workflow.add_edge("retrieve", "rerank") + workflow.add_edge("rerank", "generate") + workflow.add_edge("transform_query", "cache_search") + workflow.add_conditional_edges( + "generate", + grade_generation_v_documents_and_question(evaluate), + { + "useful": "cache_update", + "not useful": "transform_query" + }, + ) + + workflow.add_edge("cache_update", END) + app = workflow.compile() + return app +``` + +### 5.3 在线问答 + +```python +if __name__ == "__main__": + mxrag_component: Dict[str, Any] = {} + + # mis tei rerank + mis_tei_reranker_url = "http://ip:port/rerank" + # mis tei embed + mis_tei_embedding_url = "http://ip:port/embed" + + # mindie llm server + llm_url = "http://ip:port/v1/chat/completions" + + # llm model name like Llama3-8B-Chinese-Chat etc + llm_model_name = "Llama3-8B-Chinese-Chat" + + # your knowledge list + knowledge_files = ["/home/HwHiAiUser/doc1.docx"] + + create_loader_and_spliter(mxrag_component, chunk_size=200, chunk_overlap=50) + + create_remote_connector(mxrag_component, + reranker_url=mis_tei_reranker_url, + embedding_url=mis_tei_embedding_url, + llm_url=llm_url, + llm_model_name=llm_model_name) + + create_knowledge_storage(mxrag_component, knowledge_files=knowledge_files) + + create_cache(mxrag_component, + reranker_url=mis_tei_reranker_url, + embedding_url=mis_tei_embedding_url) + + create_hybrid_search_retriever(mxrag_component) + + create_evaluate(mxrag_component) + + rag_app = build_mxrag_application(mxrag_component) + + user_question = "your question" + + start_time = time.time() + user_answer = rag_app.invoke({"question": user_question}) + end_time = time.time() + + print(f"user_question:{user_question}") + print(f"user_answer:{user_answer}") + print(f"app time cost:{(end_time - start_time) * 1000} ms") +``` + +## 6 附录 diff --git a/RAGSDK/MainRepo/langgraph/image-1.png b/RAGSDK/MainRepo/langgraph/image-1.png new file mode 100644 index 0000000000000000000000000000000000000000..1a14712ef83412dcf0826a0497b06bc3c998b245 GIT binary patch literal 14517 zcma)j2UL?yx2_ZwP^3vwq)U?;AOWQJ8hUTidk7F9gpSgyAWga;MX8DqgwUJPRHP$8 zkbodH(nOH^=KKEteE+%kuCvZsuVkD|dH0@~J$paTPNIRH1|`L9ic6O+QEF+b8eO_X zvth?_yPj-ClrGr68yl2lCQ6~i@A%Vjz<8um^xTo zQdk@URP*U*nm~2A#Z-W@w}+Pt@S)-2t>@+AXas`mxQHnkE5Tq$Uny@rM|Y@!c8D`dQ`;W_k^%(N2yu6HHIhYcZ zWZ){nEv5_xOZq#jIa-)oh{DXR)Pb5{BTqF?P4{2}2dEEJR9nh1Skq5a0xGKR?Jc3| z<>uvy68DmJQZfU^Kw1QtXgQl3XgL~N8d({8sObh>%^qma-j5IZTp(fHUdT#ng zCP)<(Uq>ZnT@M|Ywuc8OB-q@~5upxqb(J8@sH`m(D2Z?v4RZ97R2M_&257?^wJfEP z`dW@KD^Xn|4Kqh`3y=of(A`lgL>FSDFD>q*<^|S=gVccD{@wv5{t^g79|^0Vpa7|$ z5R{%e3W0Rf6Bkq00!dn$x`Tq8#kEZR%q-zrU^Otp#ljSZkaG8g`uRfifdM=G zHCzqF3Gbp~>Y$Bs@K@J>!_BO`kwLEhN(g@+Bc!FeI7C~+&BzhrsBS3b>uU@`n))N8 z9rX;MaAcsNff7_*6s{?z8R&>Kk=8Zwbpr-7QE_nh(O1!M)>rlOS8_ECL%1UKxYpZ7lf#WxhNE=r5$9TW~^;yiBj@(@dts_#FY`Q zaJWSPNF1Uf3cR+ulCv7vToUP{;bp2ODGCzvc7SO(n5mcqD)|S3m2~_h0-T&6Vp=K? zBv{MW(;x1PFg5mpD!b|HE1OC~-9vP=q3VWCIw&&<)xaQqUtN%wm4~Ehhy+4R-9g`3 zO;y6p+tF7-Ts#ou?yRG1VrmfN;Oear44gh?D=SxR3srTq5N8uTxH-y6T{qA-z)DLS zChhI0Dh4%?l8~^})=~EMHJ0)*a#8a32ScSoR1H9`z81mip038y&SL(+FuJ}jM#jcs zk_M^}M?YONgFs6if42aTtBVd{yP8N@K@pNV$N+OsO$Ug9r31o6-CPHX)Hani@RdY3 zyQ^z>NttPD2Wgopn}h_rI{J$m_`#IDfPo!U00W`y4AlYq>S-E#yJ@=mAoZkBj-pon zNKp+ds{k!aFxbZnrKe>H7$RjYRj7u8Hc&7y)=>5~)&wcLE4erYBh?TReg>NQge_{Q zYbdVj2^7?%;2H)5^_#1L^$`*lKBA6bX-#u6Z?!-}U4m}ZAtnaW{vm`;dQeFe@ZlO_ zqM_&P4)g)32WUzd09F1-A7{c6S`v=7IPkLS|F#K#83^G2|1!toYD4hu;!Bs5zNRr57$j{MYRl{{_v=7!=xbj!49HQ%hq z)U=Ydo0^&;2d6SEJ9XxzIS!e(bL6*Vfn>zMe+A73IonxuU2VzRr6#Du3*j5rHDOfl%I^{@8$ zHR->{rHHDjwZESGuaSUmB>%r|iUOoB3r0SDw0cx|gJu3hOKHuzV8~&IZ=hdn zd^=;9Y}oQHeFFQELCmRI@8?Awffv?AS8*_~@{PYIVvkpRTTjhf^V-m&AXz+BjqKot zQk1?ZM(*tE&KkL-IhEFzk0f%Z!iC#AiofT~-ULC)UUaY$VU?KZByPOoNKCi}RSs6n zD)a!)#o?!&EuY>bNXhp|5eb(ROFCk&kzlcvvrV{uJANawjD z{mXpquREL3i8P-@QKR0fS9$Zqvo;ruurEb8=-7#9*@;|ePmT`OH5Cq}2e0t5-*@Kh zB_5oYFtD`--wTM9`fPAXUs8WG0os=`8@uQG^Ua2=_MH^GnWHHa9pNpi^Awe!H#*;; z*dpwrHB<7U6_-TY-HaDalJKWtS<@xGUrxC5N_;_Kvgcd!yP8l%RQgTSxDH`yZr^L&tB!NK&zqOGr>P|aqM%% zmbQZxzBz*{uYGojzRhv+jY;XN4p!`r{9eFuTusda6|xgq-c-XPcj`m>D~4lKfi@!= z6pri+ZI%8*0~xjkRWXrp5R@E9D`k_P7G4!(?=Ufygt63>m5HbgVC$#!$*r_Wj%%@6 zHFH+7DPUt^N~Z22BR!3C%F<5=D8gFo4bs!RW=yXGqa}f<&Dwr;w7t6d>KR?e9WV*M zldFvPP&D3by^CHQN>FJMd#P7VpVtF;cklBW>J`Qp33+i8Wz~?Yw_;^z7;{qIb^9ey z+;%(q=1DTNGj&{QWPW$?(9R||`MqJ2sK~N%3S|;n;M(v)eXz6?VRhXLy02PB#uXGW z4r)C2lrg+Dmnhj!KYizkPhK+Rt@LY|^^aR-xBU#TN2S9cf?k0I%96afa-LGx>bwcn zdt8U&Uo&_9YVj*VP_K>HBT;AUhhRAvCqzP901OX2g*spR`XXa%3U~+8b0T@s;(j;N z>sUl|;&a<2>+}4sop}demB(%Cy3r!I35tA5+V5oK(nf3o&VJVNmiQ0`rWW(u^;C01 z@`i-8m(Kin<+!%Zl-OS9Qu!>wm3Nq`^z|#Unektjd(UA%<%5Q;X)0W(31?gsPil4l zc7}0AG+nkO-;0r4tP<-g^Nq+|`we05{o1D7cB(Inn6Esn;iOr82WBEqIrTqM1BJ9*!>$6U(LkIe7c`-$9mRnkHJO%yDU?hpLnSN79t zxbRTjx}0O+{Venpne<b#q-j|@LyXe9obqA!GRs{1#-?m5o>mKNH7ypMaQ=q3di*(0xSrB1 z6+FD)7_g;D*bkd`*|AE+4~kMZUL`-@omyMAAV$&Oit4;(K6dhSfX*1pQ0}AwXqDE0 zjcDH}dobCC=wWR6>iS`p6M%vL33YW-TR$U@ZlC_AHN< z45y5u-;%dPdL#@eNqY>DRQ-9x#%+_ZTK$xPrW7O8JE%ucb*V7%%81Gl<5qu}mcSH! zt9toZ!>D3Zm4dKt=X}|9et2@@tG|s&Ji(+vw!=sfLn1h^Pi)qs>VILT&oI!ZvAzvlVN2RT5WbVks#2dQYmndMZ$lv*XJEx3nbmTYsfI|+(#c` z1Hn}>xagv+V^WL$T5cB7e#T@>$ty}79_wRukwE8~Vm>PRu;^Q_u89V2$tFLn{73Q| z#BKotCtvp-_$uM`Cuth#RQa*5kNl<~vcVf8dq;cCd``m)oZefif2|h#$H`AoGhK5D zZ2DcMEJQL&S-b+`%bR6Gcn?X-LLnRsbU)}WLHr@=;Qax{S0RUjy*LaZy?oVDqN-jgK7J>R zsmlT}B<<%GUJ^TFhfP}QJiSAq&#+Ry&Gv1%iZu?6c7ZD~XIYyI1lnPmG z)0Sy+=Pi4*;-@r0VGNBwm&3v6<%4(#^8BWoed9sLidv;PI6CSb7`W^;T?^7#5h_Xz zc9|)ciktwG;VIc5_I*hq_(|upZw z=eB5fF%HR5EvCxsbbTvCU3cm_Mjt<4>NxyVFtItqj(Z_qx$>5>OU+1|mi6~x`NTb` zaAe3*@T2C?{X<3?g@{6lVhia8E5GuCbuV~Z3w+93w&4VY@<1&OTc`Z$-n{x;R_)8v zt4*hMn8>#~xhIQFT`H=p-<5uf7aJcmysTyQZ?-cCzu7$I(u(SNWL6^a&#|8^QFM3b z+x+pPB2iXOZY<~I*-Ar(C5F+1t|9C6Mj(?aZ-huoivFFkj2J%Bh)=JRxg9>_OE&F( za9pst6DQ=lzb*ubYrf1ZZtDSGeX zj`O8U05js6he&Xj7{2M2t!p`5``o>R)EtWQpX588!&@(_(bRxe~* zZ#@|r9R#+<>}vaGez;|oEOQ3nwj@SbSZ*GMfMdPIrW+eYC#R;gwgoLw%seOej+dnD zBB+g>##L19zexYQfuVt>VFsqr)H{7hInGpGvkm35!FVOCBlDLNYM8N6)j>NAObW$3 z5>$$z{K-7XXnpph#5Ue-T5bUi^(icIcWYIG+I(Zx!(RC{@~c}k53}&0MKSD_7S#Bb za4}|L1x_cvs*Wl+h1eTp-4bwKXK?;TPo+RQqq zu+lHg^c$g=uP|*22RLoqsyAdly?z$Oj>HL_-ZEQp#KA1;nAc@QS#`{@kKQj7W}`WH z_N^wJDmFBe3e$9q>zhtW82)Wd4DJ!tyvQZ{B}ak4mPxIymzd8FA{e zl+(5khW7<}_T{vG7oP<0_N>Cj!SHXl4-SI9`R@B%3bB#-eIxko@4R#UL_CD~mJDGB z6-7<2!nP6E%1zTbi-(wDE-9-{HgKEgYWS>o4u+Ce;)|O6Y|GmOhp&rkaY1XfnAlZH zWCin1n568qOV~PkfA8lF;pQ4$^H z-+6qoF*d`+`#WaKtuH+{Jh}47>g>ap(B*F%ZZCDuBlJ-PvB{~xr8}vp=!I{Q{K-|Z zvPA^mypM%mkr@vVj{6&M_?s|;Yxrl?CXxa^na zOON!^Fp2)QG)85gsToAo?KE04$(R(lg#Y-QdB2rTc&&5XyY!iDq_Qq^F%_SannZ9- zCzYe{5L^Cz9MkTdFT^5L4|Gj`70l?m)toW3Bd`OPwMH_;T+?dpfvuc3n*jI)P$1g* zJQcG0(aSe*zkBujuS({o*hO*^aL!kYIr%S5tG6r>hS=AluV~00N9B_lVEfE}7<^)N z&W%h*C5}v*n2imEe4UIG1&0W`4he}p6~Mu0X_$cpsZPCwlM5TLTRfMl>=#@GuH&NF z>^9DuQ>=Y;9#jP>DR@ZYJL%i2fBe29S!AvfZM#WtKwuqy-mOW7Se4H&U@y9tx-R5| zwcjfJ=Ix*mKjT9P?6mJm^02X#V@xe?FSn94%S?JHEOAllC;nzxERA0l@l{reYPbzFJCiEv*CXk(7!08a(Zwh-! zqfe)`o$0p+<#ZtV&I4Xp9vW#4l40wGz)DQB?E^&92;ZM88Y5Kp*b}ybh3xHZP4*^V zUfNz>hn^E1=(sYfKy~#FB_Q(5Q~Y#LxX}BZLpX$!CxCXPH&bY1Tpq$>U=n(#A`sPj zem3Nss*4)weSWSEXva$z<<;Jq<7{peNed4@7Gr>(l0SsnJZN?fJIc^6Z9O7Q%dT*m zN}p!eUaPo1Y%Tu)ihhm(+u9jm=j$6P=2(QGL-k*%_R9NRfGZdsz;x8~uzUaYd9}A- zzo~dc-1o1fb6mjoGW2NYz}4-a;<<(9g&XPTT(Y< zn@XwlMaK>LHs!48b%!jZ=(vteQvWAop%pd2FN1~_@xiyJCZ)Ilg&sDm1p$7;$=OM$ zRJj0fUY{mVLSGLw>Vf0z8Z?l*mI=GsyWc(47Uo>v1VWTF+v_WcS$&H0s6q7nhD|hd zneOz=!wdJq<~IP%RpmT#Q6?y`Wpu|R5OP#BPqZ(VoA>dq>Q()yh8ey&V=@o=skPG5 zO}@$jVby?ls&nB}vyIQ1Dcb$9u_t18BpH!fAF-^Rdp{`@OZEAb&w6QCMXzK;17Uh{ zqh(SSdd%QuDEqMW;-NS_;14BHM=CsyYGszIxy$m)RO9P9eS*OSU(AUHXSWQgeDNP& zU2{9ywi)PC{lCpA4&yzSeIUckd%-esxP>MpW{X@0n%zD6se z=Bazz#@2=c#S{W zQ)z@t4U!IU2nTTTq!d#~nj^_)qaPMY86B~#aSJ~&dv0~VEo6M<>&6FBkmK#~lJ6&Q z_i{{g0K_um8V+_@mOh{YV`^|WHLg|Qc!}@j$WZM`^78UpMWW!s2MAZWJ1=dYaijBu zDOV;PPL6XnTaq7FhsmE6;~ZYdk&w=LOWNPG>i9c+u$6nFr9D4Ae@$%T{2O9WNZD$| zg)4^wC+GM*8w|qL)rQR8zdgJ#ttwsomb6pkOY9DzaIwCe)0-yc#aYe z#PC^TOTzHvJMFvjqff=JN`CPrVGy*4`uNcR@JyB$;9Ud2ztl%psT@C7LR-)Lhn7%P zOl9{dWAJ7k%g%97)ClQ->kTf01*63CDg_NawJSWT&mFzrsgm-oX1o@stTHq!Ngr&n z8ilq}|D+QRVq$zt_dfI38r~5by4%4B$LwFp5qTiLI?EP$2KsXxdBIp92_JlETC+OX z9Yn#dh!Q9z3%VYSZ{f1J0iy?unJ3^U3}j5eX}&YZfqK5t++q^x_}-rpAFST-@&(gM z(YIwH!wJN~=kj$KG18_rG5+1HEpOcd2<67c#)Rj>B!}6uhlht$$N^uaUh`H_UFF)> zU6_6pzD3TMJ5>`U@Zxrg3m-8M8cP{wB%Td(k?p5Vh?9k2*>un+ESwbp%4G|x#w zmxJG!t>~(7JPhj-nu$O%%9UA70ffi+Y8IwHQgCF9~UBHxe!iLS;|Cm+u`N#hoZn;pj>+*$=q9 zI04Y(*-+=*Qd!`2@t$IwG=^BNhl>tRjIcLU#u7EVIY?V!JJh4YCBVLnNUcqLjBkl! z{hb+wC)iph1W>kd7&}`Y8g%StzDjU9?jyE%tW1=Lt&{1r`P}1!SDAlRekN(L*i~Vq{ zspf-QXRJ!yExk_cI#QYf`}yINC1jTf7j^EOG#k;dbsu=?waYcuustOp zv@NTt@v=xX#@?2v0h%xZO}L51hC^Go!!$1R3N6!$KZ`E4`h7DnHs&h&VrOTkqFsoe zKI)3BCpZbN>tUoe#lb7&=XCnA%X^~(h0GA|#yO0>{I9zyKTmd#+ipZiecrt}AEZl_91~hA&bN=NyKf%KT#&7Q&9sdP5uH)uEmBaym zDV&qwoQO0b>IH^UBAZFi2M+E{P<_V zf^D&ewLVUuz=-!A^oPy(f6r#~NZ`w!=cX^kzxu*M8t91`d)v7&n{it zZT(ySUG+RTx!Gasgy3^{i>AQNd)drv3mZ^axn*`fy)~k<-CbA?io;`_b zA+r$NO-Z?4Yx9Rou>wS~Q= z5<8B%YRZL;IImSyRkGjWwwK>s-Us)YkHSx?I)zZ+Vpe7Bdj)f+)tsTQp398($2*HT zRNcjQOYMmnMnaFa<}~&61{3LceZPO?xLoz_<0|#XhZst0tTN_U{!|tM4{Ka9Lt9uX z{5hMBkiv%GJUo7cRcE6eE=PVFc6ph5{CwfSU+?nR8$Un4XuDk-X|Kv)-Tu2o$*bYN zx6wKz@P!u2!AOWSGc#XKRL-gpdouGF_RF7=PS{>gjBvzJKOn2ktzJ&|BT)0N{mdct?S=`sNSIsbl&p&63!m z?x8_d=2zKvc9x6Be6!tNi(%u|a_f8Dn!r%-ZKk&##IEl{Tj`JN1^hpMZi+P`tG2{y zJ5;Yq6>j?=46hAazjwRq)RYtDjT(8|B2<;yOw`mB4jkE|<(FB8{O}5shklQvU}Wzy z(b6@Zb{8#BhdXiUsgDp0|!ftuHRnI zCv@%judYfs*a&@-klEh2Im3{fE=s2OEtlJK42xC)A|vXYypRhXYE#oPly{`@%|@JH zmLv&Q&Xc=+bIo7k&2;GtmH4A3q3@g0$#&r)fET{JymOh2>cL6qWzKh!H=jjh08G+^ z_NMFlCw=UZ4fldS7#@_fWuFOnk+c~vnGLWng-cu?iOkTiIGaK!ybyksugIdY9Atas zap-uqFN?CvYnvR2%ps*3OR-IhEba;mNz>!%63sJQ-7;iO4+l9QcWL~dX^~MSObFIQ zCmz0Ez|K@{%XNM>8P!WP!Uhr7Ja*uR$KHJCP}+`WzNHrW*fc+_zF1iGN~%h5w?)jU zhSqDyIyEuez3yRsGleOX+ZTD*-Jjr*C+i9+dqg*SOFIzudv!Y@`<0ye(Mzs|#wcJo z`u@RX11#jq@UkH1-uA|ajEGG{3Z8e0G0h{-xnFf&Qm)#KCPSM|JPp zuKmI>@dZ`Tb;Dl!ObiPOI-h~yCu+2EEX7P2@sF%L#|V8Jv}@roFnIDv#2*`9V$M#> z<;wn1auh;BC9WN4%s>3&r=e9O1>#$-eMIlT-u^+;Z%kT#x648c>@<4m18ny_%d25D z@`e?234Yp2?f1G0;U>@?7e1eKBhU#(PK+G)f-!w6u#Jz;O08_n72;y)a+WduBX?LI z$?*itH99mkT@UI&?l;-AWww4Z!T!T5AZUBrqc~%vyRE4ksse=p&uzCZhxQO+?$_aZWP_P7jvR^FJIFTc0-H; z$tf&&D!i-PKT^;OtW0{z5!i^cS&``gZNYP>I zj^-zH(m0`b+J)JN|G{g{J4%_Rb6}~>EfBhG4#E&;Sz*mK<#|W+0AL~>mR%Vv#efa^ z9gIo|PFRJrIo2TISiEH=^Mxco_uYYhfP9X2!u@_FwL$TmTe$hY@bH3X%sdm|YN)fs z4?iTpHQAYq@$nZF=92m;Y(f`$J{A2t2~zz|UPB`j%eb9X0oO0Y3IaRbRTvgS5dEkU zs-{%aEJhP$O_XlSO}qknA!bYT5{UE{Y@$zFZj;?=MmCot> z1xI>$%38La z2RHESOTH(eS9OpM$!RQpHLxfY zs&%LBN2ALK!}E%Yr+4GGrKHTS~vnI+;i?d~1K$ z;9Isry`uc2LWC-jEX8>8=e$+5dV~wlX2FQx4^(PraqRQ1uES|-CP|+=<1)Ll8@u{)hgok<_4M_3 ze?L8;&CGoeaZ6rao|=s!jZGm9xfE``8QMoFnMcRFF#i;=#cthPva&e2-pd9(2O8SP z-;xWFG;H$pT82%4{jGmkJ;k;%x1$%9aW45q;vz!z%HXhGbqOXm7`Z*qt!0s5b?3_a zq@|8uYXzAp3-j~7$BRfEe+3}fVX5Wqe$Hg1)0=O$Zmng!3QgC9<(S_`$+O3WDw5-ud zne1H#ZsP9AS3jKrY}&^R~+^An%XUNY~A=H9lpYA%V4eX}7h0FuU}$#npnX-!nta>;G^A8HzdPLLLq zy2M5QK;yso>1xZRZ750xzh$szlZAem?DXhkE53zDm6CG*A6A;u#l`j>7x(UHSy94` zq@l}N0;Adh>vAnOh#AmKUERABg4G@ytFLIHY1j(6xvt-KMX7UnEogTJ%Ptogsc`md zs*4@wcRS+M+6~!`ATE5``tn<$t{&Ws4HoVay5fGrtghAYw#J)_?V1l9d{W;F{T_sG zfG4LW9ZqXECXyCgmzpJQ1Q79u}$k$6-K>CB*v^-b11$F!~Nz{p=J;qen?2uFb)uYE*nUlv3y%Q*C z&)Is<7{Sr4*XG1c%GV=xqrE#{sFr`wN3}M-XOg>Tc2u47Zoy(wIn8CjWun>To0BMtYI?j8 z>NC5>AOQ30u(m-mE?`N_v3>6sd?n8wJUG``+UYUarz|vwG!jt`cp0W=S907D{H{i+Aa(3hE>sSTWu`;XTKi7t>y$g2F4n{hKeBUmtk)Zo1kuO4j zpJ+-}-&z%#zXcCWhV2z@(M{|=QhpS_2$B5LXpdQeVB^?)?7Tj_{^qg-eibK#orLJ#1Sd7d$cPF;1N+Abo4R-b#w!Wh2=1yR&hR6AK2a*|`J`~H%3vW@) zp@M_$2a@P#JHy)tekF+v1+RZ)0FYzHdrKHskcM^Om!hA-!kSiTSs=s}mP~vLy+?LB zz?ovAczTiQD6i%+2M34hnwq9x!@oOJ8hWM%NS>6hd(juY#J}_u?0NM%yw&Z!IDn1b zTmK4B(^pB5djWv^9=+gk-)}5*d%k%B>eYf-3$J#kdOgxLgz0w)N-FHLQvTZg;=-i!g|Iy+-M!7r-fM3Zx>?GNmZ0 z?@LNqMO^whc##)%Q}sW1Wq$bOsn}=0kdLDr$uNJ$)ca%flx-|tJ39KWDJFTQm%kCF zLYG|3mNK>CgVvfJy?p{S?WQ8t-qc^I+qD}k(^62{i~3O$vuZ&+(9G*wE67q4@#c!5 zip?;f0A|HMHuoa~^^jZK$Az4PoKnf$#KHJI zj<^UJWT~`Lmf5N4X_)Afy_>qX#m&nt)55Hv+kw>|>C4{8Qtc_hd`_0WC&0oI0) za@3X0-??eRGVo?LHsQuozV?RO%#b%`4(8+S6Xq>#Z(DU99v$t)mY8264p*jGVNBbL z0s*OK_2?AgPz(bDdLN@aB1O_#8$X%!iYGQ7_0C@me?9JB2 zS?I-&{`Q0&^O1*$1D|k#-7xBFkDmbHZe zDW*)UK6Vu8W_H2bZUq^JZ|D-2`7OjY?xBimy#Yd>{P7|o<28zOl#9KXn{i=Rd{8K( zWpOHOQX*Gtm#swHhh~CS1YvP63*Bdc;3T{>I}u6r?lq(X5_?rM)jEYK8`~fBT8!>3 z{Z+qTZX8=!1M|I_zH2eQ1)!(DPq;c*Y#m{mtI{rxUYZRr}-g6vHgUh{Lna$(V7lCgWrhATbY^PAV>nH9NJU z+C%LtgpdG9C<(Se5=bB+1ri7ru!5)&CeNCs7(Hv&oSRDXz#R{Gb|<)R6^!u;=7q93fvj12aEF;sdN4EpAaSrB z9IXd~VFFpc!J;5O_z3PZ{8;?IUs#%$fg2k=Iecc2R17|nsNj#e8MqBcfluHID~p+r zp;i`~z#V&mAduzB@*!}7^uHz5zkdPnaTx z)PxfR9yf=ZSehWfEeC&55Dz@$Xbm?pGqEr?gPWL7ukHV?)DdZ7ZUQZr!eBE*oPU`N zy2%S-a@ZUeb7p@qGnnOOGxN>n7F0919^Bpn`U93`WnoR9*|UTt5_5n6rp58kGN6H2 z!3@8dyUs2i>>#9lFj?kAV1)TG7#wFH0_d6GFac}k8751@@dfLK>A^8T)JzV;PsHGX zM>v01;$TTei7ntkXvSs&Q$}ZzfWA^gFglqD3D?x{n&#)PD}@0fIEsJ;)yYiSRyS{L<%#*vz?^;Fot^o*1;DCxAde@ zarVA}QgWz^J1Zd6SBxd0VZ;CuTTDSw-NXU{!e8X#A#ta=kwWR_=CH7k5E%g#Btr+g zxP@~4!2YCWWEUV_6w2KKAL>lAm>cRIhx0D4SJw;|HH@84=&lkz`LIj0L!9yY7GRV~n%an*YJSz$$PjJWI z%ood+d0JsyTpaDWbTFDD%8iN*!3(H7l(j^_U}2o3f%d)vggKK-4-uOMhVqF#b0@x( zZAKONiLD)ZjyNLO0m}?!hYF=gw!g>{&f&UpgE(GnKPw^Djf!$a2KmD!&TwdKE`yJP zwkUS6AoDnMB8GuMk};q+@^?+`)<=@?|mjKK5jALrlj*izl!{kbZnu48qIP zH%LHsbYTQ~ggN;75_tpo^|z6cR}a6DY8bhb4)#NXe;p2TJgh!nQ~Avz3>G#5C- zJ?&jkTr(Wkp5^7swzg)nk=E{Pj>MH3K(S|;xnWsUM?B2gN@V59g;T@KJ%cEeAZsKi zfEOUKp!xdBWKx*a(@_fd6b1@~ND9d%$jXZ&Wd_jPEd+d$k1)W+hXxC#S`5Z6s z1Oj2{%ZEO=P|Tg&5w18cO~U7xvjk3*V5S3$XoY525iLDAE;3x8d7z)Azn2xB=i-NT zV-axT0B0`GIRGERat@JNa5y|!pf6V(gtRut3rS8~7Y8Yd7!<_xl~7nz0^ZWqmoDRS zaqbu=e^LMtqs)pbu%!BVBFLdmUJlk`CN0nhN0IpX2m6Eunfv&KhQJBPPz#iW)JGiV z7~uF?2=%677ZYV|x&h&S3}#A_wCof#Wbpw3&eFNeVCvX2S(U2ggt` z$;IBH?6#&lpf<0xK2S2`NW#E}`m0XvZq zJ{}=fEcZ}HGn}s|(9z3@6&e;6YHk*a;JEmpFkS?-8HP?JP_3MVSWmJDj&mmk!2_UB zK=c92Mp1}#Ck&bG?&Hf14ha+r2!Xy1aGWRBnvV$PIl~<(WHeLkOA@g8T&xe5k8{R~ zxPeG+FiD6Y@W3!AG!`00>?wBecclnW4sI+bqO-Yx89<>qo4NZ5#1hK@AC|MP55j@Q zvBBsdzNfo8lN?|UM91O6Jj_F+QlbWIhwzA+SW)FlRj9$BZW2fd})q+DCpq`Qkz0nLc+LW3#pjrZtdnG z3K8Pj!eDa}!c!RRj^|s6-C-OjcWaCYD+sV8y89xq9s&Y|>&fyAuq0RrEJF~~0KAVl zKx%=K326RKj+PuKy3^4j7T(R8DfNL#I2Z>^Xb8icK%{_}iULN=qB=W`Pm$peegp!Kf^fhJLKy^0MRNy-GoWrmo_DrEOS!(a%=_z2kz(ouR!_1yy=@;x60yB3f3J^F; zEFd+gAaj}-jTq#C@)UZ7(RslF28BlV!6Sn#+*p>rj@&RuK8EiSf)QCc`VoBi0F?}s zJr&SC6prQuRuv)+BRfc4kbGL0y*tkhtVtwx@x{tQsA0k8EG*aDi!7v5f}KO@93Lo# zV#z{h3kfq!WNqnhNtDoKVwgRN3J>*X3WV;SAv`jbZGoYX9nefXo5iOJg%Spj<12N8 zkt8_CoY>|hq)(7586jg+=~9FPiGpO3A?^DBHDU1Ae1N@~qoX+3%^@r_j1hnqP+gsbNRb7np@uF|ZQA%}~w=f2%OEk1r!YKoNKdoQdu{SEPU_v8H>udJtUbK$1L9 zGI&so!MlQgEJB?HM4A&>hD1qVOevm=4X_Gx!8i)QcOeoFbRZ|#nTZYvb|VGy5M-`} zyS*zZAP^R8ErwC(L3nl$*BWN+;zaXfyM_q@!#F%gur4v2!1EwmB1P6dTr0G%h%SY5 zd_`n2-;7EVb0IMZHFpoQ zDfk!=YT+Rv@ZerzG!pnICx(!MxAF_6QejjJB-%NMLFaSreSC#JU|Oa%PQ<|R$R5E0 z7R`h1?&U~AFcBOSLpr-(n`Ovw9nt?)Y^m>PIw!AXrHJGDBPKU_3BmUo7%HxE7{Fb zQ28=9a;sMOQ;qM;ICu52`)_0N_z4*+9&nCVZxwhMJkFgXWT+`>&x$;wOm)ybp0ZvO z`ccFz#T^cI8eNAbbIt_}J$&{+<;?F`On2`?gz)Ujs@wUVIgfMOLVZl39}1MT)s8qs zTR}eplg6s-`8uqMePq2j$FwrKWu@kjye&;DN9%5b1+=7u4G}oB-QPL(q9Y!b#is78 zrKVMm>64-Y1woY4`tPR&6y^ExtBbf5;q%z{5Zk zDw}4bGjP#OTGLC@e(R&a^uPH!OlZ;39~0DVaq5Xg=m}=l$b1+KDQdkk7-8*SA+A#e zLfqiz33G>pNa?03TW=?Qh4eJrRLxHJTZU(f`rqv+&R)@V_~@DyT@N-12af)G=>aME zTu@UWJ$+`UtFu=%I%;}3ROp-&_-j&JL##g;tzDv)gJcP~Lb=YohZDNQep6?vU~-AbtH$ zeEq+d9?y{r zzduBwPf33Qa=<7Tn1e|r?VDK6%Z4J=y6@BPEA|K$X%(`M<& zTectG_jkkAYJxZ2ZA_(*ZG$^f%tTQow)vSS&YBUkZLLTvHt+TRR3S}RbaQa_bw9P` zd(%vdC%1HDe0x+c&JRC7)-qKaZBVKnuQxK(HKmK_49*LDja!A=rB#582?F6LCZK+)@d4SrkBbC_D|Z*_SR|i zI-YskLDDz!u&kxqVwDZ!#5y&BEVUaB;b)g_1g;lT2s3~#0IZc1NZxz%#>5};tKzyw z*ZC+L85T7h=+PsLGzAPzR3*<}Cu{$GyOp1{NVG)eEJ1z&VfPrrYn?FRqG z;Z*nZLZy<0r5(NNKJv06Rf632b-2Vj=>I9V`5IYEJavm=5bw`-PKAfxLcMr*96fsQwM71L7%@pJ za1FVJ%W8W!^s2Z2z*6So*0MCD`AT575_;;ErepiB)%FVq=C3ou0!MWKM43My#Oy`W zrfZ}Bw&bC78z#da9*v4dm+#z6)ooa_XX8yk)Ja>B)AXAJ zuRDLn`bzt-eoq6leBX_s9=mrTEv`MGH4*0?lvvJv-uQI*;R~YocQ|EeJN;Z*a5~T_ z{_3^45Z)?)QXj_XPE4Z@5DGh>)z6_Z=({=RSgaR`>vju?Z%beyZUSP4tByR^Aq!LV zWA)a4Jgsch8(^}2e|d_@d(*0KetldW&YJO2q`{G6AmWf>TKxCr=*V{&?ipYe-o1o* zVtI7*Q|spKCRK*l+}(O8G3kZ7O34M|nBBK7W1mKRxomlpYF6~BSM>YkBmdU^eWchH zulJAcKsKEULQzfb`MV~6O+-N{l=U@jmPO@2Gk`|n1I{%ZQ)44h@`mG=x?E+Q`x)wb zJp9=R_W=Fzy3|uSb2~nN>Uw3E%Kv?{z%yNhy6kzd73g{SlZH7!01?1@sD7RCn%Dw9lF5Km=v_Wc=PrREp@u(mme>O{KOo~0*i5H)9rnQm^>?6mFS^X+>bTA zw1e_Z8J)v%^>cD2^>hVs?YS*I7PZzZmq0=$10n0pg&+DWUUA?&20^4Tb_EPkQH@ zZC$X$!=h?4kdy!W2ivFRL;`Z^*Scr(S59k{ft)n4x|Kt9Gjh5-%r^Y?I>3vga>aF| zCE&n%{TBZxUFVGr)K*1a7RIY9Se`m~2;pTR3KwhzOyG&eI27clXb^yJLZJm*j73Fw zLNSbn${qmz%(L6VOPB0-*5`fMNYz%?kL{_)rQP_Pn!9txH>=j{I{oJP`tlo|>FWY* zi|6A6>&Ff&x~Odpk)`UZ&UJwNJ#ICiUs)H~+JBckpo}gad--r+?#}STJ69syayIwp zl1!`2w!ZV`beogDC{ra*^KjQj;vb5Bei6c0f99z1ni%2*Nqk~+zN35x5GPhWN8Vsd zACBS=EiM2bO!v%HV|@tcozM(O;29a7=@R0ot}-L+1~z| z?X7N-p&wrgfRbXoav=niA_yok7CnD~ver&J?x9qWecXf&A7s{c|LnX$qBK7&Skd-k z?iH;U6A#iSpVs+yA>;Lamz&*0_n&^igsU3P1h!^Aj*4Av z^^6|ja(+@8U=+LRaVNj-1dUv{pTCDuxN4m&sxv6K*ee~j2TiLl>T-LS&Z3m+CsI4FFuv%oR!lyp> z-94tY^hC?A_Jwl*w`ko3;YKZ|c4Dzl2@{IV`tfspr}4Q0?1Cw0ubtUN#2h7P7c15c zDMTMPzpL=&|VCXbMD% z0m9;}7aJ7#_mCh4DkVSULhDEbaYP3-ohQvwu+dSe?cVBjLdk}gYbeLTeTKZR-OEk( z={nDD_qkCtY-qBCpbKkjyHZ{Slh>Fyg89l{JlW5A-k?x%g$Z6Ytn+DMMMRJvntfu_qPII?wnW-DsHwFT^T@;efKblTsnQ;$OHUb(FArmG`AU&qw2 zq3Sjp#hpcus;A#;<*(Qgf4OMfNIlwlScjs4AGZ3D)X+stO1Sg#G%~w=S3It*tD~y0 zl-T$jRW!*Pvrd6c&c0RPxlXyWfUR-+GQPKGw^zE0ro86E?CO#Avmz5f#^j_dnRjHy z*JT|Aa(2VyoWtm-<*r=T__cj>Gk28Ia<5jGeC1u|?iUicxIAUwxzt<-CP^FqF#phF zO)FW^)d|VTcFVx4?wK`}C;3BJ2CR-ZL6^ENgx^<-Zf=1qto?z$QJ}HgWd72j55dLH z|12=)s)4jpPt|JLC61YbL=ZI_cmuGCw;L4XQRw4(XXA_a9)|Z*EOioVy^d%5m#!Wj zc__^io(;yD?IA;qK3*Zx9)g5!3Q$m7Bz)~(1tltG(DnvAY6KqD%Ru%}HrKEF^?0%0 z;v=gKUXJ^g+AjY&U*mh__f9vD6>frTPu&}U`)LwW9bpIFlpg}T{JG|`>uQi|Vge7T z(}M~4YYBPE*Ty8Ji-pINp&>%$fZ=Q0sZ0GkUKIL)ot|Rq`HPV_^q7vC>KtfB zvI9t1E!$TupOM^YH3j2J%E1odAssd36TOwx*|T#VZz3Ingo*(e+cjb+J~*T2!`h(Q z;lFYAOcwwDGb>0Pmm*Yvizts=Zv{EJs01MJtOx$UI3TYrFrN*x*fCULefATSU#`ab z-M(oAIABbZ&laGP$kRZKN=yCeNDCNpbl70p9prOiO2N4LGH5Qo(6e`SaX&)u%NUwFLb-^qDBh(@ZbovHzQ09pLMpVdb9+P*IR){s5NhBkL>);spI zUhaFWFSJ#dyDPu^`4yTsjLUNJ7+#y3oMLn<I zkplnNq0OzETKj+W9+u@_Vja5CY*?0N(ZC;w3e$U|gw8;#OR!VZNc0bwd+z{;e(!njh(?tb4s^TdvTf_PVUGdA;B-O}$v03;#FPqJ7r}VNdOVJl`Cd-dY zG+*oAUK$wB3x7pu94PHgc%*shzVZj$_uo97{yKLaZSU>6oyzc+kO(ap1yc9Nz>$02 zec%NlfB{Mg3)Gi2PQzNeRMF;-q|*2oyV4@B%keD28uP8_+`|_aI_8(vCv^m{z85Iq z^W^$|r9(R4fBjN!*29ogs`OF!))!iWM`P0)dJ+{+^?nC7WVvpd%A8gLP>;Ugls*F@ zgu>jd9<^^j+S+ai&LytLgwRBxKi$mt8cJp6BFEwEK~5tmG>oSIcv5+6Uw&yxpzJl zOgI$%Oa)9B5d(C8tA=(4sG))O{{n#JqrTa9!laQ`-;Bvic){g6 zguhRArJWz`8vOWmLs3EK$-s7ZZEs0oyykdW&H1>rxLt6EW^Oj&$AINzc=H=KWN;P) z(nQ&+u(;$G=(D{gN~t9td5*(}pCmt&qP~`Ai>KYstHWf}Vu&CIe+ym$5mO9AOcl>F zrprwid=%1oUOF*VDFz*Hc7CqOXnI_Ksy=zmikKDUpTgcOE*jh;zuH-ZDv^*gQ9C^7ZVDPvn;aIj`ee9bZhK&PhD=Af@=V*H$FTRww6{RaG9pCF)0pbnf z)Se8WjY6P}Uv(YMP_ZGRSh=F2yO5me$V29SO?hHvq5M)4De-#wX{^~WwWH`RUL?F7 zke|=FzAFlSU2Wvi#I!MVMiqPc0b@8BvcDbj&ehRCmZ=|?2SR@Tt%JfjNq*voPFf&y-Np=#{fce^sQ;FJl8_~748Apbbt-X-+xf9a z-EA&z>av3W90-?exbV0tsC}n)+bB2(*yqjsa91-U16wPfBl`GpJyP-~Dj_kk)-r7z zpW*UTwDN3J<1cQDK~ady#dg7yVc?-S4}K1IpIfNl^mgeXQ;D%s_w(xo_;Lp6R7=+V zJ$BII@gV3WDAp{3N|V*GilfP&= zT7_6krO% z+_!@oDRZEU`6|yEF8+L3VVGA|aGG*9b#wlj^ZJ&)+tfN|w}?uVjb3g(-QI9i^spbX zkYqyA5ICFLofWzgyK@(2pc%%80QI4XrKKdq+-JOg!xB%U<{?P9M2Bjdyj<)ipMI zZzf`b$G$M|1VVh*)a1`^H5+2Bt6|O&)jt)ZC>b-1kBkQ_CUIod8VL6Dl`1CEKQJ3d zO|vNVpW@Cf4_nV#s*USk_N~lVebZJQ+pU9132)ww-2M5v%k<=G%Q)~~M6Tg7j+Gk; zsJij7O}dIUX6IcF1v67bGfp3lHMElPX`krT}Y5K;; zFG335M)dae(ezntw$sl~9jvAdOwyjmQ)`{aJkc|@%?0QT&(Tn&5sE3kbLUeh)8X*J#|M`mUq@Nz=^}j{g}Q( zMPL|7FXhrKOQI+_GNs#)ctYa=jYUk=+uS{*L=J5 zX=ObNZ}lI%z2SCKPCjk#`17wO=d6SSuwx998Q1}oM{P)%2QDI+s$=yTUz=~>{W#Pz zOwmzhs-aR~2W4ZMM5Ctg$?Z8F43%fRZFA-=QrUS}Y+s$L80?+3!rg$BHn4tZ+9Zi! zi=87z#n8oR6@_D`5^6H1%CQC8$43v3xa2gcdfo0>m}|oN7TM$pjk;Bh`xD0QuKb(OK#x}! z10Zf2r0YY+dD@eTR-bnnm>w8K+!}kn`$3ghcH(&TyUb&~rOV-c=g-IDW%&)4e}8Es zmY@6}$7;z-N-U~~X}`*&BKR>wT~)Ti0iATl^s(W;dVok>)z{wTgvpV+*1tG8UAi3f z(cI(Jue_59Ke#MW$m4TYxOGpb2p1&7Z;GU!cQx7G(tb--c#uokerPAOzX~F#rL|46 zB+x}SY0tpz`@QW}o;VVFSNr&qvir@=4&Q2`u*|-qL|C5-rT0NReLjER#KTvtj}ha& z^8Tguv4s^4Tq&_IukY&jCkx8Ln{1Ny740~BYL%hO)3I|FK`(X`{Ql)$G}?x`HU9Fp z-jwaHzTX2Pyhe(3k7}-G)vnjR4>B43@;R{2-~D=}9a^W4wi0`qE}8zuxws^64<7~L z@m|}fG+p7qt}X@=QV0Un1w_R^uT3AwEl~Os@M0l(?={?(8y}MnHdU=@jzW)*4kgBz zR=rjeG*r2yTN6DB>yiTwfC_Kd2Fntd-2cx+4{OZfe!Vh9KDw@Ow0>ci{QVD7LQLCE z^+J<%|8SJmJE}U(mo|%krsR>-QD(2Xwr;G=8M$z*OV{cyy|c+Va4u9mhv`3Fk~J z4D@XFxc&<~KdS;uIq#C93R%iwb+7VI`)HMXc`&kXORh&g{odn+TGdhL4q0$w*{=PB z-(B$Px}heq?pWbJy#R}}?^qSI`SVnZgAf!suI%_k_S6)8mE(cEBe6xiK?y*PJQzN;<9!vZ5Cw`iU;N)c z%QLNDE8FkhS84b~+K4NfGEO~aTt!6Q!&<0?HAlbiaJuJj4ZFba(;7j z*QzMqwq0Md%0Aq^feRW>Zk_g>hF~2zvU$^<>1IUr?YyZ?Q>`PpsZAMq7Ed^d7BRy* z@+DVLZchUWuic36uzj~bY&7Vp$40f3^nggtZIzKHYo-<~yHen!D?;hJ)xMi307+8CsBRa@4)< zgd8#6F>##v@=20Mm}Zt+N0Kt4)kG~V^jq||2ZwWCN{SE7UqWBCy*%+M5c5TFY!8c0 z)mB?o?fr9EUGkbF+-?1|tPh+jXKQKUBG(*}<|ac!l)H4O#=jtw_Pn2sh=d;73`Ll#*x*Q9Om2SB?7Kmf3!bk(&Awq+v&xR^porA zI^%SHrGKA?cciCLQ|{jU>#3own&<;*`+Q(PMTpr3YJj{r(9TR9?`0v9U#J02a_q`5lb@tj8$b-wo{2$j zAO>lL7`IHvAZLYRv08C{wrM7%0j#=Jo6GgY{*SIiRNr$K_jOA=>p2Fg3)2@UG5!4N zlQw(n8W}CLQ4tu=hUo2GGiaOVp>1-0!jRBK?fNh6%?6ibrS#^DzvkAiI_+ktca8T{ z_Dj^`b1U<)!)X*aK;HqKE?qixKX6(~5GFQ<_*v6H_INC zsgCuYL-d_^|DhI{Uw&T?#GsyAeM#Q`;t|;mEB_xJu~x^-_ni{*4hF$h(OVdLrYEpt z=f)$L-E~3bixz)hau!0wOk`CWgO0SjHbne_lHaIEyQay_-(n9;+3(*=|GZN6?j>3^ zH00O1z9)orNhd58SQs2PpO~&#OuHFV$nnJ?QWipc&{ZE}k0*bdd=*qPmsjZYt!9zN zlE{a@rV@-uQ$Tzv}yExj2H>+h7<|%D8{D_Sr>;eCs|4 zk6`DzF@W?J;owW4t5~(M?-|188(&+St#dA6{XRb73~#&U?y<}yVXN$f_=DoL)&HeK zJMDfzbK*{=&V~dS8dF^qvaaUCIUD)9v=Pv_*3ef>s~pwjv|PKhBb4lt{8aIKhuzya zf{FadLXGmf)amXdC}x0`AkdsM(^~Vu`K`;k6Y(o<4POFzw)s!Y{Ojr)jeo}mZhVrw zUt{~qaKDjRk!DKNJP%@BUEMu@ygCGG2vw=h0Ohrvcde#TzW&<&53gY3J&&`($9LoQ z4RmEa2ibXLoGHRYZu4PjQg+~M=Umf27S=lQ^oqtE)3t}{da#{}p`GuiSzENCP1`l} zimUr+PlCcPfmHF#1No{tm9eLfVwr>IOTQHt^8s~en>9}XzoA-E{4Ym*D5$Qp%rp&x z_7{!F<%1gaRUUV={nE#LIrPuy14Nr6#XEPWn*Q=ma*FxQ>pk8Ql+aLebs7EsvwzG3 z?1>L?4UeY`1f-T@YGa^8_-&xhulK>x9Q?TY6Y=H5Pl$jZ{Pn=rJ04a;4aw#GKQ0Bd z8D;S@;qA8OY)G(w&FwS{$aj;&(`sn+3c{YLi`!vSwohx{cMSIS>Ze^|@wa{^S=qx| zbgHqj>yqwcm*N2{6Mgw&gADaAylhRaI1uyvid^3SVdFpwkew>=e`aOx@oe)ndZs6d zNQY_}wQUVhY1%GMd2jK=LfW6kZLOZ=-t^uZ@$Y}QBsIJVxqk!oP<~G{FKf^Ehvw@n z1gGuYkN8nrgK?$}{GXa14|w@gR;ZAst5w@C4OoV|VIwlVFTp|FNw=lRo+*aku3{u35= z8XqV-7hCV^`=hV6-XIS=epz4qV>Q~b}-JGw@9Dk<5^J-05=L~bO!tkBW8F}%s|#z&nOdG4_R zQ^E5h(JD0{ceg(@ul9K^YhOuIO&*P;De zL_^p1{vP%gIrW?pHEr??<8T`uUQ%>E>Ke0RbMN=3wi=BK&LV=&kMy@ZKHGH0+?QE% zdOa-k%bpaZID2I9l?(soyLrF9r%we=RDguBIh(k~DE=}wRtpyJ(l~7B`eWS<8yp^; z(hMkVTC`zeJW6%L)v5ID;WtJ;b+lc2UBB(3J|BIMN?7tao^|9it_`3!cGUL!gVZyJ$CWSRvJMivD);5vCL7b#RAj*t!zKMs zzkU0rkb=fwFt9zzf-Ak3p@M5=+GHt$<1|KeDi|{bk1`LR7}*0Z-X@55L(Je;EeOHsvdfz4q|zTL{JRRM+MyznGNF9kJ#!G8O|F z|2?C$tIk(k5c9n+-*j^Qk3kDLtq>O%*>;Hj1waG%zwUDlUp@kXYoqXQhDVXjlq?)Dt<~YXQ7Y z6;yDF$w@Joi44!SVA7XW80D1RbftetTd^^CxTOD+%}s{|(!HB7<5snpoE@9}Zrpsv z(f3&j3Q7ktIunum>QnfZ6#K^|0UhO~r9T3@A4D(bBj7(x=_MOotLalG@4Zm`+bvX0 z1E!JMxAbZx6qh15DlHrCGF-QB>uwJo4e~vdvzFGFqLx8y6Xj1(YsH{<>rL^=A*7e? zhtgYA6Mr%7&-{y^uj#MT1OD$pBnWJ4wVUTotHb(G^^-YmtY5z|MWXx1;^I>b44&KK z&-SKn>@S7IbKjo2vxe2y8B$bfy?ZqqkqGw=mXjJyaaR^Eg2KT+qekL@bH_NH7@g6{ z0tKl21`2%1mfoIDhps+qzRX_;D$=^QXvCgMJs$ASLtCy9!5NC-Ica{PEG4YDvNlD; zZ7J46^FWVvyYUZIA?kqH#q=Vu?0Bcnrvls6n+g|HjpEOdk zg?yWxo%O;w`K%=uf0Ao?2^3;<$oh{@txNWO99#3w_gL>U`605bHzHwer|JA9!}2?N zTUkHv4wG{vJ2|wf{E~+4G*ZJ>cM)uL==n|Rha=Le^^$k!EYvVjT=36|O#X!_Lfx_# zoNs(;)dmKX)IF!IuV<-kQghGztS0;q6{=dxMlM6d_|}K>M(g%|iF}p)c(3+p3-A-XL!;faMnEDA zj+~q}?vhH+r>6&LQoKQ#bJdpM%f0X4mxrUgpeng`RP~0~Z9bZJ^H-^qyT7ma{^Sry zp;hM2zHtsS`=mFR3exuysBO_M$NFIw2rdcmOVZDsK2J?noBJI8@%>?p1|ivGC%Ww? zaI3$|_D}q-9s3Fj3t!$fmj&$}{7|kE(2{-9-}cRo3m2;ET#LF8fHV(w9gm4&y{(RH z&cH1E_2>K3e5)ubDSFXRLRLl%z)U!@gaJ)zf9*7>S(UpT?JxoQwp_J9}f zCRQ_5HLV5J16$zm_`r-%hiu#bYX!4CA!3?%JI?Pa-!lArBVzM)?A%QG25jBtvUW9< z2ta1p(Fj74v2xTl!$1BKIa@XNW4v6hI(BP;LwVu`BO}88Z}I6hAU@_#CYkJ9U1I|) zZVA*`o>OvQdAh~I=;>CWZOV#%swtJV`o|4ezrU#i_54FI0F8k{dwu6g2EW|0AxhTacI;OLB%YisfWb-ARdPfGP?*?1K0+PP$%O(5uXamzgVW9svrpIW8SQR|e@ zxQKf%R24F(%Tb`vcM9i}l0^x7!^)}=SgaOdC5h-?Rn({rDt z*<|fon8Kdl&w?F>qI=k z`Px#2PkLsox@EU|PHolQyg9#J_vKZZFH60Y*Y@&G{C$y9R>Z8fM)It*_0y4c7C5~G z+48K*!BFLWmcpm?7w(xQKLK4+le56t6LA;&h+~$1R}&G;bu^uA&3krR-j?&np+ceqWLfH zXVmK3y&GVHI>OA<|9!COM5haiW+(GfW*U1!Q|+8}nnGUfGyqO-*~Fe|sPbFAN%4v8 z)ZP?8m?#Z*K@UUqTt$zmBTr%1Z}z{6N1wlCkfe39Y$B*W;xE0%AtTSAGg4F6{_2h~ zMNjok*PNFr{1|ufEb9Py}VSKpX_aJ`zsbKT>Ilca4rYGJR+_-9t>$k$XHJ_+sp zkG-}&;0#eO3wOujdSks9Nh*THfc?C>S*Lmw^n~17ya}No-`HpJrF1qpm;wixQ19Q{ zjlf@?63u@El=c;xJz+1zSGCj5ovY}I!)kcDvRGy z?g}+nyj=<9^EJ~hP?9B(HXC4+2!-m8PxFVuAU8QzuKl6p!ahk;sNN9 zwQF800QPbO48OyyJR?3XPHok;&}+e;+NaNTj64exKmhWdDxB)PN`r@eeW=0u)P5^2 zIoaS&_|K$Y-#-wZp5Klsju=^OEx52lRIArqxZAe>d2YOOy3J1NpC(DM-_xYQ!m7%9 z<|Ca2J8#qXeLS*?!hgWF>OX>=7DL{h!@s51cKYcat2 zx_!c3HV4GnUMqaaoCchW-WMnoy-YV$<0Qp$Ugdiu2ph?f{@}ptSGO;v;2 zK~T89-zKPYTVCVekoj`kkgxxm<=G=T@f$DlNlxIM3H;p#?U~k`=@qr+xv3R29D z&iFv7(#o%X;MCAV$h|XkB=00HYpTHeiJ{?+{HYbEaLcwGZ9V@o$7S6D&v5N5P(6B! z)^M3EuX*_7{`9L{T2MM-ehj9m6q*vjjw<1_JfeR*cNW%?O)Sn1Trnlvl6ZVBUFrzm z9z44+`TUMcm}77ltl~tCRJ`zsij!gl^MqXKc0U{{AIQIEgzN=&{1AX_#t26M>NETv zr%fmPA3ZYWE?nV7TbEt^<@9=ot39G?3uheGvFQ z&|H&s_3EOHHV_y7J`4ACL^YZ`H0$Ve6LsV);A{_qV?V+2+4-2P(jyIc%0*Jy@B8Z} zwZTFD^}|{1?K=h^7*U?qxT`;UeOP_vc3H`ZwMf{z9y8GJ0Wi~MyQ^%8yk<~~y&nR4 zJ81B$*2)${J`fQ5pnQ5YrLI95& zs(uNuJ8g!dGh3zfh}zND$(qF-4gd779s2)F1a{p$bJ)3;2-r}i!+!ZF7Uu^2WPiz2j|s$!56iDpWdt9(J}>1vcG=)`c}Vt zk_`Bq7U5YFVQvOKUcVNQ$4h{Ay4`w{d++ooU>%YCX zdwLPH~fa}@Y*_$yMEXZh3}oV(E2EyqxP`P#K-bqfp)4dedS z+3H#I+>?Y^J^oX&ss%*$;F*c@qr+|W)sb^p&o8@qRK4*ie7l)_*ZV0@fNt#e(KE)o zD|gIWv~o}ME^g*=qT%XQ@;q8G+g7Epd)1RD^w%u>?*H~4q_&%)k6Lueo*$8O=GW*t zB}hMN0MY@l;6{CYvv#hcp}OdbS~N&}R@7)+@gGml#bh0%2!?eUcagthi^K0Nj~=oH zFTn&){CJg|m&kmdExEz(*rM&k*{r)f)nd*j>-(F|n}9c;4T!&w|F?eIe>l@Z(4KPw zOjq{|E>Kf?y^zorJ|Ga5GHhT?3Sq{x#>eP7FGV-snf+*Fqz;k7H z_AvXdUC5df^J`zvV?SL0Yb$lumv8rdye!9RV%{rVSzn@O@3(qWjbZP?w>(}V zYhCM+G=Eq$ActQE56Ojq^eroy;J@tdJ8-^jLwu&9CsN*5mPKUC1Z z%+#>%_28u9E8U`3Ka~smGYg(Koc}TS%F`}P2PY%Wt(Xv=v(Us4t9f6^P0BuC z#GzHrK%kX^nfKSOGe+Bo6?EnvMrNK$_)tgi6wEJ z7vi%J+Yq$(uv3SWE51HjWnl4H)Vst-Jd4+7p{$;{p#CZe3EVImL*5> z(gs!?czp!d>ul@!WAg3yT=>LMcVJV2z}flqJnnE)+qju-GHLpS_fIdte5)t%bIwib z>9yG;ya{oMd()bO8@}p6HYz^yyw2a)vRQP=F+VWZBl8A0dvU0%JB4q(?jRbfu|Z01 zdYwuLjNdRHQFC!(u=iP|rO5wtSzOZ?Dz{|_mfP}Y0sjB+^%g);fL+_LA_|BIEG5#* z(xr5RvcS>^f;32@l!SCCNK1osOM@WY64Kq>-QDot>+`(tH~;+MI1V%F-hIw>u5+EU zeOsiN_S37XD2zDT_9H4t0(XF)qp0DQ|8bH6r(=fyU;jw7mz%4zshevXbz8ZNHttdWQxV&mpO@xeL3ZJz5a@?(zc3}`SR^4 zksG~|klbdHUHY(4PDRE_0;%nt-Ml%91SNZu;{Kh$lyiPy)V;nKH4GaOAU_ZN2aePG zuBh#|iNSGO(|Y;A(?B*ttqi@?{VTay4e-Eb{V87S7$%b6NyEqlJ|pU!PZIc)^QDRJ z_dJ^{`%oQet_|huac7*M)1oClkyoe`qN!DsH1>MJQz(7KKcnLsAA?>cUe~S>dl>pg==~tA{Fhmw7Aev%1&BBqo zp%=|SNmO;zD_{gz*WDjnsKjq?dKEF@v4F$W;wK89M6 z@V2-x0FfOaexOqBQ#MG-D1l${u*rJ2n&su?$_NzIwy4I`L?)xQLA2%eq#~NL7Gb4| z35CT;59Y+3nd4~uqC}Q58~NyOYe5l{Sp2PnWM@Brh*qK~R_-VXl6}Me3by|RcD1J+myQG!8&7s9t6EU02ixLBzmi??3YL6Ne_A?k_YObw)DS06F3S zGqgbA7-$h4zoP&4^A{aB3@fo+fpvUzi09-jc931?7!DkS6U!fIwP9JP$xQmN@aZfSI%kd(VxF z+do8E&QhiQA(Jcg+s^JUc{ZUUwK=K7OxMG}5On`SGlp$Y?7D zFGH$AM5gX@gMH$SI|r|7Dk!bF`71DTv~m&t0lU)U8gPnow+A5}e(ryaSbM&Vnx}yz zZ)dDYlGzOhH0;W4XO$QP4|6WHB8z>I7v>Z%|;&1&r%dEAriMd>Et-G?}#CIu-Ud%t1Kjv z#FlgF>C!e=Y8Fv@HtXVb_ZSm%1te)kz28!9ju)rb-d=90a)(vn_)l+Hv8jQ`Ntf;L z){jlW83;wM#VPf}Oeagt4uK2nI$Y^80&qsD!QE{G03a=g8GCl?c~OsnqYHB$wrdJL zcfGuXezVfIMHkJNPc55mfhC!!waIu}Gz6EgT&A$(m^(WCt2yrP;F07Y8cx@KMAOlz zEu7#^UL5$EgvT;6kgZ;gwQ3o%rO-pj|9Sg|edAwoB5hbv{pBXMaS&qpkkY#90^ko@ z%Ds^D;tWtU-b(`Dhx_{O<&p0Z|Kw{lc$Bl}(ID5=QF($X?fF%2~lezK+7D_~ENQ{$5i!XH@u+X=(IME1B5H}HXnuZD$80RuPc~t)HQz zf~8heAIE>af4u_?KfMlr5i%WcOx1Kn?fiKf$-$;TQ9z~U)>u(RfDqt=IP{&do^yuw z317)-l$#SD)J@L|qBsYw7xvM~=Q!`8jgup^Oz1U#c~@%mkL0Ow|l-PAcfH`)KAt=kdM%GJJm9+Jz~y zb^%=+SqpS`|CKEIv+VIs>}zL@+z3`Ul+LNyqa5S{cWq}WX5BpCymTCbC=r@99 z&cBM%R;X9@%RRa`sp*?4{UIW4yEmfGHfQTx5~%6xXQ=*>F5(j4p0n%JiqxLn`Z1%JVgcb!I3VO9 zQe!J_6q8j-qjff33F9{pbD{>uSAP4?TvO9b8SY%wWsHJRQDU@G;v+9~GHj#S&d$!Rg;(eYFZ>imhb0bsJXZk5JGe!kTPg(* zBODp+chK&p9dOsXl^Gf*GGoba??ChLK5q7w*)GrD7G++n6w!R9q&V5Nqx!pXTE+F& zvHrT>*3z-w71)Cncxr8JEg0tbZpN7kQZ-^b`->!u-c{uA)*9R&SL`8BhKbeP0aAt)~Z-Ynboe8Kmy36ss+4I3*_T<`81k6~MzLzlny8gJJNG_~KK zKUtYM-r{$B_>}n||5F8qC9dAIewJpM*P4u}0^iO>T2{hjpj_UH^Wl#imgP)5SzQ0= zL)3$xiGJ{fi>NbSmsyGhr$|+R-|;ZsGCbqPh!D9Sw;6W1`=&NhjixKbx><3Y^-uxAEI| z#n?%FE20|^5YTD#*kZ1}4m@c~x}!}1(N+4Y4M0`T!iE2tuk9R|Lnv|%Bc>TSkbnmCrqgSd}f6AMAQ%V26V&66AxdnSN8x0N3%44}Ajj~*=pZyai z$=YRq$j!VE%ea!&cF+CbDgxinBu9e6FK)9ZpKE|OWk~}}d`5%|2w+!0fdsx#NjXS~ zs;a)Rv@FCYBGT0C0@N9GvioI@;6V$X&4|joswlM2fquIuy`3Ad6OG#^ zoduqjOV)ao{z1au-Q%sreHMT?*>KP`VeAo!+!k@Q*N0stt`{~FWglaPi*$AQ9d?<= zv>g(kkn;9p%DM{qHoMeE+ZSCUsN7lmm6-!jF2xL#&RLL4#gH2d#Ef1%bk|06=}j=bgUO? zqKJwHXBLAFXNFAB=@w{kF)%S5L9plgGEFb&`Rcbw%!c3p+Eah~Q12?YEyMYyJbcXQ zt%}@5l`krEN!B~9y*X}8=Db_qseV2BrAzS!tz2B>)a%idS6}zB4&Hzbqiz!*@!Wdj7$`j%$g3JER`x5YOEz0j% zzpzuiw*q(gn#}w6@2g}}H%Ic&*nR9U)sI$tnkmNHSpGL+%eJB0zeN{8P&;{e&oQw8 zgeQW#pNPoFD#d#CLUgq^kqIz?cr25Aj{6Sk97qDj(9p1@^^U)Hyx5>XLr$Zn1M8jH zfX&3UC7YS;z>(#PFf$2<0!c6=4eum3I`nZ5os$bjl9mNE%Kw9dDrQm2^)-vJw) z(>&QqdBs!k`5@bVYm^`WzB5&UjV|R}WQ@K+SVCf1N%gBhmQFcr9Eh;6h}l~pi9v`= zH=r{>{0*UCYxcz^BJj7HioZB>H0Jhs;Cw?8gZR2SCZ(EQxWJhe?6*BvulCu}Rb4}; z3Wxj^>NRb`xkY{0BiFQKHUo;QK;{d(%WIA|u;7`Inb}(7a)|_CaKyjTJ=05YC%m0a)?=_NG`N1VD+Y&h*pA9X zzYo-P>V$-J*IimUdxp5bEWV6yYP@QmRh?rRy5%3MzMFVA8!b;JA6CUdhv+hv>okIx z)!c6;FLpPE=cyTl^<@=9mfg|M<2{SuY4f1R&hrfq4Gv^xixCq0dYEA3S&0?(P=UTP zad8J0^bH`pjJB>CqDQrjFRpl?0TV>58%%Q5BGemLeZh;Cdozm;sV#d)Mf7QSH?A0j zu0dFb1^jRv!i^O{CS3w7!d670*T^`mG`H#P1x`E#7uq_=)S&j!Wo}!WcIn&_@&?d)ExP#@JvIV zlU-fvQb+B$0?M9UWT*pt@JIlv&_fI0h|{Kej@RNWGCbl~-dD`I z*PNUUq)Te<$YG@i0N+&}pUEC!>Ts)@k+E-YHujTJ`t}7!W4~A$Zzyu`vuJ+6^di_d*o8{AI~%<_kqrU&Py`GF&$9hiz3{aV2igq6z6%T35 z?`=QK7O>wm#1Pb=*jN*}t9nKySrIbhxD-st*2A8gZ(SAu2Z3JkCX)}& z4$#^Wq1$D#E65udt@{ba)VUKwp zK>$$gg$=G%Yj?kd4qTrJGn)JiK>X3=HGNR$(2^nYXflqa3w-i#Z=g)9OSSwQtu^)A z<@F{d_YcJh9-G+;id`jhnw>!T8ZEZpUy7A2IJ|e0t%&yF4CExXMtS%MEDdX(S zOYSc){=m@}vn)i1>yISOK>jn>3tlV2IBEIwb>Gi|sR9dqG#TkG3zqV!+_Ohx6~8fM z|HQ(hKs&Y>S&oS98=o$kgwFr~q{2!5#e4PLutNiS*;saQ%eoWQj^5rv>q{TDL>f8% zX_^f_vi#(!z{<_LHk(MhTKP}tx5knU8$1lP{>Nr2pc-18M)REzV?mKF(2#^rI;b4z z^U#jGM&$d<$`!EBNaqrNT@ik=x`y^4jDUbZMI(ke@~cu09kG|PN-e60F64d0jUC5L zVx39%l4`2r(Kh=OX6bkD9IVvO>t7l{XPS>#v8`V~2OC$};@j(19>SKgc2jy<9oKqT z)7`?cx=KPd2r%p)M|3D{#Lr)fuWI%N)jt_F7HGz#Fy2s543C<4Phx zN`Ry--kph|VSBMb+wyMBUi3n<@0}>~j<7v<7i-7s2|_!-%@`kDL!R@*wI> zpS&*iCo0Ai9?VT|p)IPj)y7(jccmO;V zH9a6;?A@vwowc;#yb1x^>6#35r{Cnu1ozLZ_Tz@CnBy9U+Mud6ZYG)b>*;G*k;Zp+ z)v>rKJ!rRjVf3+>s%*l#5aI_>C)z5Y;?HL-HWv=P!d(n=bw>=p=BriDtdG(aPs?>@ z!vj~>HlqsHi1=w^8$W=+%n+wt)4Tz3ECmeP4K+(m+5 zz_^KryZ@){knq6;k|R2saY!Z=ai8WdQN}c%YE9z;-=;AoGZ!f)`B81|%Q$8kW7_=j zQ?coZEMT;W;vCv zPJRqn&EDiB*c=J>!If1G((v4XIB?~^iblD@+QS+=erVM;9SSg_LyY%|76Su>LGlvI zE;H+4+!G2Hp<<+#(jY{Lwkw7$2Dn@)5C#|xW=QGpbs1uq1;4D@c8k3)8{eBK&=o|? zVYt#6weomkE9aZW$8AvC916rQF)j2n1Ik^>X*=PG;wmYT+9RN){$kOJE(467UKQo4hojJn9Ga1UR76^Akj-!bw37x#bU8aM!n zU)ljnp5JKVCEn2HcYHz5UN*7+K{x!oAd7jnCAcG)hP7yR&U;#ck>Ic<_8wyLf= zavJOSY-eOmMsOTHB$@e%zoM|T!N!bphV~@My5-qbP51DC^LqV#RpYPZ9Tp|f*LB!C z#HBk^<>j+Ov=L+VWgHdm@_M@j69frThIdVEu5X6&rKqmez4Y8D#@gP z`dXVFuCew?CY@4YQZ$n%J_g$RW>|kTIlhR%CWk%*e%@tuNQ0{^p^Ztie|huET18#t z&uLtKj^b1&d!6QlNQSU`T6#@FA5` z;E5@J^RnF#O8f^IgACRME_sSG1aCPl|N*nHLN@%>Nf+ zDjWwwgu)bjekkrq9~sGu?={aqXHK0hO5JAX&T%{aa==(JSz#&fZWCQlQ?!)>Kk>DpUf8&YE*BX`yt*jSHGa-(}fV5LYqZHjC>G7Sx4Vuy0Y6BZ5-T^Oi3Q#6Y$gyDLN=r#90(RPv(hF$5HfF%yXB|(bhrV`XsOLNv(@Wz!dtX-$8)v|&w zSg|50cJjq!jIn@5%X%AHJ zski2(=SUeUyi2aw7gIm(2oU`?c1jp)_(iyMWn#-gR~3UQs{xy9m`vhKXY2& zN-AYJ!h>BIqL#hI2`TjOAZAf*>@I)+VOGwznm~ z=PdffLBgE(uTFu%gey>&3*-TVISgaZir=WQbQxgnxGPt*%Zs(d%A*&Pe3+8;Q_$1` zvj_nT;EZV3spLQR^zW3{!<@Awl!grsp{tNqA56u+6!i3O_uG zTID3y)r&@7g)85x`8as0JaZm>SDU4Y(apFxOHEyBfQy8FLjYVyP$(_e@nr+|z+(!~ zU2fvBak-e8TpDQep`qEv&cRXegrbg9#uSLNS2hV^oyCNlkAFRWhh_qKI0j=EFUnF# z*4fRz0`cU4O~B~^zBDY?yhc5Pu6)8Gk5LE8mqZ`}cB-tB z;4BAYZ~f`vZiKy+m>)AyVj+_K>Q3m~&Gc>%j-B|6!W6eC4t{xCI)?q^-zF)!jF9&{ zEf*o$=JMZ`1VWyfu)i`TQ&%dm-0d@^xuY!7c*e20;~@J>OOVaYwzom+Nmkbl zX0yQsR*+;<+*Nti#ri*5fUg;5=0yy8x-DjL=Q|C%G*&EX`bLBkBDEWHJ6Z8Qoh`-5 zaY_@azvo*Gtfv%jyi3N0xqpo*KAx2(`hJ5<){Ux!NN;VuYnidi+5DC3SUg2ga8F+( zr#k^*>`f&UEE~x9ai_#2*=>}Ol+5)|eSgE4z#rL<_n{TnkdrqP#7y%yXlW?&xJ_i> z5F=|((Si}rKYwoE&)3!$-z66|a~EmOFO(*x86n;?mGgnE9;YsK=dS)l@rbJ&M)^8g zh)St7XP_x)UC5{1U0cJ{2~!Gdy>)l98`fSai3p;2Z81@pjb1iEZYeS_Y%b0L)&!(I z(Qm|c=^r*U$bH&HEWuQEZWtjxmvzIki$K|km>bezJiFk0bBpl~COv#!4DKLo@T|>u zPd3zPtEfa+VWMKQjh*}qDAHz;T0u7oU#{k0D_s^otQwim5i(656w>!Fwx_BUPq!U) z<8*K1tco*Uqkno}Ug^4)iAZ9LN}M*FTh$nNIa%$Pk67ml)S5}NnN`o~(oQEQAc)OU zc=o}F-INT^<7WBFe$QE5%xjQ4_P zC0;+u#xL=ml%ZnUCU97t2VOrpEUlweDIQdr)2G(+eJH}_U7-dZZ$V#@RK~+8CI~eX zY07bz?I=Kfa;1hw@aM z<&)TEv8Q8u@;Yv(Q56MeKkAc%3M7`fnznV@wCRF3^TQk5Y?4ez%g7i1AZ7NHq(Jbq zpm_KyeurX?hAV_D;*o{r;UDuQf!4%_9x>@$9}wwB6v0+)tXo*GGHRRW4}?O%7Nr7I zjAqO7wumA(>w68|{=&F>&?z!%>Xy)ktwUdnz_(7i+?$t^ZruuoBHofZ9|S-2N{+pi z75FXQR$r(3G1ZiUku{cum%os3hl2My%%;ueqlhu-O%0!V=Q!SO@ia1|q&yBsAbWf| z;S)0;m6CH2L$XUqhN#nhqTQ-22b-bk2wZ9YDyI3#+Hw-lL>;o%lU{ zLS{I}nrjftTpQkFThN!KOL0{d6_q))UxgGNdjnA@J*l*?>2HBMHYKI=YR;W@Oqh~` z)rD)mVQIZI$lDdJeobcc4%@56_C0KP7$&IOgzNt$a1D(jgsj#`BBV<=OWD`+m!YsD zQU28N*R+ZcRW}cujeJh!aOXt??TUhaoEz%B(l@3Mj4}PbvU(9-OP3o1$b&Zq8IAy% zUM6KseE6C6tzJafacPfzsVqI3KBFn9uD$98(;GCd=M~P)*ZFxfL8jGS2WlASgf5L< z8SSC$^xgJi?6UC+bh;1f?Z0BaTxo5hkujP)PbH)~x*eyTK}jRg>}~RYGzpRmKtAdz zo?_RQRdRBpE3?J=n-W6h)kNc#DRpK7t6QkTo!#hJbtghx3*QB#@dG;A$X>47*MPwP z@(DAW>DK83f{(kE9%(e!KlICtU#3FCZl-jv7-UXcy(X=!OztKIqw+cvx1S}>7ioJTV72-SR@qXD7$sYZfxyG-TH#vL>7=o+I$c*X zR60`7dIf!=0UsT-mbaoRpTm;^z0lFh-;O4CC~~PQ|A&L%PwKFX<2Mf7)^e^pxfrf@ z3z0>3VXh)Uai_v5LzJ3Nuy2gy#nkRMVIq|=S3WUWYgM0cM5$RNfA>G zZpGWv=Ov}JHtz*%PT;!kc(T{rbBM2;(`z!kS@9D-@d4ilo~i(>1t3xlJ?Q-c2%ib; zlE_E}(4ZZmU^cYYCHIxCor_0^IY!4hr_^)+s=1OzK$hgRj=5S#WWT+-`q2tckrj)^d?c>%9CO z2uD&1uPo|h6YD@6-a|Q9ET8Qm%DPqg=hF2#b9Jkb;|358?~{6Ei>KN4@=1c+>D!CV zydq>da?*pPHVgs}Zk_K0Md1=;kFGvlzUgs7=6ob9(K>`|9p9e0+|V|l)49i*FdsbM zJ!i-7q3*?r4jkIxJWG5e0lS>VJ{{_r zEc-}jB|M|BT3@Mn%X_l%3l1fC%egdcE>kWNA?7q?nB-o&-DN}fEq18A`?o+GNN;eQ zXLKpvOiXQT7^UxR(Dl^|&OvHrduS4q>vg|W#7}U7xiXDf^ zbsR`VYKc(-fv#?Y`zWeOZvw++(y+ zn*GzGr*~XO)t-wd7p+YCGl#AiCiijJXjM+|u3ayH?r&wrVXh1{9cX*lC<$})GIXb{ zTao#2Zue<25}*J(yuMAYJM!$!?VP+5bEYAKKp@W9O5$c|y!6zRpA)h7N!nuneCb7j zzj_luuNJBxsc1)P^5{oHT`I~K-lr*PIDRM)X#^z|21CZ#q3#+#&k=3LG|yh$o<*N_ z7Y%G}`}dhua_!aOGJe|#n{f_BVb48#m#!0PA(7BE+?>GZQA8slY679Zj>`_0-yP{Y zZ2y=c5g>;e^l$Qcn3@Wr_=A>4 z4>yNv{WEdchrOdr@Wn}xAj1KA9-fL0#`N=Z$AUpq^%{JC=6DTdREeS1_v>TQ#hC7*IAqiRPoK5Dz1FocltuE8nu=6hQj$mA43yYpxmw4UXCMrRT1a5#0dNbtFDGIb zaQkw1`ikyoFy?2f`AEd@Xh3ST>a&T5X;F*$to&ZbA#7rE9Rm6I(X_=0<1dLZI8Oi2 zWfak#7MKn*HU+3GTAz_Ftp(aF7P{AOPgNAX;e<>LE!zgQ+_BXiE3JGV&!!QFlF&?f zrYgZc2r%SRbkY^%fpHP$QYbJz6_fyRD2)j=gPDO!sA>SyQs4&qW8#4RbCLr5=-gub zqzjx(@eaQlFCTFMhyT$Dc(;41EaG-t#q%> zNmCKVZnc{~&nKRC`n&ydK$yC0OY(}k2+Pom=E4%XPj3A;&9+GLFX#r*Q$K3AdMouI=d2yu#|-H=NbmC0)mH^0`4WVF-dC&cRnG`2LY!4Q^hT z+$bi!FNfWS^v8<^Lc=uH9_JWIS|L7@i?Eq7NM z$%pV>5N-Rj9txHpTNV+?YsOWc3dxbwzXl+)gaSo3%h0*TGLdpX6>ju}N>9c7da3f*s^h3}|27mTOU7-T&t z#QAig@Ba!dOW+y@E&2-l*b;gqqI)mTwLSqf00DN%&(DuG?TwyZ%Ir`<&jAC3 zm|rN`;X5?!h{5>gm;8;j@YVJ!6j%z4S0Eh9(hC`E`WdZgTEpPgSqsZ>=kRO=*tbrZ&QzdxEC z#fQP;j}Jw%WYbDfb8{CzT2wiao0|pSV8hjeCRQi(RR0F6BEE(q$o)F+=XHNoFyhU6 z_K#XGli5Z_M&wk9LH|x}btBNQlWk^=O&mI-toIR(9%9dYlTR^PL_ro$ye*Cbn}6&j z5r)`0`dV7P_Zan5MPmNC-Y2_P$g?u6k6}yCOO+Unu!-&itXj)B`A2X#w*w~kE_ok) zLhvG*h;C3g#@TsTSlEDJ)EhN5HM{|Odir*u@4P{vG2Tu)U&_+;l{x<9UA>nqzo_R) z`h)&)A5?@V>Lg`9J*3JYGbEZR>W9%84)58>U5c_jpFXS8w9tc1Ug^;gg|t6(_ht$& zv%c$$yO=s)@a#Tso1HKhadxjS?Q73v0Zmoo{3P&bWliye{{|5+MgIct?jZ-7na{m< zkScC2H4&|)wpn1tVe<%4i2t;cai~C>er_36Xt5iAt>86|kYgD4gJ+E&P8UY93yR>= zWtvasgX^^WH5vyd>+626xgKA;eoBfRaULEX=A4M5ecA$~OnD@CTcA>kmP#2mh{_bq z2onuMP-Sz+6}wmVh7y96Aw+T3O99#SsJO}G?)Ju#dhxr8j3wsZpAYHPQKovJ~1tzk?U{n{P)1hdK*CJe?fI5z#e|J6CNYTqEKm_XN0L5YGAd z=~GLhA8I+r;|3w`w?+#J$}#bjxO3VZ0s2n^U^kn47 zDNksa^Rc?fuz{2e*!5Fb|MF)J7pUHFAr6l3!|23`FF&Y4{;(OQF#WXKVJfWZyWC(v z{j0D>HBxPyw)1BM@_D$#K<{m|b#O9UG$Q@ytKrd6Zrq^3p&?);Hixo8IB!9(2J4HJ znC7l7Ol0F&_ctTgsfY}-T+>=IV4sE)q4^Y>hZ$VpCAr|HAPkFKKSByB-8o&(D8OOA ze2r&0YWRdDnDA#q$aZrcj?jX=j%^W*X_R>l<9_9&ZsrS92`aE^del~9h?nhJFBfib ziz+9ui2}Qo55R-kKREaUYB@3rOcoXvf|tRnA^%o=iCndbbRcrol%iqnpYM=LP^xnPAZ%)GZmvHD6(LYUVH*4m zN<|F6soc(bd_Mr5t7krfzU5o)YL_7Hbx}&?a3=R998&y{s9A`5XSCN*h6|>9J=$n?J`x!;5&HbdRX8N zgQoKvjGV!skU#xb{)EZ-P1oaw9O)RzgAzq#V42Os3N29 zye7RJSi<4ncSrpzH{h!Eblx4M0OJ+D-*hsjLr8lckpo`Et|M4Qye0=+BCP#JUH`^f z#P&M^tnMjTU3VCrjH9}?9ZG8!cl!CTrl=d&7ib%l@=yuYJH*rXooCm}(Xr_CT1t!+ zCy^A+J(9*|v_zLVuiiS7CV)}9PR$y}Q4L?M194z0vWWy4Lcn5@b0c>vN4d(Tdwjxn zM!>zkvbTSikRCGO_Gq0%1aw0>|LwlsmP8$K593)xqc{*ROFy=3xcQu~S@Cq~Z}7*l zt)6%uYA!AU(9zkk#$v(~)evQ|9OHl_p`@EEyZz!(eWFV%Fv!x^M1BJ?zM?x5gi7rBl?5^P22D$}VD+aMOO+uZU)M z=C(!6mLbL2mFd`!(=RqY|6R0%upP$z=srfC05qb~#yHv&#`liNjTvQBP zAWrYR)D8JW{?ydeSIxMlaY$D@t&rl6fT1P<_%5X%g5%vn9mu!nf~@+0Cm$Z#bSDbD zgM@)EoSLhg>Hd@#S1DvTTkGT(92~Wc5k}9!@%s&@jYl@=Kt3uVn@$kd$5FjMUmmKJ zeTY(TPMJe`Us04tNNd#CQS9{*T;W*50QhP*NgaT6rtzY9VF+}-2wJ)DUMS>CABj~h zRpJ&^5h_q@j)^mQl2*j?J(fxfIj{M}FqyC0pmPZCAmpYE23Jg<;LY2&_`o#HZ*2vF ziuFR;#be6*!16;B6TvMQ2^&no1J9E0ewU~m0D1Jpb^v#Xa-jr6!^S_*s$wD4%me43 zrDW#L`-6jn!Q2!KJX(ORgyX&&<#fnhqq^Fz&H)1z^DV5Y_*=7 zn;*{4&k>qbRdMa%ImU{}Wu`Czi&(u_aWfAV$@lP|MK}f0AaO`n07)nBUMFhWo_<^iU{DQc@B+Xb}P^$72U7#nI8x*WGfnc0VI& zr^5bo=On?MbMZcRV*x`Ch8KP=XMmWsMMr}{kE#2Y=Re#`&$q++BRwm7%sawq)asnM zfaXEu6>Ae){W%n*^}VB*-bq&^9#H)|Q2>npc{r$r9oV6?@8Lrg6yi{~3tKyI-WK4m z2EQ>CZ+fVup`Do0g0oswnvkC>ElNg38 zU;XDyna-=24-CKnCd4itw+;(@vG#8_LOr9wO*E5=DW9Si4a*jK{r6gUP9Zp!$QcQ~ zpMz^tcwk_~gR6)88PD|TKemIL2E3S`{yd0reE%om=yWslS2+=l;|X9o_(*31m9q;M z|6vQzCK7PUAg@b?%+wA5J;UTw2JXpwS%14R>!2WN3I_Wyc3xZ&kNyk227}Z0-;Txu z5B5K-$0I542+RGOVJSUxd0;RfgU^x;qvh{_cJuvvydV?;Gt?N&+&Kjc`w$ZPvZ3!x z*y4JeNk+NvNiwAQo^B+v&Kt5QpE?$cZ_YVnL{dnMDPLKy5 zLc?N)0H-Tf$tj0IOB1T@_?*thy=kM?fcIVGH=G7*)GOaVeF8W-Ny7Wb`_ZUS&U^M) zT-k*MaB+L$&fEY+tv8-}4T^S{J6`Ae!U#VE{H=A6lvKaP|MObSDV(hI4S;)EN(F#D zNnvR&JGdrMUW23h?TX83W2K3?P%`oo;=XzrPQTnu?VW~c#7EEE z^-BJL*wM)`U3X08#jh#)7M~NFzxY!co?wxfuz?mTa63#6&)q-t)((7xP-^j$g6L#P)djPJn$X7-3KUO5D0~+V z@aA_m(l>cIjb*{11;rB8IEsh0C&aE^<^1=B1BCii>O1uZQ97IEa+5s7kgWi-GBT z(0(3Nx9X>o2vI{c7KXjg_2106&DNt4_{?|uZN6VIh7#Qgce ze*Rt8QsJskSyT7x@%2)BWoSTtlihN(acXwjJ$Iek{e#1=zP@W7mKu5DDsm4upMSvJ zr0{P~F@^iuS=E~LObxx8qBN}&N3QYZF*0COxFn;9-^(I1X-fi2|4Y;OH7_`x#Ca90 z|HqIQ>bBT?|3uxmtqln+Y}T+{EPab)^V9h@x!>2qA~HJ?*2uL5wb568zay%Fvljft z^cp3te?mlyU$Wy3!lpY7CklDzl|J1UCvX~+`?wa^3l&bIc+~QwEyXh3PWP2jvN{@I z=akEXiI~KpODk}HNmmh-*Zvm3m~xj?_&L z(y_=qG-ltB^48&Dggw9^8+`CGRcL-=VJE!r1k1jiRW`y>U8Yauo7YR~PwGW^xFnN9 zG&S4P!r;_*IP@`hkjDCZL3H$mdoGRkB)|auf#6-#wcBcC0RtuA6BsPjSc)plfBw$V z`7+I6?ETN+S1fHGH*-JnpZ&74{_N^#r4`F7HW~L-xnH2GiW+ViFD-lt|D9}v+Gm zYyy>59C8zoR(hu2R?h^v31Wd3QjLzNEhl@#J~{0Sy`nl&gpWIIso)_2aqMqLR8tG< zA7No(Rl2v3?td;SKRUBr6*eTwTqu{>6Mw51bP#T#6ar?=`HApTJaG1S9cRk6tHC+| z3zW)vLUB#}7{Dm;NEd<{heKb$+%%B?;GFM@vUiz6@~t)V>j!B#%S5y@mn(aC=(=nk zj!u_N%39cck}tiK*CIY$Ucc`q=fHk{|4qPE@%t_0c6?q(#{Nmi0>a#L3Ie^~g@FAG z0$Q!<-*AHSzt;%&aFd>XZ3{gUG=BlobUZixCbd0_L(81@Z#$88+*> zZ6be)^S`bWaX^I99{uTRWm*WPD61zYm!0$R^Q4z0cJ;0QuBK-f04GGG`HKPH*Smc1 zzm~@WF9p#;tp6B=x#=eYFR}Ec*YfWhCbuNJ#1r4SN{zAuSYaH@*7P!o&al(Epn`i>BFc4Rf%*zE*hlTm%iB}BCK6{f>W0nV8OUnBU(KxZq>mv*&u$67(W| z>)SyLH0-_7dl^aO6WICRCjhQ$?|n=hJ=}6p2=SLpbW;8rqPd^DEiJbdYK*MEAK40C z-TUJ9#rniEzWe!?U3Wl~2|X zY8TEqt3934(f9XiO)Am;9ot^Z(S}f=GrDO$W3LIZfgTSk2tbrV7{_;RUz3_`x1Zw7 zUzwq$6k`I^wt!*x!PHbwoZU5Uo$?=Yd*<7y`&lGdc!0V;)7D{$*T`0(ByccP`A5K9 zkbC1Q?3pk!ys8YjH>WVu7DtUlLm^;q&WcwNtYCLO-zTpL_Y6SI{lK{2^xfyj%R?Q4 zg2Bi)RmI>qmJg+q&gSQ=jX>a3J2{sf&1OnBj+Q-9ZEG@R~&4-a(Ecja#m(lp? z(%gYBh71k?Y5F&*$^XWR|9|@~sn<4e7OI=%D^sn|-@~U4V`O0b8#SiIfWfj%36w6C|j$;5>fgO*uzpn z!F?h4qR#y zfAfD)_7_l9zDw9JE(ijWn~<)}CIl%->23*?5)nb^?(XiCE@>qM=@1Z5P(iv=I;Fe5 z`@!=&=X~dV|7(5!wf17^V)HzA%suzaHP_5oyq~QLeXaKV`N+HiJQq|)T=ABADSyXH z(CHo9qq%HouU925$`h#ToY4*a01K$a6CT_YX1$Jx1MB!R%!`Re67t2=NvS5wc0=+XEJ zJuMRpm*UyXLUH1&R{GodtY-73rj02usT_M^<==fNAL)IW9x_c#pFE=ai&xMLw*&>< z`E;{AiqQJJcX-Z6a!-F_IWaaRskNrv`uB@|(umDRq%)Z!R@hSaLOZl2LH{Ik!hjBq z$~2>yh%IVsb2Wq=p-ab)cPcZJa13$LYnQ6sUIXd4h2w;D`GeMWd)wX%_o;7lm((xY zTCH+z+RGb(4YO2Z`v~u56s_JEJC_NSzQElI0~ee&XYsv=Q0Xy0c|*BGnw_NzTwBCG z8rGT!m98ZI)V=szIm8_ziT-M?0=dcWR62(wGj98(AXs&JKJQ~HOKY-XEJ%j?!Ab@3 zuuUN+Z2bvEuZYjoJeCrb3noytHstO&0IC9ev4e@!oMp!Vw2D?N&?GEI!+x9<=sFzl zvA#bhoj{vuDJBPwkHgAJK72**8GgH3180%n!tH2zNM?8b}TbwflD=IK4xOTllAWUkHRAQdP?3BjLSUTrN*j*uy zS-Lvs8Q}uJ9)p?a0v{>g8#NoLHnIV&`Q_Dz{Q`0D4&dp8-z=)%|7}s}V{{$v+#mmb z!nv1uE^6dP5I6 zP_M4`vb|ffG^d+?3-f?34`nJFEoctqxL|`O z7)K)#P&TE&g_iNja$ZY2;BmT8gB3Y4Fn~|EUFjZT4stMAQNaBh#~GaHP|pU(r_uK? z+J+R3NWZh5NkB`V2r28I`3Xqi(g=|}B_|^zlk-D~02b=lDrt_l6QioGPGGH<7MkAn zEg)uJ{_s0QUl-?EFZ}3OBN^IyGVS^9HnfR=E&vX%nGq>5#u(&8yRXc0_gA8)F{nEX z6`;(FU*8oHaDDx1iX;u6Lu2fbw6P8UYh0@2gM0>qv| z4icS`I9LTj)0}u-M2u!?ptskx@r7BR61j}^MU1Gt8>Qrh319s+IUJD9 z$r$wSCwxPJYzK$v)#!jOB;JBo>3xHHQF9hvcb8x6*4d`#Fy06SCnOYF5~Mi50s+Si z#_0E75BNox-deCdVqkEs1N*jb?T~@7<|?{i^X+AKg9nvC9jfZ+3mY4-3+4o1BGvmp zSLIsEz=n+T>@$R?Nsqn3$Zf1a*sN~8+!Q#1v2Ak^fqS;*O}29%P#w}v{iaj=7ghkX z8JMJux-qO08NhTD3zNRY`d9+T?UUtt4-tQOdHtTW^_Jq?T#E3R?SXK_<|#`@z)=-D zI-jf;gDC2K?el)&65;}^=G#aj;#NmK?GP~PbBPXsHm^s<9f((GK+HB{3^6;p{u-~7 zc>K0kj2?EY+pDBJ=$DO=HIJwM;8fMYskH+OZEI*yGcMaWntKTk)*g0DTiFOfa$C*{ zsUzM)taOwIz_W|ZA2iRH(+Vh!SClcpMb1~39`jnHOlMJ&on3{6M9Wpl&N0i3_x1Tq zoS6aR@7<>YtfgUkrjN`)c)@#$l>kigZ`KWdrP|HpfV-VL-^G2iorvrJaKhiJ8jyom zRzf#&O~m++-aY*^hD`mmOmMtJ^?SctGQEEwbqolxfrrvQ*2Z6LF>Dd6+e}aFy*lW3 z3BVnqVynl++oYQ4uPZwnbke=Qxk!&8?lpsiet<0#;*A231w5iD?0(wa5cEy6Z+L55 zkaE!q0AH?#E*yY25w zS4R)=U-Vn2zLj|W;70bfA=$SuBPGEYO9dKTr*Ky23()9{ngP zhlicNJfmr5e*p~6X$^}(V*pTZGMaY|sl1%e!@&AEx!aBs{#9|CA_C=Yn)!Cin2 z?yv&+x1T8uVKvTIq{0|gvNRvL$!9YsqH?v-`f4{gI)aWR%k{L}r>FKVffY-eJI5dP zW1pj8beLq&{FBbNC7Qp(oWKW5_cu5$Mh%Yp!S7#c83+(WKydIfBBkLoF$qTJ0Xxg% zh#WXVIXYU_Qo#oSSp^Nv7fzwB6y!RBiEB^Y^o%$wIB(-O)Uw|BfPZeakS)L9E z0G%QN7IUpVBUeBk+?#(ve4p3jXuI|r_)*4;bV5Ze4Gw>zVtm*_(8JU`6`$Kmi?Agu z%}HqU{?g@-?DLU3h^7ic;-rJYhTe`tb{fztG(fLB2WBS-Zr=j8A;!ONL&PgBoc!bc>o@)Wy}Uy)vG-V+E(rr{TCrGjyOj zkioBcFaRM6B1iyI#LmG%N4@<@U8>yU)~cKPf)|1h$Pp>DaXt{x`AL7EhvZ>+IccR# zmV9d+N~Y^FsnF?SJQE9x|HqH)ngpbL>IXObjim@Mkf6udlyo3$}^5M zz#tif6JmoeRHK)?{7eRQA<%$*kJfq&mE8xGx?ZZ9lT7@LGM4j0QZMucEBfEjy_$0E zfSyFoGezWY2vv3Uz?~f%Zf-;3xEyz zkb>zyd_7{Z$`xLY9sesvUhFn9U~aX8YS25NA(#Hu#i>?>0V)*k9M$utj27BMhq@97 zovr4QMJUDpl_U*F*A*Kk>;hRp2eabG{jbA#7X+kZPn3TDg%*Iyhvb*#U@Qs9RS}Rl zQXZ~@Vhl*-qyJr_zdz|9ogVv1Tn`A~5FErKSmUa4?}M*B-W}k_7)xvg^(6DRi~w`& zUkVp7hXvL~00O2#h(H3E8rlyH?L|R|Km-ZEU?x(ny}h`g^%)=-%qv#j2)`k8kJ&kq zl4Fb|fxSFmo_Q7v?lERvheQ-5NwMbN-JPAC+#-W&e~0uM8ad~l7&|m15d4(W&8#Yb zfgwe<4m`jZOZOSGs&Uyh0P=Jy^%rF7LjrHuy2b4Tc8@~{oSYyP7$tNp9^pdg>Yq=9 z6p$*JA9p;#*Hj@TQY|+SRREoVuZj!*IjmyH%8<7HzsFd`Fp;OM3Q*N2ZX6DGXsE(_ z-AwYWR$z_CSr-^0lcdM;LUSko^SoDT(ELpdNbiBcgSV!s+^P)dgI>${$whD!((J#+H%)@qr8HG`Q1+HTKNvF_`kE-E=-4vH281XSTA2 zb!Jc|9SyYK`wIAgG#%9aR-i>g-C9A~a|+1=N>Q(-HopLU;#A;lU zEns(EfcR<`k=y15FTmZcBzt`2S`$#-#LDrvIBh*g(9_E!->^Y0^+Kc!-bPPZf%?gD zstA;u>in~f=YJaMePu7S55^mvKOS5HI)uDsrq`J%bawEmJ2|DuX_Z2QSwfW_d9HFp zYSbYFs6xSj$PDmmEM>6NUkId*y=YtE-6=p-_uWI%zDNQ5V8j7P3s7Y7ht8ztOIOrS zObBn!zdRi&zN!*`YP?&Jyz(5eE&NSWB8Q<9u(!R;o=*pR0Q&^B4f z0I}m$*qHuI8i71V9~3so!T5Fe|HmGIC7ID+ z(75Ke;)~bBudba|`mT_({Mx25B`h@WW?ea8K!{SAv>o1pOOX>CgfO*=cbP!K5A%8} zHkIcU_A`W1vAMb%enp~WhK z2LIt*9xWKtZOG!!e$)4M1OvozoWO6Zq_a=&(z2S=zs6#{D0uvLYb_z=3&Q0JfW^WN z#&EW`vU(T%1qo zKF~vlc;6dkBVMrp)o1b6YX8npxW&v=zdb(3LnKf@{h7M@m%+ioE~^2)zvH+Ki5OD6 zL=q%o5bek?fO`%Hh}fU(Zce#YFO)=fy(m!qA1D&Nby7}fwslHiwrq5H(3N=`Lc&_} z`trk}*=m5_{`*4`3M42p0UJVavhRT@n#JZ(J_cVi4@>&?cPGI+!6zL7_VfSF1@XCu zQa7!H`JoD=dO%!J@J08<6ty^?X$X|k`SzHMJ-l3=K(YFrWz7b=%KBx(0a`+ z_5o_EFAj)T4e2{$Jsiz>&;Vb=W}&^^d=4`)pN9qaQLy1Gs0d+zaumybV` z@&3;QTPL8gY+XDQz%Pd=Pfk5e-{*~ByxMK6Z2ws;EeIB3&3qLki~J9lMQ7|mo6%2_ zOL`=Gyg4T>`^C_gagb9CgG`MO?RP3*Ny;Eo1y_CY#4jWS-Nn_FmWJjQ=vaY{iz_QF zjcR6Yp5KCohDHE~W|j;&WKRowMSeX+d{QYRy^m2B5ALNSK$KEN*fBap{e?dm%E3hi z@2q z1LYd>^vl1gLMTeIK9fCw$RVHv{Ye9X&5Oq!>QW7b{y1P>MM^*){tz=&{wJai1qJ3S z^P8J9jR6f5&fx_O&L+-B>oLMgkf1hY_W_*o_YK$S9c1D-xUHsxN5EE)!EW9|IT_FS z=c?R*rt_y^gRSXwIZY_M>uk*^;J?qZcUKCZ^Fcbw0fTDF`E6#*I5p4TOdrBkvTL|+ zSHE3R)6Ck}rwv&wyUFsbjh6e%9!_%Fo! z=wo<*6i%0`(-jeXg}Q&Z0K1@(o&NgJ`=G=4s92v$l!*`2hmJ&Il9U_4m8#|p;vo6SaXL30SM_11JblWH9l zB*_r+?0+B6NJh5ar>Ys)kcvN~zLHx2N8?#CR#Q)n`VhBJ#4Lh(UG^GAB1r0M`xFqq zCEg2K$RZ~)(4gd)4i@Nx^h-Qr56`o;Lc*{I8MfwVooD(thl>Wu5De@7LWhO`IPiJ) z$oxVWBn7iv1mlcMMTfPuGd-%kEuE6pF6u_nc4vmYlmjH` zInnl|(n!7QV&iJPumzbrqQMc67Wzl1n4wubR86HriYH(aJ}144Q!3-BE+Wx58vwG~ z9K(xtx`Ua7&XI&X=TDvu+9T#EPVa&8ES<9`vS z{y9ZG7*O_;^ELhuVTPDgul6d%xp`0LGXb&xgL(ee$xsmT^z)Hp2Am2o(xXx{Z*2sx zJ?**$6z3F#?5By@lZ=96Y8OfE9`8ehzDUn1Exu$@E^ddCV z%0>sWQ&EZk$qaBIPwgj=xt^f!Q~OewdpY44f-NV8gfxPS8Z#DvVj(f-AoGM19*KFlP$Q%eaAy8*yxI5h#~Fr~aT4IM_4~5h^4WAKzqWNk zK5^;baV>J51Y&K5U`QUke;^Q6l9eg(>cYXHe)Ey!i4>!p*nQt#(QAsQh01{*J)Z}> zdM4GF)|nn1ZJ;BKMBl(l9HPDxXU{3*&WUj{r^8bl$fSag!~n$w?q`5d>q?PDmnQyU zr>d3cpFYpEv$rGDQkL}URjpbG=EhRQ{lV&dxi<|76P(YIKviB=kEpS&^z%Ny&~zTT~=eV2Jk51Z!e=B$9Tx&jd0o5N_Us zn=8|Pra#o($By3@C1&xpLb|8$g}goa>jY&ntTzYUZVX8$ED5P{)Y zXyB2h*Eo&FdM8gV4_p<`{zcfP!61q98H4w|Z2}y0g#}Y>7fn0akZBrS8W6FxB z#xzec=m!q!y=SF{_Mn#U*k^aXfq?-IP{BWfjOQ*WUnv+DAD=JAXE_l7I#|K!>GO9t zSTst+jEopY%5+((L5oZ(P#2!&(iJox7#QtMe>6Dewc7X2<$S9)HaXdZ)#Xm)ayZ@g z+-BfYl2jXDK>0Zye#-lFtFtmr^+jy79(EmRXul-U`BM#bzaJBJLnFgt7ipU5o(K*4 zQ}>P9hky?>e*jtE0F#r?dL8d`gwjEqJ6w;3$2TB?CTL8dg`QOuE7bk`eC;cY5Z@+A zOzNGSzQmXk3><7#xh^092od@Skp9OYC+BlvmKPb+AA>u>&B*jhQ6du5iz$b z!0!}B1pqhp!c2YJGm4&*d!7wg-x9t!U)Z@%cxO(Wk>#yW%YF-d_J*i{u9h29nh14g ze=j&XiCRcV=-PhpIV+&EsE(?Jt6s}V-I1mf$a7zKY(A6OoZ1NzMFG1`3`)Wo%9bNX zyi!7*Po2jU6^Rb`saM-UJFIX&yuD=bKZ%Q)6OmhTVg$&4?u9TBn#RdYk{VvVx>OZd zTY4*Ha2Smj)Ui-!CRc*h021hTLBoiJ{G^w0C>U0!Jd z9PnMGcb!92TyD&woNR~!q@v!}`Q(HNtrb-7OB=(e`-yKG$h=amRZA_+&XHR@6Us;B z12)3q4UX+VqneTwP!%nc(|O{Ze3p71l~W9~RF$xEPA4`Rxao6pjmDx;Ucj@VUGB=S z8gJ&>K-&oB5=H5ehF2)ag^0~>faI=t4g6|)d{Ee2-k=Zkkn3ylzW(-BYH#GBzA-4% z968zdhV}<3^>~fv|1dEpx3gb|S2gAG+qf|TMgWaK9-4uKd+T8PBz^Qc`Ff0QGQ;$z z#7u9j+plHjKfTnX+yYC*HuJSpdUS$wxYY zsF%rCB4KvTQf(2Q0&ZX4Z7GOZ`-Vuw>KbQm*j9So0x9b&YKrjKrpHP%8Y3f4T(tNY zwDKj)_}#Zbm8P>0w6nA45?*8%BwC#xz6f|r5bQxt#+4{TN z+E#rYD`JD|>k>amGmVJ3GbIkp1VJWyEPNYk-w%Fo^1Oxa2s1XLSznj^As@@88-BJp zcQ9H@qyMdT2V2vNE=aunoel%dD{g2hF&HAnU%a_ANkt#Q-C`)v(nnBHNtIH*Hh$pk zv1+}ub0EIW=AmL1s$*(M8}(*0@M99S5mpPPFWb}!NDE6z`Ciii)N>xW8;%lkDqh!# zfdI1K8N6vl>G5V-zscVmbKg4in&f`ZGYdGf3=ueDDJJ-9tIQjnUw1&ZVoFRD+EdJM z(6QTc!O~DPKs;e)vmdJJI)M#mWB~V^JA>KJMNNM0 zPJf@pbxhmHgbgSj#A;tSDenft)q=|_;v0cGV8>@0C5t=(gKRvz79F3=1wM1W5P8tjN$L|>;eXPhceELzry&;n&esgje2W zBM4f^TjaFSf;IkD1aO0r^wAunHmdcGg9%lh=lP{dYA5`^!1;a2kCQ zW;~8G=mrSP)9FS5i^DJVXE%roUX0y;rK>4U)?9a6?Nb@`Ti)%X}GZ|H-;A z;TiM)=F4hE_`_ojo>>$zLOV0CGKR>;@mSTGV&*x{u{Obp`>e6#B$`t6D+KFxAg&&1bux>{70&QiS5FDZ8V=C zGAQQ%HTDVONkka-A;47uL7yTGWr#K=sS4|mSUKlstLr*RRr%X}+0nMY1x6}u60jbd zBWu8*yG!_Kgmu=<@U%oz!-);(d$($5qZSw6Kme%$Y6KonfD4z`h0FahA{Grf7RQd! zjxg%oro$1P$SqNj(Au5Kg9+iNlh!S)o_aO+XB9wC-3l2_IS;)MdA=DJI+2SVNehs$ zW{Z_lwx9*Nwk2o?hl=Es3Pow!9mMbKPGC8R*ypvrA*3 z5A*W~H4d0(7Krn_zXTTyBKGl)#dr388B0#(({A(nC0R63p6UlC$@o5*i^HDHFvYpE zkC>w+y@>FM09EE59Hi+GX#=VLORRy%&XCTXAm#*ohn&ypjCKrwQ|L6E{FN0-avk}t zzUsKa87}){rwaax$5(Fo05s{)2Ysqe4hB^?9ht3>hRm)=de}BV1q+f2FZ5lgZ&lpt zpa*J9lc5FZdFcZBRPPQbveSx)yu^Rn!Ax6mwhGF9Bn4!5b;-$7z?@_vNczW&K$Em& zLFclnz>@k9Iw^uq*#m1!dVp*SC2qEFj#tv_%Xp~V^9m57uSvszz0bF$Y+>7cpxZ#` zJnPAaeET-N=KTCT;+^cDw4|g_gNU5crg`})*lsAR`@A{pDLtm;L-VCdnY2V5?=wa_ zg-VVF;$E$xpmMw7b7ilnpYFPmAYe-9nDf7DLIzcdNI&1ZchE4eJBl@4#vvh$^ZUSp!nWg0%r>IR);C@nnH< zK0dePN$`Fm{2rE{Sd;cBOtvkm>A7sp{f`V2E#55% z{As62%hD*88c&Sb!1BXy|<%z^nR#b`zC*uyzePCQsU)o?#1jwLU$ z1PwlmWsSwS!P;A11L^*QwLw4Y_H4^{1-LQz%?17fi8$gz z>Bq0(g2eg`+xLb1<$7_EgDZM<`2+n1u%>v|MWm_J5KjU^BM$&TEO$c_vx#g?=`E9R znZib2-}|Y3+e}oY>=N_nDkh?5Ljw+ffO1M4#<71zPvX3$DkQRfY=*mX&pm(TIGbjH zu0!SW2kU|@-abKjxER7XOd|Glr6dl$s*GB}gF}ZrcR2b82w}5?jj3g$wj#2^{+5x! zFz9=axMG(|p9al_S%N!8ICeuU&G&d8&;zq7hmn`JX4e8S9u49eJXU<>mQx@PR~`lM z(_=JXq3WPsQhvuHU?J9wXy9YCP}Zhlh(M9tm##}hRf|blJWE~AKf0dlt}Ev)Q?{1} z6d&06F7VRD=){E{Ol5)e1=O%HkTUZ>3n2DG&$HioPZ>D2bw)*jGxrMzcIV<&b_RX~ z%57%!jkWD=%!mKXob^e{@{+=j4alzA{oGsbbc%d(eyZS2ExM4TL%rPHEPvMEvdpUM z-F>GC_Vi{YUGg+ScEnCzJM!nJ3_5^hhdMbYKZXyQUglpgJ_v$|PYfiNb1d72oa zFh(L4mC?R3rmBQmBj32{jJ8Hj_-O34%liAmyvYuVTBS!;nC4q^>xoiuTjiLOGtgXn zcKyq+M0f00`1^wEm2^5+_lX|9*{Mac^W}Lpb2O=1XPat|*QvQ$^fjrECUoj-Xv4z8 z>GglAVcAVtF&Gf?b|6j9kAn_;2)}Aao9b8an)>&S;V)#pWUfA)n;wKx`Lbm+I_C+V zn~2c>d*@N$`;(qkG(zpd|2g@6w#aYmMQP4AuBD@G$px+QA~SnXsq0Op4c{X6l*yDLX`oP^J3Lz7^WjWt(r>HYA zGaiz8;(Q{l`vF6ctoja8<6SAjuo6!1$uNnHGkrrpnPO_0M#rCF_10eD=~SE=!_Vdd zDKR-;FMf8z>gCj-wGlXGbje0)p}HWKj`)X>2-LXq9exoEhjcOhA9|{>NB0fbPPbjf zDQlfxXPnDz1EXJKR$!NEN?4@9`_Zzt%?9-DWn{h-B91O|)5cGELn}9y#(ni9 zf@FYNF>BVR(VHvx`#L?(0)EXWFAw}H;R0Ij{&bz?p=EJ*VuJEU$oZKNC3-%J%QDFI z{L-X3wd=>`VOS4(afn?Q*Uleb>}2j8oX;FKQ}@s}RW6a+7dj2(HVwm0{#Qm<`F;0i zdxAA}Dcjtq$8G5>4;&onK|2Bp+@^byy6#IPO%=SjwKnV&0r8P>1gCi&0Mt?+ojpbt`$jwn z!{>p0>7Sr@HFlu{-*v7SR!S#8WT_+e=3E$J7uM-$@$(CeUpll_H|h4M0kZrrDxJ?b zp`YEe72hNm==22i(vR!CV>&kP(5(!78Va(rvc-n>0J7bSi)fA++# z65Mtqru=P+C)J)4mn>*z3!C-6uGDpLZ)bj7n;Kfd93BNfU&UOt9sF`{9Pl#csz+Y} zcEb;=;=Tt++?yK6GWa1B)*CRi%7z7)4s%EK!2GSzL@MJz_!UJxojE0WJLRF|RbXpS zWXqHvJypGvL-&TB+xJ?FFs`k|;i9rJ`xSRM z@u1Qo#Wsi+mz1<|sR;Qm-u|w&KS6e|Ii1^|q%wO=7(La3-dmy*srNYJL3QI*;u?vF zTb+S-VC3!dxSg&r*`3-$Yd9M%&Y)Fh&|u*}`CK$+j2$9BwA5BJvK_F^#Z9z|<~fH< zw6vcFS&Cj!dMB5o0B0xc@&DS1FX(LcvMS{2E*wG0Eyo^J!OvgUXP!g<-on8Xw9figJC9OWs@iHcm zf_6ScfR?JdgR*+lfm^Y3I67+LwJ5#~LRD8c5)_44qm-I@!RLK-AyZ-UUzsh~si5sM zA<@DQ^RfgKirtWpAKi}(DFjpfNNZoto;Vs)S}G#k&MFFbSD!}n!V1!>KWd!kRb_-= zZiTWCe02VSkcJo9R8+i#FfZxMg*cxLl&EV~63?H>9a%%1^wwG5o4J$>7 zy?E`h_j99fyOw?+Y0-PA43xD1xr_rp$3cK>r%?1#elpv18V@A_T}pz3a8#)C+qd~p z#>|+DmlX!m3p~B|@87Qjt+Zp))3G{>3n_0CT2guJh_5N;T!ra`f^zZCH&;MCyCZ{5 zY;s;X&tpJm&~2acSc+aa?2poXDR>0a^9BWk=mo7mAKnYXp=8#z{|pM$hnM+Vu|E2w zdI0*7&Npn7nOl6zqLWlImR2^=6@A`#BIcnx6ZF7~vwS{qG&Wwx=cg=AqF4Q#OJc^! zSO2C@L$>Mz>EnE~TNa535e%5Z%l=f4gF1&l87GEPQd%K!97@xnCNGDMJLfTCIw%?+ zU$PDp@3O&XE3caNqn-13(?rI{>e^Q4j?p+b&c>g#*b;Q+R8^IH zeJdpc3w_di9nutsb>XxrQD_f>JO6Lz7{~XuwF~X;=xp{=Miob_^*7R9r^M~y-iQ#c z=qfJ|*NXY%_`txrk*1U)?knvsxzMhZl$6}H%gSp{WCawsxcI%$Jl6&%s2G>c_2sc5 zvf`UJc~#QpfJicM9q1CDl5)S=eu|9-Qyws%;-#o;Sz=ADL2XRFFcCXZeQ!`eCN2`V zpDz^xOcIuG99+^y=}+?gITg(~b~WWLr}C z^o$c%=lC2G;p1cuUr||xbG80YUR_yhQG8l80kR=d$LwAOYUudh#4QhEq^Wj|O=o(~ zJr|q|)#y6RhIhICe9MfU6}uJ@hU~gXzu2Zy?Vr!#qtRE+qp1%z97Z3YbTo#XP!P8@ zy7>9|k$uf!v92eSwQKII^Wu|hv9LL&3zs5bi0mARu92|`zFs=P6wDO zX&A9`7DVUMp3d?t5idP|t1rIE0zOPh_k%U}=#S6+kdm+xYKlS&0nJJVFBC8_10{`{ z6H#(N)_CFWQ-mEEso<*kE8qq4yB!o!N!lxc5G*l<$FT?OOl5jIhv?i%^k|&v!MGEb z$mt>h;NvCV2{2kdG=GBD&cQG}qt};zW8e^urdK;Yv@^^#i zT&AJ)jHdO~ckae~<2joqdIz>uv>HT@UKV7li%=zV-DSUCnYq1dUkl3mm=-PlOyWCL znj7^#eE~;Xd35k+n!Hds!|Y+;S9VIT^U2xyv-7gn`W!Bjar=i&!k$&B%d8V`rNJ%L z*DQQahDuv8yjhUK_xikZ@;PBB1u7ND4URvqk(21_6{WHSmR9WIi7>q}zVOb@iz%*a zs#;E$>)<4)NW&DzCL4%ZJrZUE$}G0Rp9%$3U_2m6d<_^1MPf7?pV1Xd5KoW-2N@=G zijNA)F0^j1_Pr z-~i+46oQVz6YG6Z^ASyVx~s$NrrU} znA68DjN2PX_kBASF@GUGF(5uVzu9>12O&GR5sc>{)#jhCDHe* z*NL0z*>tAdn}D}cAP&i&>3OUED`~RO&ONLU(%*#cVN%M!4PO7{HW*`=coqayUM0W( zoYITHZ)*d(AHgYhh1Oh$Dm`O{K*4fd3NfK;W(>#!#dR1gyA#+;J=Nia0364-PAEgz zS&WYS9%5bUQ?rRn>9QBQ@B|%p25PF8SrSq|BI0U`9G@Y~B8htu18xN$jP*9o`X^GP zEJLNH{2e*};R5uWGwI4NGI76`Epk*8itnOK*bZm7~)rKxV6-n3EMRlB|_N7jPg9Q@lH9?Qi7x-#N__o)mYusPX$iIBnl zTJ3M8*`09%bKNjd5PdLYvsvW@my^O=(LGip%H4`mk*I4em#eptt8eizohhEPdOU<2 z!na{{yNmA&GuzG%H|X`V!JQOY9P(y)FD$`%##Q#YTAR9*W$)ZkKu(Pm-1ryBZVXM$ zl1HFW)6Rul|D5ar{~5Y?L3g^{-`^iOIYJ?w1Azw=gwY;}aV($|PkIM`)3nl-isIqc zdtK2~_py;JBjJWlZYw@}LKpDuy)XsS!x#_2)P>^-fq1#9$&;CtRH~OflRZOO(N!mU z$d=PqBV>jC#!hr=-BbzB?$NR};kNl3;E_^bvg2A0_y7N!6}Yum@DC*i;+6!8O`x^I zgl$AFBw247^pfuFw^GK32oz3__@BTd6+fF$%Q;M zFgGx_mkJeIlp9_Zm36uzRc-XD`ZfTFF#Se@KUH|I9=7fhqt3S>*Uwm7kJb*b8XjM5 zvyL^Ge?%~a8qW;yjFs=+UQ^2b^+i0{cB>=Yif_=ZI3?~(f5r9d*f1@PS(6qjFjG|B zM=HaA(a;N$iW+%^x9uTMJv4>k$UBo-un6pRx{1`$5xL@&1GlI*9{%%TLKnTOXur1!#tO&*YV!lX^M)Cob`vs? z$YFrh8-L6oTJ%f>PxlZG-_YqN{0{fSmZu;KtWhwYKYhK0$ptO#e3ao?XZ zSYNi6S(6N6u90Xhx>l6Bg3~{^ZfMINX)^t|1dXFERuqa=+}0 zr|cX_6a&cej{1*IkbEjRyQ+_VggNRY_S_l~6L)x9fqBn%CAr4CUM@By{-!3A9LOMC zX-UKV*dP#a-0<|RZ9)mct|@M8_iX<1d&^WDQ%(5yN#x~ATZZ}9xfKVe*mdW8Trrxe zF8z+3dm6Vv0&|pC$klvpXGOnm9!u1)+ubMEzRy)u9O^GntCbptmG{+I4QyODp6vS< zQ{u`lgLsi?4$VLUfh$uQpOIO<(qxNujJG|6#mizoBCU)_I^ z_#hwjMtg*Gm#(E8j<#g~O^J25jM^w{T3xT_rRa;utjkF0?1q}V)|cft%`-?O1D<{r z>6P#J^e8>aH5rsa`Iw{{5@AriTKR6!4Uy~*0^)6bYPr%oAgNV*tDp7}Vb*Nfz1xJ| zi4+*Zz4W2N#o|z)JBtg`+WP{vK+hhvd7_azHyF3AOjuN|*e5ky7%1qi zdc6Cv{j!QbXXL*VUQ2^>JW)~X!hX%!e4`TLSWDW6r->4V5{kWns!D;+D0<$-FtI1& zc0jPEk9p9os;X(Fl8f)%BJ7kD%vNbB=c`;=M}6tv{7Wg(bk8S5^T~fa8RW8EDScXT zWxbt~SJJd=qh>4x*O%t}ce3LAn=>Yg$sjXfNmMYasFD>8TI1(+< z1d!k74Es;It{t&W;KCc?0$SE>4llkxurR5+DNuC^h_D%kvWF`i*>I7&`p_oxr-n}B zv{HyD`Rw_Ni9bYh+oLYn6(oJT0t?HR(xRP2;$VZRJ(@8M!nGA^)82m`-n{6q-iaUy z3DJ*k=#IFvDcQ;<0YinKcboET1nU-6c#Y8yev9V%$c=e@an*Y=oSpK`c_fI+EAD{# z%Hh!LEJB%hMIpO?S7fF_?GD<^6Rt(R7&?u2(Fb68UY) z(O{q9KrrRAZkEq7hL<*(LL0&R-D8sE$c(+z-$ofl+LJ{Ft4Mt`bm8TUOOl{mjNp9x z`4fa)C_)e_pa-$X#nu}yVO%bp7m{esMJ=F*`G0~Pf`L6+>L3;ST?le)SbT?60a#7O z@I%Q*EHy)!t-ac4JCYMEoF7JcCUC#O(iwIx-&>LlZkPdkAy;mZTiEGF9Pw>Z#9j_O z9Ma=||09trDTA{PsY1Q=Z>)){uF#>k3#EjCP>tr{p2gq@-w5uKhqh=!rGerWM&9ye z1iSYY`ofv+$IDj~Urdo_GspZ`2nutZhiHKPHTe2pHSUryo)Kq=opmO?+g_w(oBY(^ zOCZQV2g+ri1aRwKnIG1XW}Tswz`;wNcv~fZhl3D}MTHlW@z=x&0+8L=QLM+_Ii%k* z>ctT?$L$LtA}y5Xcx|^ELCiOmN)QqaU@S|}{HJ8SdWEqx-M<2m^JU`(Uw262aZtM1 zz$*sy2S{w>Mxu}6+o0O;H8!HYqs||tvdZZCc@Q&~{`MUj7=#Ii3)hv-jH(*yXcNcO zAHq_ZigNBSEsMht=;+F@5Vc8untmqI8JRfcv<{L`FP|oHR3vduwQL?UKgmJ@8a-|k z?jj!eDGIg2g zv)*pG1RgPvE&L15<;_dLQrWP%KZWuiBVLQMP$Aa>)U8B#W9~>E8 z+gmqQn>9;anznaNceEdg|C(`U@%n*kRuk=dlDE_5-Tb@|R43wV^>c-qjYReys|qX) zd}*bhp*J&$MNgkP4g)hOLwc<#W!F&HJ6`P-cbDyXUWv$p@U)76ah8t`^qTYKka+Xu zW7&<|_HA6o-WL-!wGP3FEsau1Sf>pQypz{=GCJ;V-oHw#*__QzV@v%&RVsumCzmkB z`HmL_PwWigcYr_2~A+uq(NHW9^&98tOAKP#G+zVnampV=?6uRq$$n*A`xm*h{~^Tg~JGeOiWbGAX* z+mg`cxvG@dn}s(v+QS!DC!IdK=k12^Ny}!Pu__0hJuM?Xe(WZ4y_k5R@vXZ*@F|%m z^F8w?hv`2Tf6H`z`)kulS*{v}AK1|$ezR@6cw_qmfj|Cu)!Us-lSI$!su_)EuBdx0 zVjnjC5!S3ql5taPy)Ow3Jqk=DHc zDSca84oFVL9-w{*<1;-D&mH#Ov`)wr=1!Du%qjV>S32?eYI5ECQYL>T+Da6JH^IKb@EN&N&@yKSE%hWoNu!rRu7ZM?g)zK*ZI5xN(EVu)qwSXDcY}h{RRY$K0JMHY-qfAzxJu`U4i3g z`c8UFj$s~xXcBO~UpNyHw~*0YAomwxISX`fmpyD0i%%}UY~$8;t51yA__&^r2fOpF4$`F!-)Gfv)fP@j zQ!o0pR{uk;=ZS)yEDtYlQA5oWBcdm+(y?Jt+oSyp=MKu-n8S39SwMvS*hn9$X|L%D zf7jL3d54|VoEP5P^n~s_LhVU#Ufp4Q43kwAAv97NybrDY$3{g3Cb@3WUQ9zzUwBVl zMRFxP=XgHNcA%1_D{4ZuEtcaCj%2h-5sG8Ia z$L)H5SfKda#&fO2d|`%1BBzevDbme0Ga;kRo@qK3y;qI?T`Bo!YPgf)%%z#^DcA7+ zz-&VUHTR4=a_HTg{dL~lgtdrn4i#FVq|@yz*NB=pe=j5xp1bR)q-?L;o?{|!*n?p? zb;+2ay@RUDyJ)VKKzQ~(K8M8^GqMx%9EfnzNLNxfS*~^x(bPv(^Jg^6 zK7E7@MF9TzE+k9IUb}d6$Ff4t?h_y#V>H!oNpDnC+n?(h370J|tMrFnp4lAh2((<& zli4p1V{F`|RckAHkB$V?5e*^IKKt2sg`>qVc%@&_%R|8XQ$mRX*DJ~+&^@5h9YpcpS*y4!BGCD-! zF6jICLk7QC)%(Z3TBy<}Qc6`)cfnDNofr!AsYLA-k>1|&kZeDDQF3*vXEL!mVOq*o z%rx*Phm~2xR!mR8+)w7HeyoN8AAej%`8>vsQBp8%3|B56A)Hb zTq$QhsRk}&&hs2ckyDZpeh{ky`be#4fPz>N$;-RrN&F`~n_98m@9k&%E9TXQeKOeV zB2PZs^*&iSD2rMh`tmx<+TUK>Vzig~?v3c77SzaOK+&Vq^d*X^?=n!1 z+Y}2FEPr^l6FtnC+qm$>j3v6rJ@KM^)GX_+SW}#Bj~ltk zB}3=t&H2vKr1+r(yb}u*TO2Glo{3_%%OJ&DD=)cIfA69xqju| z-a|s2HSs~Tcx7UB(Cq8lD5%+?*()a6!E8Q)(pA*!*1^1MgY9W=(}s1Y8xGW*jQExe z4?|ArOgmW=9X5wxl!A_0Xwh3wl#QB$2&0C^g=JXSf4W}p#>aGh-cL=W1FO+Y09|`I zxJIC~K=9t3sXVsN_{Rc$N9EDfTBUKiKZiNpWA6Ua$*!7$ZDq6_qt_|Z3_;T7D7kU^ z|FHL#aaC?z`=~5I5u`zsE=d6qkdly)P#P8;iqhQ;OByAmJEUVtcc}={4blqI-OYcl zh0nA1e$M-z^XZ%~=lQaKKelk+^PY3eF~+>cb&Yvr_m8y&s_Pr|L*qk=52M!lT1s_B zm^0VjyT8d=WaO+U8&DQtV!f}N$FwXXy^%YQ&9u^&?(^~4Fb`L5V>*<3e>lImNI`X- zNp&P?C~w7<9R48shgmN0%lqrD*(VEF1Kww4(a8~{Hd+KWG}MYTQF+&q`!E~AaM+MB z5JsUQ<`86iGMSdtsQ1p~_$MK>@(_o4;_z+cz)qBaZFcF&mgc7Q8SjV(WF29*8>Gs@ z6>&3^o+K70!6I~!5Pt1Oc?kyW{P`ipXjQ^h=V6ZILLo~u5kx!#12Hi0;m`E}6^ZDC zr0nw0dn-}n8p(rpQOWT+lU@ha^rMq9K*M&e{`ZJAVViwLz z_csfnN=h<&iFl8PRC6=zKQIT+jDG*+^zoyL1K*t1itRVLEJGaIa8%i+R5p-qpA5ie zRRyHYB5;#)*7lr+Vr+FpTDCFj(K%iS#UhQjH!&J|P(5${-YxLXtrBmS#E@h5uQ}ND z#T~Spj76RIWLDi{21-xz3=An(*NwmDxyWpcX^=+_4yB8gl8~+rtLqh=j1%O;nIc>S zG%Q+$R8uE2R|rz`PmUHlmOM-N_iI0Ea(tcWaDURWbYcR5r5OVzeFC7>qu}j+83xqfJVD1o_6QMUyM_{mfs5~AufKc;>AX)NPE!uCK>zy@To-2c^RwT2YBL`2KpEGl z@d%K1d=1449sGp>*)kgPFXAAEM2esldVWDcbWBWkMg|R(z|W-pCps!BdQcoDayaPD zV&38Hq;pd2NWcA=@L@q9DE<{DB#>lfXPbiZKp{QGVE7k2D!NzLh~yR|nye_IG*%%D z4M^XE{*=m@NO9I0Jo;K2HF`NsvkXo44aEDw)vdTxbUWX82QU$z1AB=2Rt*nL&VXC- zt~Xh*2q$<-HtPTMi@0cA%o+9dPwq1?uyArJgA&8Y3=1=}ikezZWF-CpJw|`z7hH7k zsT{<}LE~=uU!#uT`4*vz9H1|w{qIVbl5O$c|Ef2W0NPy)Fgdf=7E zui}=k5(G2I{l)cK&=ja!WCza zhWwpT@H>qZp8R2mcQtpj+FgS!p;d=w@O(r?z6UhA1Qz3~n1+R%#mZaOc4nl4L~c^v ztL6ZVH*7w%YOyb9ogj)8;q32vtiZ3H0?+SJ_(^i&1l zW}GEJ?;Qp=L{)(6N~Y`wWk(LHz@^PG4>U5~zrWop(Ek*bh6uc0C3N>{MAk9j{bk>L zMv(9S`cxm#lwEhbdANawi{;vQja|-0{jQuW0N6e-$dANv7`zVEs5Fmvcz@i3D(!K4 zAh;gK%N0U{x8)0-!{8qwcl8}qqBQi#!;AMKnv9H$eXrmlf;Bu!Apa!2ldbLrxIM^3 zQ-bgsdLcdH+7|oGhQrd}_FYaN>~Au_K|v#ei`qqN^d$gi z6kJDA^r_uF`$hb#qPvg6;#!)4rZ+O3Yi73q1gn`#D>>(KD1*jS_U2cJ^$+R=em z0y?TIKi3I{qf4Q4g7lYtbhzk#5I5X-_AUcsRts$lNM?yao91Gv4fh9h*a4cl^iU(7 zR2V2hVn|b{XKC&(a%zi7xi1G?yUoauFLLHYo`3=U%6t9; zY0aU;vkN2JV&d0zsG1$--#*Q_LbA|(!6Xqv@B@$^>#XLTsI?i&D)>C<+Nk2M!aPLs z1HQ%?1ol?t*ixkBld*%>%>@MBs1*VJ9nD9a;A%slKLzWLN{5Y%vRlO$@{%Q(-F@b^0>vTLrtgm%FcwHzZ4apJ&rI?oZHoojtn4|)G zJOekJ7Zn-D>Ocf^buwSp_yxinzLBi#)jt2K30mr3I0roNg2c`$J26{W|>*Uf>~ zIh^74ix8t*lh^2n8`E6PCN&7~e%@cHk>4>*1Xj4t;CU}TL$kyG>jo9-kZ|W;TmZ=b zPmJrz5)kGPP6d_+^{Fxza(OtxMoZ#jE5|^tFXBH`+rV0acygX0*Z3v~Bz(pXjWMoP z4Xl=T5%~AY9c4b`-%o)b9K){dBR2(dBl1dsB$tWysQ}Wh%t10+>X$5|!>FL4k(Z~O zlMmb4>pv*7#Jmx|F7aU>p=vSVNFTdRAP8FUx5dwW-z7Fu+{_|P? zndRXk;S4qcbYF46J{ts5i^7M-pv8~tEbOK|P(hjP%zq!r&j2Z~Z2Th$a0}oY?ugEB zaSK6Mtg4 za9)xVfHeCHFgZKD>VwLNsfOJ_oD}Y$`_lJ8rC!TCOw=s1aWIY{^F!`oZ)L-9d=H1?^?I={+t4Q-UJbt7f&5-kM%tHNxwnr?rgMp?Oj z3j_g%`QKM2{I?B&gnq8Lg_ViT0+KB+2|+waj7lndNLoj77T|GMy_qq46F= z0HTRh-i?|pDdVTh$rB5B&HZ?!prlcAzk)$UPdQ_}gEqftEC+zhDjvU-RVgpE?@h5o zb9B{ml{X8bQiMAQp!Oho{-V`~WB`%})NY}xzuskcZ>N);fUq?nLFvkWBVv&@4KR;L z*p4WtS%=fo(ISie+3t)q7I#NSlY0E|A`7QeRHV|Q%#Bw717?=t$;&wMNPgfcDI=pA z%h{O4X7obI^dK#_Gv^vOGlz;$QDLBpbzg2IrwkCF;?p)8BnH`J-?^IZU*I@EX!WwA z3VNG-;-s1x$4bEwZZ=f2NYv4O?~YS^M=2}6&6YznrL*ciKZ7BMC5sUZS|Jb)tY9M$ z>bEpry_l|)hyZNwnS^xQ-rmY!?UNqiQ<%4X_kic_W!@ZC(8)*=;$h6$95r8k^J7{# z*L((3My6AFqdmT3<;yf}CDsihTK!BBx2FnjGZSO>`OljBfl-7~P>=*%dHr_qBek-P zelBDDDkvTc;!vvaU#kf1{2a> zfIE2%`FTV5Ck169R0#vJ0rEiG&9Q#ltC@TYj5-d71Mi^~i$Lj5sKbkH)s|UGEh`4Q zleT*DqQ79hmWjS3A^mb37&;mamOG6g`)5O25=ikK@U$za0bv0Nhz)dG5i`odOEX~9 zL(lKahLT(pX(k(cKU&nfi*7*G1C^iEIZ>QPZb8K<06e7%h4kML>`$R=D^}!!gn}H| zcF4N#?$y|6z{7*%LJ2|;=={>qwCajYkDyF1#foMWD0cAgeLr6ra(Y{Ic2a zGJ*JT>HKhJls4=MVn>a5MGCEMUsMo86~5lTD>PvzD7?4rK3t&N0N4Iq)7VdqdPao{ z7h%x-ee&|fQsyDz!-T)>;UYhb5<=}K-Wkh23Y3n;dY31o2@hY27Cb6|77aKx?ve|F zK5Vt172Fy1(ihzXZ^rvfI(}aaT`La*s-EQ5`ZK?!=?#5IzMC&n?~~*lyE$x=t~X5# zJmM8{23FJyy_^)^1GKXv5pu5vEgSTUC`>mEphO|}IG<5^ot5vlqqiI1gKO%-pbHacZ+*bxR-`7-)LRHyaSEMNsM>q;)H@RIIAh zxTU~lw5yO^g>vsqwDH?PUAp3iUsh($H=JHN{nDB_iK&2byAk-wE>;u#txBhTo^UGl zvY?~N^zg*0;BucdIz^ay;1w?p@T^q&P6`H2=QdPXQm8bDQ(|DqhpUXxI!Ppvx*znZ z1pU?S@Ag^?15&G!t7~nS@Nu=4e(!T)=DO409m`IcbprSjtDOf=;5)Qdxib!%5{ei( zG>AfB5`G_V7I{f|)&tbfVB=$`y`TGY0L=z*le4XrqlkH$OOjjiA|r+N3l0YPV9;Ie z`B}-bsPS{i@2~{oOnd}(NJC_;`EaiMKzyac1znsO_@6wo#j9L%_5lh7kKKqfZ$3A0 zauthN?5554SrCPR%yC0W15g_<9-SZ<-mDd7VRiB)mravH#SNby68V<5{%U|K937-W z;*82Suk2x)SbuKih_tTK{~Ru>U^qhc8#``(T1uF-~52>p>>u_Ev?*&`&)5Y?T2wsN-BVtxOIeMX%PFy!Ft%o0~wjJ}UZ9d(4s zAm{_?09vE0g6oGXK--Z%Q%*I2J8!x#3b+D`b{Lf9`O!z7|K1OQo2%??aP3o;J-E~A zQu=<1l)hj#qjhEIlv(~DOpbb%4yEb_o25n7hi@sB)si4h6f}@{eq|BHE!w-auG zz`hzPu+ewCmd zV}vb(mbpV{1)?_bM5u0~z;7_?uB+V@>rAHrL2YMic7Pi>KD}GuiQ|nPbqJ`2O{aE=LHIbR zqBl}c7?IR%g#?itWzC#MQ>}S!o~6PI7JsuK9LJg+9|{WUg+}x0)8Nt5wxk0%*vwvS zDJjUD-T8U*A$7zLYk?z!$G@?4br2|vrXKt%*Drazgbk{;FB@dh@TvBic(=oEl|Dnyx%>Op(Y-jnzrdlPGOLpk!49%tKaBOH$YD)%V`(@r9b zo|xYG#%)Q#_q>NRzdph#zy^_hgIh4^ML4YbxU4$JK=VKGGCupM+L^R8Q@kTjEB8Lnkg9Rp>SadDrS5vd<3R<~B>LIW=CAN` z$MLgF!4hzA2@avnx`LVXtGwZ2G`q&?vo@v8BH&(TZJtSMA0n~}Li~6I#x34)a25TV z(599A0t6(d-lE{?*;rA!1kCtkt*o~&TAICnOLWk{sO7pPaON^nDyn;p*iGl;z>#!q z@GaM#I9bINetzy*wD)#bXVj78z4sKv6G!H3+N*Ana=%RuKp>7WQCG;3cQT|AD+qFm z5--_y1Bb#q1g4?!`oa>58GkL$Md~&5EG`wu7tcqgpTf=qUgW-pQm;?dRV~|amvu01 zed8*_U#^_694zYvUM_Qzl5hC8QkRm)okJli7Ed(PHojLl(vo~qiTTvZp z3{)K?0tcIJ2dKifh6k*VPO;G*f3~E!D6h1sP!`R|+>}$6@o2EU={d0&D}FS^K6Okw ze4n9ULgL*Q;doBmt-Nb3?aSB00_53IaU2rE|6Z$@od|Cq&72lpJZyUW^aomOuHDb9 zK3^v5Ut3zt?5K{e!A!}RBn~>1kK_Gsm zGo-pJ4d%!no*vN^Ue@XHs`-iKFbTTlsxAf-LszqzE}i$x&!6`icOBExnD!p@9vW|a zdA>h(U06|fbS<#6+G9k_)xPC6mQbdi^1a>ICq=MxSCauOwE*o6|3jY6q^e)rXcm$m}ls%w-kE6?R&AaH|l)Z57OQ`Z>PM zpAvM*UM-om7HaujzW)f;ocTQ)d)Kf_YSk>y0#)MY`@3zR8Gd-Xbmmj7KM0q0vm$jw zO}r;Kj-M@H@eN;z4)HNkiaU z8hC(sMYLo&NYGZhyacVs^*K@rIGyrZ1tAt_RB`|li@uE=^cgEdG|wlEk??+~O#<+V zgU@^qu677+yf>|AMss)hkF}bTl75W9J8asyAW5e!)wO|+K~gW&jFMfB3-}!~DqBU` z3mY{mcZgWyd31=PRYy3?E>C-*f`{El=|oiV@>B|sW^|5!vui$8wlRsXh+KMW7hp0z z*-FB(_du}D9>f?b<%6+R%gUanH#=BR@_WlBIr}ZBvKB>jwLcR&xg2_ELimkSgXZh(T+2!DCg^c~WBn&*S_Q$>=<+l4e0^K0RI@$*dq}wr-wV&}U?&omqCV z?mKL_U^h0%ZpnZO^^cRCzi#zNyUDYmi#cMpiZJvp$LDc%p-({`lO*$VZ}mL(Rdw9f zD>T7H;NQY1FXi#m{l!~O>(IUxA)F{F6QGKZS6U=is3jdwy*fxSYh-3R!iqK21&!SD z^T;?QyQUprf=e%ax;X%LU!u$V3ABaQarqrR(ur{~Cw!4<@>^+(59YDjRg>+}vbzP; zYG!s0DpZWFK;G%l%{_YLywK-Rg+NB$d^BeG6Gkz|NPyHQzBn(hMAPh|vryx6FM|za zB1O7?wqT}TfYRJ#SFx}o-<0M3J*S^F&}#%_(|hZx#vVK_znsllBW~$AZt$g9x$k4J zq{VM%ejnjm;3&Qx5T^OEZ~A&b;^)-n;|7d6Za+B`n1Wcw)G0PMnlem*NtmY%qk>+( zK0EJ1M5=tfY$|7ew7lE>#S+n3wZ`-F+vR0IJv*VMSExI~Ygpuq>6_fO__cdx#1sQN zsB2D!o=&~WGMW3?0;~UsdT)w_9}4}$hcj&kZvxNp4=U3dyxYs!qQY~JdE+@aQ^7fp zb1j^a_o3;9VW-HLJtBKUc>m8|W@`+lU*B{7`rychb9d3ob2rfygw;d{1Ho;yaiek5 zg%lSQ(b^RN_7@<2#bFLe8J?_mqM}x+e3No!yc_dxYoE^u1hn4b{i(VG0$PsW31dYx8g($ zcLh1-~3iWM@ zwOGdNoX;VJshNDnEYGXTJNVpsHH7FDh|00bX4L%&+-3>T{CJ>()Jz|G5@l|6U(wBS zBblgt(hLAYx}=IH$ZFTD8j6-!#x;Jo>M`N-@re)Zs4Tr_m+Z@-iA`CFIlWfnU-^fk z#ame3Cj^KuM3gtDJS&n$9VKwC)7Z+if(ZseSc2X*nVH@1PpF#av+z^UVhPeTV{pU& zA?&4P_SB3TFD&uCXV*Apu;{Izx0J^i(*}$~;kj9DgPNE@g=u_Ccwf~E=}b+2Ynp-2 z)eWM2YAT*)0ZZMGW;1+u(rmY;Lu}OD~O5@rVs+LQ^Sm5yE|y%xk3J&|of-BXf0V_(e6F3pVcq zR{(r)dz|d?+Q-vq;g6kvu3;wQmjwjBB6y;(F40-`r`gSzi#1D&lh;~&(hpWN&CSaVi$fOzNY_8aC1GGHO4!;=!~uQay%}PuHrSTOECB{r(2p!I4_C zfqPUZVum8c2)KxMVvtWMr{FZZ zSkm0BN<^Eszk`m~t<~juSU00##Zh+QWiUXun)OoX^pm!ikE26?+NzONZ1&%f^ zBhrz(AHQO*d0D(I#bi@l{QR6i&*ir1ZC~*gH~iMLvG8DCn{{@7Pd2!+hDKSOW~+3VUKvTL)b8@+ zKbM16y}MI45c-T(Kj0dyeR;)si~}=|GX@N)Wa#6At0h_k=yz%Fv?6ybfEuIg^q_zv zOFqoT!?n=Ywj14lsrmc%MG9%cb5cA|YHw+u34q*edm&AN?*|YZLg%F5D@fl5EIS$3 zUB|~+`AZ%^+AOdlY#5*1ZT)7dj^_pR=lv$AYs+!5xp2s{W;v9mn{=L=P04m)wFU?T zR!d$+3{gE4X=VePrEZ>Fee>Y*#b6rC#mA3PFK$-$#LJq3pdC7TDdBV3FdmQfQ5C&f zq#6D+Nbhw0Et50>E#jW>;LRYTnLYE)_( z;A+sSlAkFn6LazuI`DyW_WaGGDt9xHHoQPT?->X|(>~7~JKsl12&T;1cDlpWDchGB z*G9^I+GTMWB>E#W7Y95ZptD!{NSh7z9meA&l;K!&)v9!5@<|yZ?)9aS`!ZK&Ie~(g zF^=x@Za){+;YBmCB?R-YIBWCgD2$CC$VgZFJ4UOJ4fOL;Y4LJYXfl>Th5YT< zDrsFQEdS$JSWm6DQ;k{BD@qt;i5s}|Em!Yf`xmXw{0d3$!2D}-sdEusnZ;w&&)7jJ z?mN=)muPT`M+L#2TRxQPmveKLu;eDn3<`iIKkIqu zXg7CV-~rsf1g?`7eQRsy#=iwz%jfJu|Tjw zgs)b7%O8Nnii~bJezxy<#_FfuAuz8$SW1-uiNt2d!NpUCPM(58HRvBe&kbUUqdqx( zaqul*6Yrm#FcB$gMcxA6vDEf+g1Mm!Ze~}fgp)9hg^QlAc{dT(+#>OAIPXx^CLi_+ zKoV55BWbNg>xK)|xIth`(3vLvVP5Q_j$;LVp0Z+`oJ*DzefPe3T6HdJa8AZy*@2s? z8x>KpC>1jscKXb34&eKz5KBz$$&qPPEZSjbb&%|T@p(Rq{5<#j0NN$|-jQYvr8t(E zkVqD+*(4%r5YV~)t=L+zfM9S)XO$suHbbIgg;R)wNC^{yt`6WfT>!Ub6G2K4mHsUH zH-7?uD!@S%x!i6`*cE$_4Us+2KcMgEBKZiozuw1sumK$w6&u@|Zg?EDxSyn(mr>pi zP8bb-QY^v&=H>pd-5yywZzhHm`HPpRV-bF5rqj!<`}pBM@XF_!TNIDu(#JT`E8wl1VzlNb9dRm%nL%0; z7jhTc^@i-`Av3h(XT~u~b$V%Mio5PsDAyp4n7pjvHkxj06qGB6so;Qe`7Md!3bav1 zJSc|6`&9|e_r$%8<>8cAHWkOi&gj9-XNO$;-&k2EcI!LB>eD?(8;Iv30f!QS%E~;P zi*giSX?H>YDhkrXJHb(Z5SDYuB_V#R0eiZ0l!y)(S0Jt7&t}_^lFY?$1K6UsZbohNrxUZ$*5NB{evrM1 zJV0H;FkQ>%xnmdw6Db5Gj908O0K`SG6&5de-u{aVFh<)4M(uW)<{WE-;>inCQ!Xi&NBAVhaEd_n4=8EVwP}ssJnxxB5LBGd~g`x$P+5BaW(p9v1 z#is8k9yH0x7~#;W{SLwkJ2zwaS1|=T|Cdx^$DDHcE<~3w(8-%%bEkn9z(AD1ZC>0p zat%U6oLLVTHb`MCxLDkU0A15}|1n-c4F1TyROsus8L#iV*-AucJXL|aLTFNZENa(1 zQ3&Q=#65h9DCdBlD+VL!&e5c0H-IMMF{q>b2$UcGV}%N7Uy}IjNV=O|gi#3c`?pr= zMEyu@KkGaN-KYtm3`DKE%}-oMtXDp{hQ=)hbr*Ki58veJRaD9mrQmpXZl5lWiqDL@ zD#9@G`#zyh2d)%|&x(-nJS1!C8VnUZ>Ad{}0sAk`Q(8wOf=7EfqTOWYMr#=&q^I!#t4mSL>5hGwK zE6J1RTVBi&k=8%-3)=?SuTjnM0w2!?9k^@p%VwdE0j|;O>-?&JSUxuaI>(!KQqrFP zOP2qy%4LDUGp9DrAt;4n|3PX&Wwy#x+nFdZZn7Ce5>U4Ji78I9C+@0y#5#W)brL~m zxZwDB^J*6Fg0U_%6`*U`U&A;>d#|4$T`H0GZ$J*jXOZS z?5;En{q?#RA8@5|!JLWKqYiq%yU zxG{GG8)p7dp-owpbTa_g4gxr&Y> z;Kw*p8v&m z2$&m-=;g%MDh?a$Tt%Pb{*(Jhg_{Qk{?Rsxxb%Oa-M24Fy6XSWwEK^(HWWbVC7xD6 z1*8qM*I)4bi*0gMQwXd9&+d|D`oxU@@%b-~F~~2^oRq{uN_W_yh8M>jUF2CGqq=f` zlB_VRDAr07wQjDy-WE_&%CAk@W_92*h*T=ODWM~T1_G}WDg^c~k=KY)nrWyky2Prw_0POFk=7nko9u+HQ^0|%K;tT7q zD~L{2JZ!`A<=yjF=2BTQPeHk56~n9**NVlU5x73Bf3Wih(O`^V9W$EeRIXeL8QqpV zb^qD%Zejwl%$Atcd|JP~jdFhQw3_O&;V{`me!`r9ijytCZbS3a7ph5CShBvk=82U? zMsh|)jY}{sPenxzYvt+OV5(SE$XX0l02wRWoixBg)erE#6-?o}MBN?7;X@?uc>9`z z>oX9dImM(UuR=7NwWbuP>}0rY)JOt2^usZG0U+8Sc%+FST>>;x9t|(OM)#VN!%aAX z;^@`1*?3wwERMjsPkyjgO=f^AoET|o#pvBnR`o9PjZ!^E_?-sm78@z17VX|{AR=2M z-hV0p))GAj6;WRyC>&;r9e;9Y3fLexHf(!^Fqpgwi%Y)*PgPW#Bv2OUE)>)7y^MY%BBkG zU=p+WBC42(qyjf|@K3@W*K9%^am$viZtam7I}O3nlie=P5g{yCvILc7o0i&%W1 zfrz?mWctStry;V`pmNYvNTONiXrY`;`|SNE3Y^u6DtHC6G3d^2;V({qTeHeiXV8?I zfGd9Z8G@-mgkM4UsI|@~3dx&ClvNCg`hT^)Q&m>Z92!ztRWySVaH#!L-6GO#0$!!K z>)po1IKypSi!-QPNC%PbEX|gF#eqi`@nPz}HE=NthX0hJDs^a}X zLqkBL#uBu+8lOHC54446;^WhZkB?_&Wv#fdytpm}u8Hc}6q>eQ=&gAQrv?0k;K@+V zKV|I5W)o61fxMUHNU;GRn*w1;e0Ku(a~z?gw2kUHY&1(tN|$-O?j$~C%sUT0O*?+O z2?TrKAsAD^w0|A~%K8x>Bm*ju+2&Ur@5Bip!i3=f;^p77M<8RkYsim`<9!K$G1`TN znn66vA3Pn7|Hq;L^E86s8SF7KuNk8UOjn?3TB8P}QXDLL9i%nHA8m<5cb7&)XVzed~+-avx;IqpH z*A}J$yl#X~c4hkkb$cV9tc$+ZVH3T2?3;_mi zZs#2K-$I4czamn!kNFqhl>lU+Ne?l~kx{4lF*y57Eai<|hqM#~sY}emP_nKRlZ^;E z;5p$n1k$-x1>##%Tk5nVyFQd4zA8DsD!znRaW5qbVRPU^lfhZnaYgxR9P8kRN*oj{ z>l$wj*}bVvPapsthL62#|7{?>dlh*9t+I61OalO{YP2P^yQC?4v$+R$*pN@rzPfR*bCn|DUmPw-_di+heQXRIc>jrujanhyZg&n%qGC|=vIw>J%J~Vllnokzo z_*4LjfgwO+4Hry5Nx&Zl2g?6ZhARrX&tw6`yEE;q35fIZIPA$+8Eu*>m{NKqug!ZE z&Gi445UuzBNQh2C=x+Y4kwhN@0Q76Pa0N1n5U1AvA8F7MLFvhw8kIny-B`SH9nPF- z{k|5vp#4L*bl4bnDZg?ar|1?f->oHdjP8`m7 zo5Q@%)9iP}1iY@lyhD?j2e$Jc0g=6mg+~Yp32D?2wKTc%KvX}6vWCfzj_+N{x;dg* z*&l0)!?^AO{WB0`%{OvnB04pATcLJT3KxA@ZG?Y*>BN*X6H>hD1e(S;ICqK?g}TY` z`7|xo9t`SR0bve8$n1BDh8?v&5K5bBthW7_{J~7o+Mc#U&r<$gXmV6!QvUqMP^ieq zXL*e!P;Lj+{6fAg<>BA_x*GXC%X};GgL)ozy(&%hEzC=kU(Ol#z{HUu22)L)e$~O| z+3b=Vr@iSW^FHq)MV1kc1FH<8uyoa=;^`Eddwa!s+RqI_AQnRi5jW9?xQ9&UHZDg3 zP9Nu1HbVXQ&Q<$rVs}bi)zcMtDG3Ncn*{MUIiXAK+YK_(E4gL0IHP?ji+N6?u%Cpj zC13(X3V;)MfsI^%wp(QGt9rv%AXE-0k+fB?Pu>7<;nM5^pUjF%Zc6OMtu+7XHe`j$R*VF%SUF1@i4qL;Gty z+VTu+O<%00KLnmC7U8MBB~Bv@I+S><$?z2{ab{e7prpM5=Jt{YG2W>KxlA zke5J)<=5KUg8o$n(T<^^a{q88DyE3DF128->ntv2M(L$w*ybQ?K)wRL$Eovh_K}Cp zEK!HlI^m&f9+>5N#4I;(WJw~H+zhQN#6m`?79*hB-hy)6?C2*e4ruZdoR%xd*che` zcFHS$IdLje7*=Z0NS(mt#|RI0#js){aUI=iw4_4j!JbURnM_s^9^-n@hRC5>!Wty` zN7~@rzDVGWJWo-d6fn))nY%r8lMxz3Gt$obi2Xg(hF85(S?lmp!^n{|yTIRLb<;}zbVgoBtmq)hJ^#GT zaYf+=1yS;ok2@VoSvjv6x$o;pOMkyS&92~A9fjsMmdNqlJMQRZ1`UQ%vw4aT?QC9n znSjFdKh(Iu1M2pAtjz@sZ)W5?DUo)_B{bw*72NdH(+QZ#OKO?H+~*1vOOpWJrI?lt z>l9UJyz1$yuvVsxkCpX&c0X1K)_AE^Lq-37wBC__s4Ah^L^{r!1G$x$DYcs9S{8va z5uHc2MIKRaeLm`|5-=y{vyBFI7%;;hR8E&Wmb<5(EF@=@xg`~_?>*@~AW}K#hL}EU z767(Ceeby|LWo!`mzMAR!Lf-~^Stfi+c3N)jIi;a=sOLo|E@b*v%^=1`Q7KuBO9@* zQA@;Dz5UfKddikLqFNIJy1(n*RhiBe3+L%w{9x|dfK%|DM<)%HGz^ZPHKv#726Q@V zS!qltm&%H{y&v(r&aMVeLQ#zF1O*IzM6JQ&U&j!ia^>=9%WU*G5(<#CcL-;48{te~zL+YpmLn;#jkzeXg(_|D zH*UdaOo;wbys=!eO0&@vHkN+{qJrGv0>8}KS?1&Atgwsc(%XfUDP= z=sE$>RRVhOMZH7XlD85)Q{e6O7am?eewP<0OYi|Q9_4IjiqOHjvwm_K z=KZ}_t)%0svu+j;!|!$0Y#L3jSr2E zzm}ok<_)Y5s@DCl99FuYrM`%a0Sh^vdJiOdq&B{o;Kvax-w35;u-zWuWX@ zdVOqoKpz~G&4c-q-_%RHCUl%<=M*pT@LU6K;Q_sl(bGRmvB<>7)VfJ`YuQUyr$YC1 zp6BF%I4AF6ot5ayN1y^k|2s`9P$4bbJ>a0;KK+KywyW>`qs4M^xE`W(mov2X^kSJy z5K9_F0y_Fts^ZMPqBF;NGcOOhREl$P+7sQ3`Uj7deKCF{NBb6*8#gS%d=M|mMZ5&uv-20S9$I+qW@^RBhnbc3?_#z3RBnww z1Yc}=9OSc+IM?)SaCB^BD+oi-xd4mfl??Kz^;HMqA+Z}d6t6e!omP+jj>d4j=p7y2 z-HDdzUDQi!c$D3L;Iqo;{i}LL5nCyJr?&$6ApA3jyDY@yHQD6Lnx_pf?05z6i(tp9v{L)=snY=aY4c_Re z?p#;qqwg+a(L6gF2iU*eQqjwu$d7%g3oUE6`TwW}5P~zo?XLvm^)6*2a6PN@sk3?@ z$8`mFrSAiR2D7lR9-_&^c!in6?`XA-Ldc_3Ac9x|_b&`1;C4i(hwV1X*jrv*HVD-h z7SCkgEAoX&1UUaDj=$~wJ%X4jWt?KO+(BBeggnfi>R`b@vPV)k!#s)yKHS_3*|l_# zdS?t8*8Ht0jt%kHX-8Jax<^B4?fLma=5gCCYQvvHz)TO-{do2h=JgP zzG;W~pT&}s+&sFHu<&+!*YA<{LGPRoL|aG-ypK^s!40}eM1=9)#(=v&;>0uK zUPiPPC!A=9(2;pG8FrJb#@(cF7IB(6KfK0Yjcxb-R(4n0bCw|BK^WE_OlL=&vxPXb z*}O7G3zj46OUaPmTW6OGvuKF|Z5R}R-;j`%LIEk)HOTrc^UGc?tlD4lpv|E9cAtV6 zOXV1(6HvE}Dlzd(R6B z_t^zA6&G)tFt-)bjc;8ThBRzYTIq7M-R3K6s`zEH?sci5=6U=s!D*58BrL~sqTH70 zC`pTcMt|5s$S_M8{@GG?e~M==z@j+x(IVGh?ENVU_L)=hw1(AohTAV4215Yd?JWL@ zODWM_R8*8Yi;rPXQXYb#hT$s;OYKb-Q1iKoGXmOtyt#0n@i<&=6TT=R+KJosIlTMm zWq;|L&IHkn1&6rZRJRSjUO#bpxSNR4olvDJHjmE`M9@|DX7q92-e_FART-zZh-wsuL9XreWtPsaCi>wZ_R28J`P zPzx7X`Af6@iwoerGA_gF>ET~Y+HD|P5*<=pt|O7kC>>JkI(8XUOx5%38Y~VGJd&ay z$ej%?JOXE}jw$wnwylwwsQ;CIN<*N42EAYLZvv_Y*91oDHy!6<`YG#*7kW99=gQp; zyD^Sp8Df;ZYR@jsqB*Pg1>@r^E^yI*^X~+RA2rxdI1r)-LBgWrhlLSEB5-r?VYLP$ zOHjh-&(^l?P_h~LjFonNr@tr5+4nE^YzU6@7tQ#qHe2~~M*VCGeBOfm;t`@|GRb=- zCKreOB{!%W<`e~&%b?rDu(_q@kr7b&k>Z~(%`{H`qW{qiShQ{ZFZ^I_ZGgNvQok=Z zXiB^5to58F>IEZ_+}{aw0lD2Tb%_uoHl4{_kDVya6gg6cLJckCEQDG})j*@pUAx_O zjpw9liK%}0_}p;XE$4Aro~ilxkOG{T_5OF1=Q4Uir>p&P_j|%3L_o}gdQ_`$7Henh zg|Z6!Q)K2dB1&q1=dg(qk6n(Vz9H7m=(43`-MvbXMS)Ww*|IcD0YE5@Pi`dJPB;v?`zhQ;zsL&|AHoZB zlvG;S&Npz~@w&5=fOkppeL0EXCX76Qhbd1ilm52VxiCd*x@NHWH5e}9(C_;T90Ea_ z*pBMhWL=CAAgAnl&W`!@gtc*PLqw+aX{ zcdT73R4C3oa5Y${{lR0lJ0f2sc0IAFs)`5d_WRkX2XDbDOyz+Ky1={?>sTs zc}Rt3i5sPEFIb2j9#p zR(GcoE_{~9FGkmMqPZ6aI8J^L2&>ACCWWsCw!%~^a>^Ix^j1&j4D-_L!qf?+?*R^+ z0kF`!K1yT=I1MmBQ_m}75n5S(Lwl=e`lxV5=NXz^!;(LQ)wG)%2^n?7LL=or_du+C z++guwt38fy`fPJP4`a3HRX3#$f*aeM*wdA1vGB}w`n}d(9r38S2>$6YkKFg~-$x2Q9Xo4LMXlzt!kQBgyR>l%)65$0)$6?7 z#tzb~3td}b-}h$^kBCS=IdNsdZ34ozFWB#NXKI!16Sa~|8)+X!w=KOFk+RP?t8P4t zX4gUqJ&sEiz9?%ew^()5IoyXoK7TT4I)M>HQN4&V<#9QcgQom5hO%IeXZ_-X>*DRc z*qdJ5Pzfb$(3k0+jxH5?0f8q8 zdH_P$_wCy=7AnnZ>vT|%47Gl@;2e8P+>RVgw7+>_8CJ|Q6Ht(~HH0byJFh6Md(HHT zL4Eg=$(jR?R_l#}jYnROS++Vl#;2p_u9WoXiTgLSTh1t9moKej_!k z!$jXdaW{q1F!|W65jp?q|HjS5l?yJkP2hJhRe#z4eZ^MrVBvv>Nqb1g_XnS{IAP(& zOMFIVo5c;a>z8thuC56c1B-q{y`a7GnO{pz5nadk)qDmDS8WX){?(e9Cr0FDXJMTQ z(7PT-u{aKcY7AP7AvN=_lApNbgU~8>E69=JT)mayV0DHqs20)p$bguoO=A^45i5(ccvpWEj3;+}zxEWOQ{?!1a*lnDdz_l3=$>_|1atU6Y-%%QNm zI6LeHOJlBw=aPSZ*yWt}()o_0)7+w@s|hF?HX(7EKbtef>6JHe^!IdB1ybdWHCiZR@V_?(lQi zPfX9R4|wS?)+i0%-Y*NzJ2uUc3YgKBH1fLKG(uz@ps`2E#S@^oT-`jIJjO-{2rq!7 zGU+iIzvEgi+;hJ`6Ug$VlnuILW|sAjbwenu{rKr~{O#omu`ztb4dLmBBTb`(=<$-> zmT~r(BaP+RfYHc1%fS+GQEeMdgnGU{cR4zpEV8INa!PUeCMB^(cAPGGAe)w)DXQ|e zL>flm_29#6)0ru>?PuL=7w0-?o>=(%l~-k7+!;;5*a>8uJegZ|ibJfCi(VQwK_?)!cXy4v;nLiY?)Xy2>wvEIVqw*O zKST{j)s3N{XP1<6;C%_^eoc*@vbyn+bl4(jJ93u~_`Ha+#U2Eb$AEf+^ZI835eDO( z*PKD%3U2q*=7mL1SWCSmLxS{c!}S*=!o@svr7>?cGU!D#d5!$f4o_A{@pWvbk|nXc ze_XCQ6>JQJU2Ix;xcMD#!d|mJ=VVYPHKJsp}!jqSu{$jDaT4j)P5hqcQ2OP9vAP2@#~Vqew8pNrr93w^{z?V1GUb{V>tF}`HaS7La60P!sl2*(&)5p6HYEy6}i5| zeVibAx%gbY$-{7~8ja_6@2sAMX~;Mh{x)pG47%~?Lpx~wil(ihmtk=_%EE3C$`s?4IkX{mNsO-&W^mojb$9ETwCYH%(4Y!#9Hq2v!^Ra`?r_$Wy;p z4B94+#V+u$)k)lrq`!)g*eXb9N8y)OQ2U@re>h3a5D;Aw!eU5<{078*I zSJ57zha6fvQP1O(0uxC2JMb0*5a*vhSizjXk?DOC(T{InJ zz57uA-Z)OfiHbuo;?;$Q*)R^jXwZq8z>3OKu)3dggbmtz99@m=>lz)c8!lMDQ%o|66SX@;EFinSrFF&EYw!psa#7LJB$m zwgG$4^J%MFlM-Pjl^d){>0g#j1m3u$($?#Tta`T%vS3E4aS6Nw0?ng^-KB?v98&zZ zDbw$VrhU!2h$R8Sf-}RJ`S*bFYvF^n7#>(W5YxiG8JFD>EU4!#JyBH!PuV_jjWaPb znIEkfy!M>0I_xO1mwc6bA&qaQW%p$*Yj?q8pLQ7E$Jb%16+sjr7oU%eTSsT2I|UQx z5N5tAG zl{>ck6&7IwEnYkf*Ujx>nNOWnhZ>jy|`cS38@(y(=Hh1TmPt3_WQqze4{j6WuXN#*Z#t3J|sW+Y}4IFR4i z67WfLyESdHyBxJXKhgZ?NG=QhfD|Sfk?ym)2A{RHNr=9V%8VEJ;=lc+VdqzF{tmaC zKn8LLb=8MA*+HyEqt=>-V_tR>W)X;c6Kva<9pb@En>L-lW>m?3h>bOmB~jK}UBU$l zjwKa6oo01&^Iu4YW^PKk|2Zu%i3^7Bmq+$3cm1Rm!E)RAqPcLm;DRbop>t%3#tS-X zaT(avojT6gk{TFnM=Ud;+N(5ge{YQvt(m?Nn%kkZI5v7Nkl*%=&Xu9HXxeU{s4>x^ zM@xkbg|a~hQ;7$Ch;KOF3>}2wt>&AT`@K7w&H1A5-KdwMRKN&{1xhk)>?spkIh3m@0~l`T61G`j6Kn|lS*(zSwj?WTxu*ScHV#{%0{&~?`%5zIpLPU0i{qs zCEL8Fe>=b~rLKkM#TXo61t34~`V`7FDKUtaWdMJ>LE76;;ed;CGZ3|5YO`Z^ORV z*(hT$oTG4}3@N10u!s&|PNrqTL88yl4Vd#=;%&bv)u+*Z72I zA}4Z7KfDvp8(e+;qbg>T(x=PL6HGkKcp;L`GKJvqT)XI&say@xwUdWUorf zXz?%+HnR=-fSCAQHnyl_N1g_2lwT>gzjpro?Sh;kkHH=L`L?>m=KQY*%?C$Ku56sX zF=?u~!dMbeeRf!8o;ElmTBR^oYOzOld+w@BEL~Ul@S;-l4wIg;?b3~vfJ2>#mKjNf zTm*F{$D7h#ET5=IdcFy!e95;v1>WupV$GG)*SV7R*sWRAYm~I<3$kkRZYoe*<`DOd zxrI0gzsoc&*(JoqICUOS&GrQuI&Gtjte~Ssl@3R`YpCA;<4kLUIQey(=$^UB>4tlG znN#@d^vEFdiR>vUM;G`(*&~zf!H3dzcMsImX&XPcmqyyTUMLkRDi|$B)+*3Yq?P2> zbH<7L?K~a$&<={f#X_eu1^RSmVyRfm?Tr(iGi8oI{dn5X+appoy4$o!1kVLxLA9Xs zrbQ0hC+g}1Q6!|CuU!1>cmDCy$h_y4TQeCr;w)!2Mw)$ix^{WeemJIOc|@6RpW4gUGcz5pn8O} z=U0t(-CMuNKPpBndTX;>VlSM?{PF1WLR_l#R~6XEntPhh)c3hZ#?8~zp^qQ4UAsC) ziKU?QfrFdl#xuS`m1n93e(wyeugw1+1a+V>I{EV}2boCB6PJLQgy;`9tzotEE&4S8{oVGq+iJ z8V&(DWqd*3o?7k)TQ&wU1-|GFe4^)Cnwqai#7(Si82Vr9L3fWZnjJ^40sF6Nm&*G? zd487ICvr%M`5HQ2E=#HPtou2h#l9jgP(2&r~)$wrGIr*X`+=+dyTA0QnNGrMPGoTHfQ zmZy7e^2lPqw<0w*QaY0SnIVq|b(->xLR}&2EvL}XCx;E=T1R>KUnd6b>nRUxhTbd; z`sT>d?lu(_T55E|bb0RUI&M7#)vIxzNuY2speWdo+*E6FknT;T=lq)Wz4X}Fm7t7w zU{3mH!wAWF%^OVwi91;sYtfWSY3VE1DjL>#I0}agvB^4h*71gfNukH>V~T(Wpgv;`j#-^#FFkpvW}jZF-`G$3I`>OkZCaV zh8;SnHl)&eMBtM2&h&crXT%k;EG8`ZI=>%dM(5X}#XrTDrE;#no#;2#-O8GalvWxh z97p&WSi|v&occhbWgld{dGi)r`Ugt`?97LM(FK)(7Ob|)YpmC?oFAJGKglG+U)8ZQ zJ*SFr+O4U7ePx1aH=^enBDk5Lam?)+5CH5&@C_tGxoO(xh#Q zNqV&-poE}W->Y;cVi0cb5|@SWcW3SZBUrVofya;YpLXs_xtmvRe+vIrpQK(yCm!Cx zmAd=6-co6Hm4f$>+?g#v0XNnbvHybh;sdBVNy0*VD4TBh{~R&L-o|Ytll9 zxu8nbSbCsgG;n9~3S!PxPsBT-bOFKjd-iw;+ZDn#I6M#24QA^O<0_X${O1Cx#_RjL zffAP>!5z|k)ljIjw&H6h&LM37HL0E^kzXIL`%4|$R_k|34(TS7<{`usUvR{-m_U|Adg7GC>Qk4_pGDW)9>c#AJ#7B z1Lc)|*6hFcc3*wm$_MnV&o$zTd>Q9WhS|h2{kO;7@l+{!m0x1xqeZp5Nh;qPyXnip z2!)q*?bV}urUisVY@f|panTRZyaDZxhM+zd^wTmY`jC|b(z~_T()z{|{VFh@dgo?` zU8&r~ETwq!nNLXpdT-{(~5M4JqhEA5jL_zZdlDA|N2j#1Vx1Qg>qNZd}U3q}+{3P%&a zX7FOc;(PHvqZZXdvT|@9@9ZDB$n6&w4Ikz(lIF7od{+Sn&BhE>cMTFuVp&>I@2Ska zenO}*PXBUGNJBH+Nbwn;eR!0HjuXg~WSSJuQ)f(Pb2Pd?)GVmHQ2qxEYXV-8jVowb z5!HBQkK!yEzu(d@>KGS?#AcrL5B%U)z=?dmxYP2gt3WRo(X6mBOc`m&HAWQ@g1b(C zLH@ZV36*jPz5c+Of&TPA{eqWu%v5V>MhJ@wo8MAmKu1S$qpGCjIKK8%S-JP*)E9FL zo>F~OU;(OA`B^2<)#?VuvUzP+U+Ah?9o-cE&`cuJ+6FjBnEuj9bpg>z8TVmFv8L%e zwYSO)e!S^qyR+;YuAEHaQ8&=w>>#oJWbqrSEa?TaO8ULhA62)oknk~#5DPFlY`J*H zlU&IuHRueEq}4|o6?=FdeQP@J)ARc(=Isj`eX*@Rd0KIS0|?DnQaP|K?h+N#cQ z<06rw!UHpQL7i-tAcbre^Rmw$*k52{mVraz{zu-P-@Qy80pJe}`DIr0&_n92{vW>} zUf6L5$(7h~3V30FxfD%jfyf7-qiK*x2BU;hpX9zNc4otrn4{QM#d=5IDedI&Gx zREj_hei1X-DQ>pU7@_qpYQ7V7w=FgE&As`3oAVpB{EZP}+vjV6y{7g2z9bad`R7kn z+$?m>jt~s&ks{%u(mENsFz7Z^9*&k1}yvMmhQhz;`t0yg#S!1dB0#XL-WHGHz-6Gi?^|hwkgUk@|r(d zSXj8{86|j9-WSp&!7@R>d2x{af$!vxpyIkKT|HDM5M=PI6$2b4=WyG;qkq3j`er`; zfybbkcYQH?13DoHS_(*{#{lob=n_52VuGHaA45O>bC3A@7r=nV058XsnI=a+-o>pL zLr7XGv!Y*x{_!7cQq(j!qL@x9_;*GbS`k_SUXxS&5_&>Wpyp>jXlL7;z6CH6a8mtY zBvHlSS(`{|4*V0KFElw^s3PjikouEEq|;SHV^5uQ$RHIuVM6FAJ)tZ3bOV6d@%ecZ zp`zl%6|XVAwJ%Fb>79|4*B{cJw(V)?c{#DQw)G2NB3D7z*hN!@iUiP$ zU#|LgQwxo@M!%=^Cb&38Y~i{EL2C&ip|GeQe)`MZ{d8sj&;rRHw&P{{e^8u?9r6Ol z%)`$n{O40}1faN+AXOatFyuYLye2{$=)QVV5Ego~1t`7G_#l!%A06>HAB#b2Ktv|^ z`fRH!nt?60687|W&>HGPpk`KfQfCECwyR(O)`*L>XtJHJ2ef&T8b@$OL{UAU+B5%E z8vZkdCJ7)&m+1YIbTTwm<^jd72c2Iy zWxUg`5>wS+Fm%7dt3P|w>8B}wFx~km2D;O|J)71eu*)=p43uXBoqkG%Qm>ErazI-@ znbu8AP08&zsFMk(_6`*ngF{oJy*^q~sbb2o9P{L-p#HpbjjcioO4*6h}%*%B2qRwXHa=_OpHSfy%9lTdL;+ z0s)k82~6H*2Xan#1`WJ~QE!#H2B<<187N`bJlHB!Y2bQkX=!uyvl1h@{{DXB29Lrd zg_#khu(mVZa0Hmq=Mwt=mw38>o2>e=8m`rGQ$y9D8N#8 zMjQhUiD0uf5cVjBSyhT}^Rs&37Frfgqy@}0_Q4Z*n~TvfYO6pSfkh$5 zfuB$hFvKrDM>$7SM6rpnvHu}q^YOtFRHC}Ct7~c$V-&$rb)3p<8yTc#cgBcQSE0!< zq9>P5&MWW&5fxD&dHqQ6Ol;hsdnP>rnv*qg_gvMSY2Z^23H(}~%;8}qLpa9YWcz!p zGgd`^T2}rb@Eayp(X~7=+p~hj2AcqG8C_Rz#89gE5Hy9881Pg+>u+(m@e`bpM`C#%e{qEhnPTIP!6wVt=k=O+c z__8e5gT&{p2v`5<0^V;}k^oJ%Xkch7o9G&JIO_K^Gt49F^x7BJj4f=Yyo6fE!2=s1 zn0twl@WA=xd(&+Tpvv%|K&QlX@od#MZrvL7$B46sSQgU36@@ZGFHC8XyTte``Y-2GNRO$NcO2N%W*D1K9obaG=o*6qBWZ?G}$2 zU|W+E^h^XL;JK)`&*RMBZVt*X!rj^)Q?gL;-g&fdTV3-F|7A&V8y1y~A|jlE)4w{7 zpP%3VPACNxjQBGa`5eu$fRWlw020*nzdIZkbhB^wQgz9)Pspc@)jP;~qwre4Z3lC@ zxr|b3?tyK@G6&~X{!fMs1I@b=#iK5b>faK$HjNCwC*s+wAz5DWNuz=hsDFO7l%p~Z z!|Y7zoHp9|`ER6NpD-P4D97u1(Tq}KBy)qkv;hFV=IQCn2v}uB+lo9x^sK85>%KY4 zFkn9_TR;0Azsp?xPg+uX*K_fl=G@7rCyWGSG`zi$ZwbR1YYFS3kxQ&dDmUNajlE`0)En8-TSmZ1PVgr&;{Z6RrdIK=1wyHCb zYI%yBm#TKw_yz@$AphKR(h{5D_`&7<&R3O-VgpW$mJ31VOG9wg_Xi!f#I$dElx*N# zy;^kyl#rjTHEg{jnQnG65%$)qJ+I1!#Hcg8ayLU^W^%gH&%4t^;nbuG_6FxhllYED zBnBooF`$Q0<_7?p>T9g|f-t^*`=(VW=kd45l3X2@r!aBvGLTO=HCiFc&8>k$M8DNO za(zPT`hZ&6@niXc^DL-{WTY*#Q8nzqrOmnBrhX0O{)Y6qw4#J8w0;Ms%O4jlT=kx+Y04n znc=PW=Z5e7m}m|wu~wgxaHNhig7;;B@HCtCiiuUI>al9tQDWKtZBQ@VaSj24 zcYO`APeVz`gQ#v~?HFS0{o~66RT7Sc@j?V&{M24lS`T<*H@%p>}Q+5zx(0701he) zJNHyqAp!Vo5$B})l-I>|6nP_RnW$RNuCG8l8B~;Zm7AFkCH^#8Fnr1N;RQ0$xP*kA zRaZ-{PO9%sK!q-`AZbwRzH73Elz9h7OZ8dHhEt;lkY<>?8%j9;Q|#I=T;8 zyi-tgc``}-|6!KZft1cFB(e4th)ra8u|Xp?`f<-ev$svygC|8s(WhlA2{?2ksaOE0 z?)32d^XVZ}0MFFC3`oKM9ErH1pbiyisVpCj{>58Ti+ZC9t9tI!zYFdKMoX&j-98Zb z1#XfYOa=yq#f1gx9>@E9f6i#|n$*AVA|VWrSDask`=r7&^u;MRaNdUzU71C5!+8yG zGkLT*ebV;~JXg(n<=~MI6?)MUT)>J+rw>dTuu6+T!+;Yp;P?6RmoKS+S37$@rds zj*Y@lKh;*aTi}-ZBN|PX^_*ao6Qd1@?=O;9_GcR{%b5OK)Q*`gY{+2cX|QsTVNIfm zefpl@LF^>unQhkKV`!_02$F{7%@0Qgw+<&!>CI0ijxKeHo&GJD6WETwH|}&#{y(?r zf9&Aa`vQNa_M1GvWrwLXU0wp`uT46YmDB6Q|NIhh^~VXvo=)auM2mXr&J!6j!6Fn& zSaNfZrx{u78|lvJV4_=GUASd;vw-nkHaQtd@m_&E^T#|6A#SthtnGOd+E4Q<$dRAA=tMo2KX z()$hX02jI^0C6KHDY0xD|wW*f1p3Bj42Ht4{rmc zr`j-ol;;&FoCN8qXkLMS@LmH4)%$k{bu<^8V_d)Woq(fsxKx+5T+8m}kc`F!kh!xM zUYorvIUAXtOHmE~RbHNt>?|*C)ID_YDq41{&xV`Lji2K_$9Ety1#yu-Y!@;OxsjdFs~b|W_;$Q){Q6Lc z>)YW&E|G}U)rEmN-S}EIAl(m`ofX>|Zm`SR_~POf835Qbz8b=P;3^B0nkB39X&j1GuVQk-0;D z6pWB#{Jz@0pM$QGxz@fJ1}dhCL7KGD(<(*YcD)lKLQ>8R{G_aG0`?Ez$ugbOSM}~B z(I1H4gICp+=V=M>Q~s<`o_8?q`EbK5G4|{nApRKzTzo-sq5$m=P(_AVx5tjm@d=*y z%<#E~%?5hGmFJ@gS4v0bMn%P0ts$7ghu4A;f6K~SAS?I@*9OsEL#mfD``?=nHuID` zkC)2{e@gINYO1~)TNmGw@BWLsJ7$dHwjGTA?DdL358GjN)ia|7jTQU$$gfHK3(xyz zx{;{+Nr{(IMiy(Dotm@WWqW>UDra|j+_E>v{J`(jL)pX#1S&o{PZOFv7B*sj^4ns# zXGNx3e*{I5b72ggq_KEP|3rTo(|8&%L%MC}&6(k=og_|em?_Gh`2JI&J!3v1=V;?PjR5~Hy2LXO9dt3pg8<}nS z8U~6zSO61R-bMWIRp#RfBUt%J+x>um1ui*Xqq37Gh0rKdcYxJFL?l%T$*UZ@g$*In zecoK(u+m6ZfYMI(KrNK$SM0i+Q3h>!t?#5mE?~fqCFO4_CH+pVOkye(_v7$?pWL0%s-o-)ZNM8G8!ClvKmoU zU@93+E7U?mtY95iB8^rgYV_Ujcj!1s(6STlVo>Ni#rTPB@B2V$^BZN`}mAE)c==k=-CIt;M+ZzN5Pn5p@<%E)H z1q$Jx-g}G?F`PpTULPytq;S;O_29e84ZS+N(1?wqTC&m)kfb80bgLylJSrZfgpr z*|^!k$CTH0-7^%+H>_fnra*|W$eE)zk@B`>Y&hHRs>IOWJ_FO#xFqBN@s*<16!M3N zzNuM3{d6bwTaGuiEi(F+^*j2`{RWgllvHQL!NP=`=b$YfBqXl*M_wz4jLy`~|odx=D$+VusTuCcE*ryd)h{2w$x*-&2 zfwx>bQlz#0v$y(~lI>&%(Uifu226ckI#$S$IYA~mq?IS_>ZkV2*8k&!_R%-fM9)!~ zzSnK-cHZ=O%&W)%ihR6!m=@<08wvnw$3d z#y#FX3XgocEqreL%u+h90)$@6KNU(>_fdV7xl%zNWSc7`Fuye6FxED{S_DE>H>0?v zW{ZW(VtW2sA_($=Dk)it&=M6fiJCo&HPUKipHgIap^CwlPAv5 zoKf?4^QT_OMk9XON-LhOtFBtB@#Xf#&kJ(*BPmFQ21I@?Z+7lri_X~|AAQFO%za0v z&@iK#v4Y$Tnb?wN=x%;JSv(r(KdSwT6gj%WHM+aC;V>y4iS4Gf17Cs7$YkZX zxa1P0z=Mh(O3XiprKOg{=f1Q^b&J2Z+r&xn{AgRgmG*k3M4+#)&mRGk_riM?P85){ z*v5}Mq!zg_5=(F7m;JLHz}`6!%Ailck3!}r#-mfZ1_4;gqUBo9qzVIxqYBoPA72n7m*JFk=Y`(Tg8KWu$TS+ zN-e+{=?Lz85I8ND%;%LUC9>;?PjKP#`hF^qoj+4(t%N4PeKLWIKE>-iBe&t&)zyg( zYCraZ%LTf~kaCRfWq9G-Z>&OHuMe;6j+f;Jp|<$s7?;-C&-EVP=t?PX>TcBD{vyjL zj<^bp)}D^9>O~H0y}kn6{ac9rf0<`|{!$lGz@+>jcY>j3gChIJx_dEqvq=S|oS!I0 zeWmW(K5(xJ0$mut$|HZk!~DOs8z-Ci3-}>)sw}xg#Bbje1bGQwxX-R-e?1^|9&Nep zOYQFQ7V+&s?$b%o^JHb048Vmc46WTPZej@o$U@+Pm{46mCnvK3`vy!!l`4O|>nTG$ z9Hnq1$LL7JP)%K1OR_B^msJNkg!s4bZkN)Qd3{KiKfb60jA`ph8fD3YU+;=3DCh-d zCQLyd_is6Gr3Gqpg37i5GBBU0zp8@kDa2zR6dXzR*Y+*;C`{hc)a-mYF)4jD`L$iT z>wAalmac!Jj^u6Fhh@NvpTYJUVEg09-bTNc8Zvv8U2LZ5>Tjq`Qkk6Aj98s*fWw8v z)4PX#DIMpAbj>C?FPsIQ&Vxp`-CaianIWxMjoBHv=NS4#-cE7gZYRx9;l`uw+>u*# z8iPEjN;HW4H<Z^$q+Y@-SWv_2TK*-F6;Adbf8N=Y&po z{?eNiM7wj)d=7#Y4BAs(sc5Lpm4#>_>8_GxYj74;=Vw-x$uswlZf!G9zBaOsJ5yE` z2Eb-%j6ClN9Uz3n1ujKh8B%+>QbL>earBm&Nm0qD0=WAsGW^+#&D)zE(7|v*8D0xu zsQeRq@8sgmTyfYX+}ylG!PU`>OHPYl!g=ug7NSAzI=iluAszEyr;|E3om`k?CBZPk zkFcc5hH@g9*X+LMY|`n~daEEUIvtHA7EHk{1fUz_yL6oZ4u!R9RsGxkC26}|bYvQ#4q9uUQydU%DW-b1?5k*-i z7yvZ4ibEUc>rnvpzI6+3{R=gFNvqUb1u=P;$C9hrOC8Iz{-4G1vH@D&*tm!GY6O$` zoB?A0sSJ@(-u7B4XYbLsov?r8z;@=OYGsGa7;5%KNFJT8Y5f=J+Ws`M?|*Qv@}C~2 zoSyX>zzKDKL42H{`(^C?8xU_dVy37LE=16E+Q0pv$u3}@<<0P6B9_-N5 zP{jU5oz^ub=g^+&hLAe|_(5~a#RXI*!1a-P^?w0MeX}q(@h3=iWJNxO_|CED!ysziX0xj51s&gUZVRa7U ztAl+2#=YDpVa=?m?bKHgI63^7iMd}~&wrgMEv8z{h+X$Epp1-2V$5Hw*jpm|%Jmni(CtJAWWLj^5AkwZyZeY zb}@l@mr*abzQ0G6iDBeoc5}7Dk~cg@;66{+*fKNz1w2pd48gOTi-kFO?_uPHcxZ#m z$azDw?N?ml`!5!A`iQb%VEj9+EPq3yNK1H->G~uhB`{4%tma;4akAJPdD``DMv+=Yofu<$}^-tG)P;yU4tvhC!O(Kmg(E>k?sO@W>*f8fV>3F!zNC@EXXtS+xKM)Hs-qf zSOHXSZoTCH4>lA0A^OX1A;8~Ca4z~H^xtwk{|fKg0rFD^u)B+;MUU7&4I2sU+z&SC)c;W&WI)poZH+E#gWqT z?_(=X@`Sk(u>_v27i5mkJmV;j{1+J#B6rx2p_gunD6U8}0g6iLr zz^#xVjz+qTBKs`L_ z{DO5ua2w^6xF&mt;X80zMfYVhjgO1KV?Gr*3dpEqqDc{x54M0BF}$T3s>p-CQ(NCW>Qex438{*ddvyuq@a3f^%4Z z-^3I_uvo)LfB$$c5XMk8`OM5a;pd<0=*hqM0YYlPnfYNzFZV+pCl`aRC21Qw3qSo| zNGPmJ5Ey5VA?FWw{^4&xR*QA;`bQ!&_?f+J~(YsxYAGJa5CfPcyg8uDeb77zaq$JA26 literal 0 HcmV?d00001 diff --git a/RAGSDK/MainRepo/langgraph/image_new.png b/RAGSDK/MainRepo/langgraph/image_new.png new file mode 100644 index 0000000000000000000000000000000000000000..8185776d91b85f5c3229282fb58adfbb08eeeff4 GIT binary patch literal 128266 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%0ATdAv<$U~ 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 Dp(Zi- literal 0 HcmV?d00001 diff --git a/RAGSDK/MainRepo/langgraph/langgraph_demo.py b/RAGSDK/MainRepo/langgraph/langgraph_demo.py new file mode 100644 index 000000000..9ff984276 --- /dev/null +++ b/RAGSDK/MainRepo/langgraph/langgraph_demo.py @@ -0,0 +1,498 @@ +import os +import time +from typing import List, TypedDict, Any, Dict +from langchain.chains.llm import LLMChain +from langchain_core.documents import Document +from langchain_core.prompts import PromptTemplate +from langchain_core.retrievers import BaseRetriever +from loguru import logger +from mx_rag.llm import LLMParameterConfig +from mx_rag.storage.vectorstore import MindFAISS +from mx_rag.utils import ClientParam +from paddle.base import libpaddle + + +def evaluate_creator(evaluator, evaluate_type: str): + language = "chinese" + + # prompt_dir is ragas cache_dir will speed evaluate + + def evaluate_generate_relevancy(state): + question = state["question"] + retrieved_contexts = [doc.page_content for doc in state["documents"]] + response = state["generation"] + + datasets = { + "user_input": [question], + "response": [response], + "retrieved_contexts": [retrieved_contexts] + } + + scores = evaluator.evaluate_scores(metrics_name=["answer_relevancy", "faithfulness"], + datasets=datasets, + language=language) + return scores["answer_relevancy"], scores["faithfulness"] + + if evaluate_type == "generate_relevancy": + return evaluate_generate_relevancy + + raise KeyError("evaluate_type not support") + + +def cache_search(cache): + def cache_search_process(state): + logger.info("---QUERY SEARCH ---") + question = state["question"] + generation = cache.search(question) + return {"question": question, "generation": generation} + + return cache_search_process + + +def cache_update(cache): + def cache_update_process(state): + logger.info("---QUERY UPDATE ---") + question = state["question"] + generation = state["generation"] + + cache.update(question, generation) + + return state + + return cache_update_process + + +def decide_to_decompose(state): + logger.info("---DECIDE TO DECOMPOSE---") + cache_generation = state["generation"] + + if cache_generation is None: + logger.warning( + "---DECISION: CACHE MISS GO DECOMPOSE---" + ) + return "cache_miss" + + logger.info("---DECISION: CACHE HIT END---") + return "cache_hit" + + +def decompose(llm): + sub_question_key_words = "Q:" + prompt = PromptTemplate( + template=""" + 请你参考如下示例,拆分用户的问题为独立子问题,如果无法拆分则返回原始问题: + 示例一: + 用户问题: 今天的天气如何, 你今天过的怎么样? + + {sub_question_key_words}今天的天气如何? + {sub_question_key_words}你今天过的怎么样? + + 示例二: + 用户问题: 汉堡好吃吗? + + {sub_question_key_words}汉堡好吃吗? + + 现在请你参考示例拆分以下用户问题: + 用户的问题:{question} + """, + input_variables=["question", "sub_question_key_words"] + ) + + sub_question_generator = LLMChain(llm=llm, prompt=prompt) + + def decompose_process(state): + logger.info("---QUERY DECOMPOSITION ---") + question = state["question"] + + sub_queries = sub_question_generator.predict(question=question, sub_question_key_words=sub_question_key_words) + if sub_question_key_words not in sub_queries: + sub_queries = None + else: + sub_queries = sub_queries.split(sub_question_key_words) + sub_queries = sub_queries[1:] + + return {"sub_questions": sub_queries, "question": question} + + return decompose_process + + +def retrieve(retriever: BaseRetriever): + def retrieve_process(state): + logger.info("---RETRIEVE---") + sub_questions = state["sub_questions"] + question = state["question"] + + documents = [] + docs = [] + if sub_questions is None: + docs = retriever.get_relevant_documents(question) + else: + for query in sub_questions: + docs.extend(retriever.get_relevant_documents(query)) + + for doc in docs: + if doc.page_content not in documents: + documents.append(doc.page_content) + + return {"documents": documents, "question": question} + + return retrieve_process + + +def rerank(reranker): + def rerank_process(state): + logger.info("---RERANK---") + question = state["question"] + documents = state["documents"] + if len(documents) < 2: + return {"documents": documents, "question": question} + scores = reranker.rerank(query=question, texts=documents) + documents = [Document(page_content=content) for content in documents] + documents = reranker.rerank_top_k(objs=documents, scores=scores) + + return {"documents": documents, "question": question} + + return rerank_process + + +def generate(llm): + prompt = PromptTemplate( + template="""{context} + + 根据上述已知信息,简洁和专业的来回答用户问题。如果无法从中已知信息中得到答案,请根据自身经验做出回答 + + {question} + """, + input_variables=["context", "question"] + ) + + rag_chain = LLMChain(llm=llm, prompt=prompt) + + def generate_process(state): + logger.info("---GENERATE---") + question = state["question"] + documents = state["documents"] + + generation = rag_chain.predict(context=documents, question=question) + return {"documents": documents, "question": question, "generation": generation} + + return generate_process + + +def transform_query(llm): + prompt = PromptTemplate( + template=""" + 你是一个用户问题重写员, 请仔细理解用户问题的内容和语义和检索的文档,在不修改用户问题 + 语义的前提下,将用户问题重写为可以更好被矢量检索的形式 + + 用户问题:{question} + """, + input_variables=["question"] + ) + + question_rewriter = LLMChain(llm=llm, prompt=prompt) + + def transform_query_process(state): + logger.info("---TRANSFORM QUERY---") + question = state["question"] + documents = state["documents"] + + better_question = question_rewriter.predict(question=question) + + return {"documents": documents, "question": better_question} + + return transform_query_process + + +def decide_to_generate(state): + logger.info("---ASSESS GRADED DOCUMENTS---") + filtered_documents = state["documents"] + + if not filtered_documents: + logger.warning( + "---DECISION:ALL DOCUMENTS ARE NOT RELEVANT TO QUESTION, TRANSFORM QUERY---" + ) + return "transform_query" + logger.info("---DECISION: GENERATE---") + return "generate" + + +def grade_generation_v_documents_and_question(evaluate, + context_score_threshold: float = 0.6, + answer_score_threshold: float = 0.6): + generate_evalutor = evaluate_creator(evaluate, "generate_relevancy") + + def grade_generation_v_documents_and_question_process(state): + logger.info("---CHECK HALLUCINATIONS---") + + answer_score, context_score = generate_evalutor(state) + + answer_score = answer_score[0] + logger.info("---GRADE GENERATION vs QUESTION---") + if answer_score < answer_score_threshold: + logger.warning(f"---DECISION: GENERATION DOES NOT ADDRESS QUESTION," + f" RE-TRY--- answer_score:{answer_score}," + f"answer_score_threshold:{answer_score_threshold}") + return "not useful" + + logger.info(f"---DECISION: GENERATION ADDRESSES QUESTION--- " + f"answer_score:{answer_score}," + f"answer_score_threshold:{answer_score_threshold}") + + context_score = context_score[0] + logger.info("---GRADE GENERATION vs DOCUMENTS---") + if context_score < context_score_threshold: + logger.warning(f"---DECISION: GENERATION IS NOT GROUNDED IN DOCUMENTS, " + f" RE-TRY--- context_score:{context_score}," + f"context_score_threshold:{context_score_threshold}") + return "not useful" + + logger.info(f"---DECISION: GENERATION GROUNDED IN DOCUMENTS---" + f"context_score:{context_score}," + f"context_score_threshold:{context_score_threshold}") + return "useful" + + return grade_generation_v_documents_and_question_process + + +def create_loader_and_spliter(mxrag_component: Dict[str, Any], + chunk_size: int = 200, + chunk_overlap: int = 50): + from langchain.text_splitter import RecursiveCharacterTextSplitter + + from mx_rag.document import LoaderMng + from mx_rag.document.loader import DocxLoader + + loader_mng = LoaderMng() + loader_mng.register_loader(DocxLoader, [".docx"]) + loader_mng.register_splitter(RecursiveCharacterTextSplitter, [".docx"], + {"chunk_size": chunk_size, "chunk_overlap": chunk_overlap, "keep_separator": False}) + mxrag_component["loader_mng"] = loader_mng + + +def create_remote_connector(mxrag_component: Dict[str, Any], + reranker_url: str, + embedding_url: str, + llm_url: str, + llm_model_name: str): + from mx_rag.llm.text2text import Text2TextLLM + from mx_rag.embedding import EmbeddingFactory + from mx_rag.reranker.reranker_factory import RerankerFactory + + reranker = RerankerFactory.create_reranker(similarity_type="tei_reranker", + url=reranker_url, + client_param=ClientParam(use_http=True), + k=3) + mxrag_component['reranker_connector'] = reranker + + embedding = EmbeddingFactory.create_embedding(embedding_type="tei_embedding", + url=embedding_url, + client_param=ClientParam(use_http=True) + ) + mxrag_component['embedding_connector'] = embedding + + llm = Text2TextLLM(base_url=llm_url, model_name=llm_model_name, + client_param=ClientParam(use_http=True, timeout=240), + llm_config=LLMParameterConfig(max_tokens=4096)) + mxrag_component['llm_connector'] = llm + + +def create_knowledge_storage(mxrag_component: Dict[str, Any], knowledge_files: List[str]): + from mx_rag.knowledge.knowledge import KnowledgeStore + from mx_rag.knowledge import KnowledgeDB + from mx_rag.knowledge.handler import upload_files + from mx_rag.storage.document_store import SQLiteDocstore + + npu_dev_id = 0 + + # faiss_index_save_file is your faiss index save dir + faiss_index_save_file: str = "/home/HwHiAiUser/rag_npu_faiss.index" + vector_store = MindFAISS(x_dim=1024, + devs=[npu_dev_id], + load_local_index=faiss_index_save_file) + mxrag_component["vector_store"] = vector_store + + # sqlite_save_file is your sqlite save dir + sqlite_save_file: str = "/home/HwHiAiUser/rag_sql.db" + chunk_store = SQLiteDocstore(db_path=sqlite_save_file) + mxrag_component["chunk_store"] = chunk_store + + # your knowledge file white paths if docx not in white paths will raise exception + white_paths = ["/home/HwHiAiUser/"] + knowledge_store = KnowledgeStore(db_path=sqlite_save_file) + knowledge_store.add_knowledge("rag", "Default01", "admin") + Knowledge_db = KnowledgeDB(knowledge_store=knowledge_store, chunk_store=chunk_store, vector_store=vector_store, + knowledge_name="rag", white_paths=white_paths, user_id="Default01") + + upload_files(Knowledge_db, knowledge_files, loader_mng=mxrag_component.get("loader_mng"), + embed_func=mxrag_component.get("embedding_connector").embed_documents, + force=True) + + +def create_hybrid_search_retriever(mxrag_component: Dict[str, Any]): + from langchain.retrievers import EnsembleRetriever + from mx_rag.retrievers.retriever import Retriever + + chunk_store = mxrag_component.get("chunk_store") + vector_store = mxrag_component.get("vector_store") + embedding = mxrag_component.get("embedding_connector") + + npu_faiss_retriever = Retriever(vector_store=vector_store, document_store=chunk_store, + embed_func=embedding.embed_documents, k=10, score_threshold=0.4) + + hybrid_retriever = EnsembleRetriever( + retrievers=[npu_faiss_retriever], weights=[1.0] + ) + + mxrag_component["retriever"] = hybrid_retriever + + +def create_cache(mxrag_component: Dict[str, Any], + reranker_url: str, + embedding_url: str): + from mx_rag.cache import SimilarityCacheConfig + from mx_rag.cache import EvictPolicy + from mx_rag.cache import MxRAGCache + + npu_dev_id = 0 + # data_save_folder is your cache file when you next run your rag applicate it will read form disk + cache_data_save_folder = "/home/HwHiAiUser/mx_rag/cache_save_folder/" + + similarity_config = SimilarityCacheConfig( + vector_config={ + "vector_type": "npu_faiss_db", + "x_dim": 1024, + "devs": [npu_dev_id], + }, + cache_config="sqlite", + emb_config={ + "embedding_type": "tei_embedding", + "url": embedding_url, + "client_param": ClientParam(use_http=True) + }, + similarity_config={ + "similarity_type": "tei_reranker", + "url": reranker_url, + "client_param": ClientParam(use_http=True) + }, + retrieval_top_k=3, + cache_size=100, + auto_flush=100, + similarity_threshold=0.70, + data_save_folder=cache_data_save_folder, + disable_report=True, + eviction_policy=EvictPolicy.LRU + ) + + similarity_cache = MxRAGCache("similarity_cache", similarity_config) + mxrag_component["cache"] = similarity_cache + + +def create_evaluate(mxrag_component): + from mx_rag.evaluate import Evaluate + + llm = mxrag_component.get("llm_connector") + embedding = mxrag_component.get("embedding_connector") + mxrag_component["evaluator"] = Evaluate(llm=llm, embedding=embedding) + + +def build_mxrag_application(mxrag_component): + from langgraph.graph import END, START, StateGraph + + class GraphState(TypedDict): + question: str + sub_questions: List[str] + generation: str + documents: List[str] + + llm = mxrag_component.get("llm_connector") + retriever = mxrag_component.get("retriever") + reranker = mxrag_component.get("reranker_connector") + cache = mxrag_component.get("cache") + evaluate = mxrag_component.get("evaluator") + + workflow = StateGraph(GraphState) + workflow.add_node("cache_search", cache_search(cache)) + workflow.add_node("cache_update", cache_update(cache)) + workflow.add_node("decompose", decompose(llm)) + workflow.add_node("retrieve", retrieve(retriever)) + workflow.add_node("rerank", rerank(reranker)) + workflow.add_node("generate", generate(llm)) + workflow.add_node("transform_query", transform_query(llm)) + + workflow.add_edge(START, "cache_search") + + workflow.add_conditional_edges( + "cache_search", + decide_to_decompose, + { + "cache_hit": END, + "cache_miss": "decompose", + }, + ) + + workflow.add_edge("decompose", "retrieve") + workflow.add_edge("retrieve", "rerank") + + workflow.add_edge("rerank", "generate") + workflow.add_edge("transform_query", "cache_search") + workflow.add_conditional_edges( + "generate", + grade_generation_v_documents_and_question(evaluate), + { + "useful": "cache_update", + "not useful": "transform_query" + }, + ) + + workflow.add_edge("cache_update", END) + app = workflow.compile() + return app + + +if __name__ == "__main__": + mxrag_component: Dict[str, Any] = {} + + # mis tei rerank + mis_tei_reranker_url = "http://ip:port/rerank" + # mis tei embed + mis_tei_embedding_url = "http://ip:port/embed" + + # mindie llm server + llm_url = "http://ip:port/v1/chat/completions" + + # llm model name like Llama3-8B-Chinese-Chat etc + llm_model_name = "Llama3-8B-Chinese-Chat" + + # your knowledge list + knowledge_files = ["/home/HwHiAiUser/doc1.docx"] + + create_loader_and_spliter(mxrag_component, chunk_size=200, chunk_overlap=50) + + create_remote_connector(mxrag_component, + reranker_url=mis_tei_reranker_url, + embedding_url=mis_tei_embedding_url, + llm_url=llm_url, + llm_model_name=llm_model_name) + + create_knowledge_storage(mxrag_component, knowledge_files=knowledge_files) + + create_cache(mxrag_component, + reranker_url=mis_tei_reranker_url, + embedding_url=mis_tei_embedding_url) + + create_hybrid_search_retriever(mxrag_component) + + create_evaluate(mxrag_component) + + rag_app = build_mxrag_application(mxrag_component) + + user_question = "your question" + + start_time = time.time() + user_answer = rag_app.invoke({"question": user_question}) + end_time = time.time() + + logger.info(f"user_question:{user_question}") + logger.info(f"user_answer:{user_answer}") + logger.info(f"app time cost:{(end_time - start_time) * 1000} ms") diff --git a/RAGSDK/MainRepo/langgraph/requirements.txt b/RAGSDK/MainRepo/langgraph/requirements.txt new file mode 100644 index 000000000..c4c9f4ee5 --- /dev/null +++ b/RAGSDK/MainRepo/langgraph/requirements.txt @@ -0,0 +1,2 @@ +langgraph==0.2.19 +langchain_core==0.2.43 \ No newline at end of file diff --git a/RAGSDK/MainRepo/sd_samples/README.md b/RAGSDK/MainRepo/sd_samples/README.md new file mode 100644 index 000000000..06e4ef319 --- /dev/null +++ b/RAGSDK/MainRepo/sd_samples/README.md @@ -0,0 +1,151 @@ +# 安装stable-diffusion运行文生图参考样例说明 + +## 安装前准备 + +1)安装部署mindie +Service容器,镜像及部署指导参考[链接](https://www.hiascend.com/developer/ascendhub/detail/af85b724a7e5469ebd7ea13c3439d48f) + +此处只需使用mindie Service镜像和软件包安装包,无需执行部署大模型相关操作 + +2)注意运行的环境不能有torch-npu,如果存在,需卸载; 运行模型依赖MindIE Service 1.0.R2及以上的版本 + +3)下载SD 模型,下载链接如下 + +https://huggingface.co/stabilityai/stable-diffusion-2-1-base + +4) 下载MindIE Service适配代码,并切换到指定节点 + +``` +git clone https://gitee.com/ascend/ModelZoo-PyTorch.git +git checkout a6cef84ca2cce2413a3c34baa1649e05def18b67 +``` + +5)对stable_diffusion_pipeline文件打补丁 + +复制当前指导文件所在目录下的补丁文件 stable_diffusion_pipeline_parallel_web.patch 和stable_diffusion_pipeline_web.patch到 +ModelZoo-PyTorch/MindIE/MindIE-Torch/built-in/foundation/stable_diffusion目录下 + +```bash +cd ModelZoo-PyTorch/MindIE/MindIE-Torch/built-in/foundation/stable_diffusion +patch -p0 stable_diffusion_pipeline_parallel.py < stable_diffusion_pipeline_parallel_web.patch +patch -p0 stable_diffusion_pipeline.py < stable_diffusion_pipeline_web.patch +``` + +6)安装MindIE Service依赖 + +``` +pip3 install fastapi>=0.110.0 uvicorn diffusers + +pip3 install -r requirements.txt +``` + +7)设置环境变量 + +``` +source /usr/local/Ascend/mindie/set_env.sh +``` + +8)打stable_diffusion补丁 + +``` +python3 stable_diffusion_clip_patch.py +python3 stable_diffusion_attention_patch.py +python3 stable_diffusion_unet_patch.py +``` + +9)导出pt模型并进行编译 + +``` +(根据执行步骤3下载权重路径适配修改如下变量) +model_base="./stable-diffusion-2-1-base" +``` + +导出pt模型: + +``` +python3 export_ts.py --model ${model_base} --output_dir ./models \ + --parallel \ + --use_cache +``` + +参数说明: + +--model:模型名称或本地模型目录的路径 + +--output_dir: pt模型输出目录 + +--parallel:【可选】模型使用双芯/双卡并行推理 + +--use_cache: 【可选】模型使用UnetCache优化 + +--use_cache_faster: 【可选】模型使用deepcache+faster融合方案 + +10)启动web服务执行推理 + +不使用并行: + +``` +python3 stable_diffusion_pipeline.py \ + --model ${model_base} \ + --prompt_file ./prompts.txt \ + --device 0 \ + --save_dir ./results \ + --steps 50 \ + --scheduler DDIM \ + --soc Duo \ + --output_dir ./models \ + --use_cache +``` + +使用并行时: + +``` + python3 stable_diffusion_pipeline_parallel.py \ + --model ${model_base} \ + --prompt_file ./prompts.txt \ + --device 0,1 \ + --save_dir ./results \ + --steps 50 \ + --scheduler DDIM \ + --soc Duo \ + --output_dir ./models \ + --use_cache +``` + +参数说明: + +--model:模型名称或本地模型目录的路径。 + +--prompt_file:输入文本文件,按行分割。 + +--save_dir:生成图片的存放目录。 + +--steps:生成图片迭代次数。 + +--device:推理设备ID;可用逗号分割传入两个设备ID,此时会使用并行方式进行推理。 + +--scheduler: 【可选】推荐使用DDIM采样器。 + +--soc: 硬件配置,根据硬件配置选择Duo或者A2。 + +--output_dir: 编译好的模型路径。 + +--use_cache: 【可选】推荐使用UnetCache策略。 + +--use_cache_faster: 【可选】模型使用deepcache+faster融合方案。 + +上面步骤可参考[MindIE Service](https://gitee.com/ascend/ModelZoo-PyTorch/tree/master/MindIE/MindIE-Torch/built-in/foundation/stable_diffusion#stable-diffusion%E6%A8%A1%E5%9E%8B-%E6%8E%A8%E7%90%86%E6%8C%87%E5%AF%BC) +指导 + +# 大模型测试 + +执行如下命令生成dog.jpeg文件 + +``` +curl http://127.0.0.1:7860/text2img \ + -X POST \ + -d '{"prompt":"dog wearing black glasses", "output_format": "jpeg", "size": "512*512"}' \ + -H 'Content-Type: application/json' | awk -F '"' '{print $2}' | base64 --decode > dog.jpeg +``` + + diff --git a/RAGSDK/MainRepo/sd_samples/stable_diffusion_pipeline_parallel_web.patch b/RAGSDK/MainRepo/sd_samples/stable_diffusion_pipeline_parallel_web.patch new file mode 100644 index 000000000..e932c72c9 --- /dev/null +++ b/RAGSDK/MainRepo/sd_samples/stable_diffusion_pipeline_parallel_web.patch @@ -0,0 +1,277 @@ +diff --git a/MindIE/MindIE-Torch/built-in/foundation/stable_diffusion/stable_diffusion_pipeline_parallel.py b/MindIE/MindIE-Torch/built-in/foundation/stable_diffusion/stable_diffusion_pipeline_parallel.py +index 76c7e606c..7a07a3793 100644 +--- a/MindIE/MindIE-Torch/built-in/foundation/stable_diffusion/stable_diffusion_pipeline_parallel.py ++++ b/MindIE/MindIE-Torch/built-in/foundation/stable_diffusion/stable_diffusion_pipeline_parallel.py +@@ -13,13 +13,20 @@ + # limitations under the License. + + import argparse ++import base64 + import csv + import json + import os ++import io + import time + from typing import Callable, List, Optional, Union + import numpy as np + ++import uvicorn ++from fastapi import FastAPI, HTTPException ++from pydantic import BaseModel ++from fastapi.responses import Response ++ + import torch + import mindietorch + from mindietorch import _enums +@@ -29,6 +36,10 @@ from diffusers import DPMSolverMultistepScheduler, EulerDiscreteScheduler, DDIMS + from background_runtime import BackgroundRuntime, RuntimeIOInfo + from background_runtime_cache import BackgroundRuntimeCache, RuntimeIOInfoCache + ++app = FastAPI() ++pipe = None ++args = None ++ + clip_time = 0 + unet_time = 0 + vae_time = 0 +@@ -37,84 +48,6 @@ p2_time = 0 + p3_time = 0 + scheduler_time = 0 + +-class PromptLoader: +- def __init__( +- self, +- prompt_file: str, +- prompt_file_type: str, +- batch_size: int, +- num_images_per_prompt: int = 1, +- ): +- self.prompts = [] +- self.catagories = ['Not_specified'] +- self.batch_size = batch_size +- self.num_images_per_prompt = num_images_per_prompt +- +- if prompt_file_type == 'plain': +- self.load_prompts_plain(prompt_file) +- +- elif prompt_file_type == 'parti': +- self.load_prompts_parti(prompt_file) +- +- self.current_id = 0 +- self.inner_id = 0 +- +- def __len__(self): +- return len(self.prompts) * self.num_images_per_prompt +- +- def __iter__(self): +- return self +- +- def __next__(self): +- if self.current_id == len(self.prompts): +- raise StopIteration +- +- ret = { +- 'prompts': [], +- 'catagories': [], +- 'save_names': [], +- 'n_prompts': self.batch_size, +- } +- for _ in range(self.batch_size): +- if self.current_id == len(self.prompts): +- ret['prompts'].append('') +- ret['save_names'].append('') +- ret['catagories'].append('') +- ret['n_prompts'] -= 1 +- +- else: +- prompt, catagory_id = self.prompts[self.current_id] +- ret['prompts'].append(prompt) +- ret['catagories'].append(self.catagories[catagory_id]) +- ret['save_names'].append(f'{self.current_id}_{self.inner_id}') +- +- self.inner_id += 1 +- if self.inner_id == self.num_images_per_prompt: +- self.inner_id = 0 +- self.current_id += 1 +- +- return ret +- +- def load_prompts_plain(self, file_path: str): +- with os.fdopen(os.open(file_path, os.O_RDONLY), "r") as f: +- for i, line in enumerate(f): +- prompt = line.strip() +- self.prompts.append((prompt, 0)) +- +- def load_prompts_parti(self, file_path: str): +- with os.fdopen(os.open(file_path, os.O_RDONLY), "r", encoding='utf8') as f: +- # Skip the first line +- next(f) +- tsv_file = csv.reader(f, delimiter="\t") +- for i, line in enumerate(tsv_file): +- prompt = line[0] +- catagory = line[1] +- if catagory not in self.catagories: +- self.catagories.append(catagory) +- +- catagory_id = self.catagories.index(catagory) +- self.prompts.append((prompt, catagory_id)) +- + + class AIEStableDiffusionPipeline(StableDiffusionPipeline): + device_0 = None +@@ -983,10 +916,19 @@ def parse_arguments(): + help="Steps to use cache data." + ) + ++ parser.add_argument( ++ "--port", ++ type=int, ++ default=7860, ++ help="The port number used by fastapi." ++ ) ++ + return parser.parse_args() + + + def main(): ++ global args ++ global pipe + args = parse_arguments() + save_dir = args.save_dir + +@@ -1006,89 +948,66 @@ def main(): + pipe.compile_aie_model() + mindietorch.set_device(pipe.device_0) + +- skip_steps = [0] * args.steps ++ args.skip_steps = [0] * args.steps + +- flag_cache = 0 ++ args.flag_cache = 0 + if args.use_cache: +- flag_cache = 1 ++ args.flag_cache = 1 + for i in args.cache_steps.split(','): + if int(i) >= args.steps: + continue +- skip_steps[int(i)] = 1 +- +- use_time = 0 +- prompt_loader = PromptLoader(args.prompt_file, +- args.prompt_file_type, +- args.batch_size, +- args.num_images_per_prompt) +- +- infer_num = 0 +- image_info = [] +- current_prompt = None +- for i, input_info in enumerate(prompt_loader): +- prompts = input_info['prompts'] +- catagories = input_info['catagories'] +- save_names = input_info['save_names'] +- n_prompts = input_info['n_prompts'] +- +- print(f"[{infer_num + n_prompts}/{len(prompt_loader)}]: {prompts}") +- infer_num += args.batch_size +- +- start_time = time.time() +- if args.scheduler == "DDIM": +- images = pipe.ascendie_infer_ddim( +- prompts, +- num_inference_steps=args.steps, +- skip_steps=skip_steps, +- flag_cache=flag_cache, +- ) +- else: +- images = pipe.ascendie_infer( +- prompts, +- num_inference_steps=args.steps, +- skip_steps=skip_steps, +- flag_cache=flag_cache, +- ) ++ args.skip_steps[int(i)] = 1 + +- if i > 4: # do not count the time spent inferring the first 0 to 4 images +- use_time += time.time() - start_time + +- for j in range(n_prompts): +- image_save_path = os.path.join(save_dir, f"{save_names[j]}.png") +- image = images[0][j] +- image.save(image_save_path) ++class ImageRequest(BaseModel): ++ prompt: str ++ output_format: str ++ size: str = "512*512" + +- if current_prompt != prompts[j]: +- current_prompt = prompts[j] +- image_info.append({'images': [], 'prompt': current_prompt, 'category': catagories[j]}) + +- image_info[-1]['images'].append(image_save_path) ++@app.post("/text2img") ++async def text2image(image_request: ImageRequest): ++ prompt = image_request.prompt ++ output_format = image_request.output_format ++ height = int(image_request.size.split("*")[0]) ++ width = int(image_request.size.split("*")[1]) ++ if output_format.lower() not in ["png", "jpeg", "jpg", "webp"]: ++ raise HTTPException(status_code=400, detail="Invalid output format") + +- infer_num = infer_num - 5 # do not count the time spent inferring the first 5 images +- print(f"[info] infer number: {infer_num}; use time: {use_time:.3f}s\n" +- f"average time: {use_time / infer_num:.3f}s\n" +- f"clip time: {clip_time / infer_num:.3f}s\n" +- f"unet time: {unet_time / infer_num:.3f}s\n" +- f"vae time: {vae_time / infer_num:.3f}s\n" +- f"p1 time: {p1_time / infer_num:.3f}s\n" +- f"p2 time: {p2_time / infer_num:.3f}s\n" +- ) +- if hasattr(pipe, 'device_1'): +- if (pipe.unet_bg): +- pipe.unet_bg.stop() ++ if output_format == "jpg": ++ output_format = "jpeg" + +- if (pipe.unet_bg_cache): +- pipe.unet_bg_cache.stop() ++ global args ++ global pipe + +- # Save image information to a json file +- if os.path.exists(args.info_file_save_path): +- os.remove(args.info_file_save_path) ++ if args.scheduler == "DDIM": ++ images = pipe.ascendie_infer_ddim( ++ [prompt], ++ height = height, ++ width = width, ++ num_inference_steps=args.steps, ++ skip_steps=args.skip_steps, ++ flag_cache=args.flag_cache, ++ ) ++ else: ++ images = pipe.ascendie_infer( ++ [prompt], ++ height = height, ++ width = width, ++ num_inference_steps=args.steps, ++ skip_steps=args.skip_steps, ++ flag_cache=args.flag_cache, ++ ) + +- with os.fdopen(os.open(args.info_file_save_path, os.O_RDWR | os.O_CREAT, 0o640), "w") as f: +- json.dump(image_info, f) ++ image = images[0][0] + +- mindietorch.finalize() ++ image_byte_arr = io.BytesIO() ++ image.save(image_byte_arr, format=output_format) ++ image_byte_arr.seek(0) ++ return base64.b64encode(image_byte_arr.read()) ++ # return Response(content=image_byte_arr.getvalue(), media_type=f"image/{output_format.lower()}") + + + if __name__ == "__main__": + main() ++ uvicorn.run(app, host="0.0.0.0", port=args.port) +\ No newline at end of file diff --git a/RAGSDK/MainRepo/sd_samples/stable_diffusion_pipeline_web.patch b/RAGSDK/MainRepo/sd_samples/stable_diffusion_pipeline_web.patch new file mode 100644 index 000000000..70264e1c1 --- /dev/null +++ b/RAGSDK/MainRepo/sd_samples/stable_diffusion_pipeline_web.patch @@ -0,0 +1,279 @@ +diff --git a/MindIE/MindIE-Torch/built-in/foundation/stable_diffusion/stable_diffusion_pipeline.py b/MindIE/MindIE-Torch/built-in/foundation/stable_diffusion/stable_diffusion_pipeline.py +index a953ae480..b470ffdec 100644 +--- a/MindIE/MindIE-Torch/built-in/foundation/stable_diffusion/stable_diffusion_pipeline.py ++++ b/MindIE/MindIE-Torch/built-in/foundation/stable_diffusion/stable_diffusion_pipeline.py +@@ -13,19 +13,30 @@ + # limitations under the License. + + import argparse ++import base64 + import csv + import json + import os ++import io + import time + from typing import Callable, List, Optional, Union + import numpy as np + ++import uvicorn ++from fastapi import FastAPI, HTTPException ++from pydantic import BaseModel ++from fastapi.responses import Response ++ + import torch + import mindietorch + from mindietorch import _enums + from diffusers import StableDiffusionPipeline + from diffusers import DPMSolverMultistepScheduler, EulerDiscreteScheduler, DDIMScheduler, SASolverScheduler + ++app = FastAPI() ++pipe = None ++args = None ++ + clip_time = 0 + unet_time = 0 + vae_time = 0 +@@ -34,84 +45,6 @@ p2_time = 0 + p3_time = 0 + scheduler_time = 0 + +-class PromptLoader: +- def __init__( +- self, +- prompt_file: str, +- prompt_file_type: str, +- batch_size: int, +- num_images_per_prompt: int = 1, +- ): +- self.prompts = [] +- self.catagories = ['Not_specified'] +- self.batch_size = batch_size +- self.num_images_per_prompt = num_images_per_prompt +- +- if prompt_file_type == 'plain': +- self.load_prompts_plain(prompt_file) +- +- elif prompt_file_type == 'parti': +- self.load_prompts_parti(prompt_file) +- +- self.current_id = 0 +- self.inner_id = 0 +- +- def __len__(self): +- return len(self.prompts) * self.num_images_per_prompt +- +- def __iter__(self): +- return self +- +- def __next__(self): +- if self.current_id == len(self.prompts): +- raise StopIteration +- +- ret = { +- 'prompts': [], +- 'catagories': [], +- 'save_names': [], +- 'n_prompts': self.batch_size, +- } +- for _ in range(self.batch_size): +- if self.current_id == len(self.prompts): +- ret['prompts'].append('') +- ret['save_names'].append('') +- ret['catagories'].append('') +- ret['n_prompts'] -= 1 +- +- else: +- prompt, catagory_id = self.prompts[self.current_id] +- ret['prompts'].append(prompt) +- ret['catagories'].append(self.catagories[catagory_id]) +- ret['save_names'].append(f'{self.current_id}_{self.inner_id}') +- +- self.inner_id += 1 +- if self.inner_id == self.num_images_per_prompt: +- self.inner_id = 0 +- self.current_id += 1 +- +- return ret +- +- def load_prompts_plain(self, file_path: str): +- with os.fdopen(os.open(file_path, os.O_RDONLY), "r") as f: +- for i, line in enumerate(f): +- prompt = line.strip() +- self.prompts.append((prompt, 0)) +- +- def load_prompts_parti(self, file_path: str): +- with os.fdopen(os.open(file_path, os.O_RDONLY), "r", encoding='utf8') as f: +- # Skip the first line +- next(f) +- tsv_file = csv.reader(f, delimiter="\t") +- for i, line in enumerate(tsv_file): +- prompt = line[0] +- catagory = line[1] +- if catagory not in self.catagories: +- self.catagories.append(catagory) +- +- catagory_id = self.catagories.index(catagory) +- self.prompts.append((prompt, catagory_id)) +- + + class AIEStableDiffusionPipeline(StableDiffusionPipeline): + def parser_args(self, args): +@@ -890,10 +823,19 @@ def parse_arguments(): + help="Steps to use cache data." + ) + ++ parser.add_argument( ++ "--port", ++ type=int, ++ default=7860, ++ help="The port number used by fastapi." ++ ) ++ + return parser.parse_args() + + + def main(): ++ global args ++ global pipe + args = parse_arguments() + save_dir = args.save_dir + +@@ -912,90 +854,73 @@ def main(): + pipe.scheduler = SASolverScheduler.from_config(pipe.scheduler.config) + pipe.compile_aie_model() + +- skip_steps = [0] * args.steps ++ args.skip_steps = [0] * args.steps + +- flag_cache = 0 ++ args.flag_cache = 0 + if args.use_cache: +- flag_cache = 1 ++ args.flag_cache = 1 + for i in args.cache_steps.split(','): + if int(i) >= args.steps: + continue +- skip_steps[int(i)] = 1 ++ args.skip_steps[int(i)] = 1 + +- use_time = 0 +- prompt_loader = PromptLoader(args.prompt_file, +- args.prompt_file_type, +- args.batch_size, +- args.num_images_per_prompt) +- +- infer_num = 0 +- image_info = [] +- current_prompt = None + + mindietorch.set_device(args.device) + +- for i, input_info in enumerate(prompt_loader): +- prompts = input_info['prompts'] +- catagories = input_info['catagories'] +- save_names = input_info['save_names'] +- n_prompts = input_info['n_prompts'] +- +- print(f"[{infer_num + n_prompts}/{len(prompt_loader)}]: {prompts}") +- infer_num += args.batch_size + +- start_time = time.time() + +- if args.scheduler == "DDIM": +- stream = mindietorch.npu.Stream("npu:" + str(args.device)) +- with mindietorch.npu.stream(stream): +- images = pipe.ascendie_infer_ddim( +- prompts, +- num_inference_steps=args.steps, +- skip_steps=skip_steps, +- flag_cache=flag_cache, +- ) +- else: +- images = pipe.ascendie_infer( +- prompts, +- num_inference_steps=args.steps, +- skip_steps=skip_steps, +- flag_cache=flag_cache, +- ) ++class ImageRequest(BaseModel): ++ prompt: str ++ output_format: str ++ size: str = "512*512" + +- if i > 4: # do not count the time spent inferring the first 0 to 4 images +- use_time += time.time() - start_time + +- for j in range(n_prompts): +- image_save_path = os.path.join(save_dir, f"{save_names[j]}.png") +- image = images[0][j] +- image.save(image_save_path) ++@app.post("/text2img") ++async def text2image(image_request: ImageRequest): ++ prompt = image_request.prompt ++ output_format = image_request.output_format ++ height = int(image_request.size.split("*")[0]) ++ width = int(image_request.size.split("*")[1]) + +- if current_prompt != prompts[j]: +- current_prompt = prompts[j] +- image_info.append({'images': [], 'prompt': current_prompt, 'category': catagories[j]}) ++ if output_format.lower() not in ["png", "jpeg", "jpg", "webp"]: ++ raise HTTPException(status_code=400, detail="Invalid output format") + +- image_info[-1]['images'].append(image_save_path) ++ if output_format == "jpg": ++ output_format = "jpeg" + +- infer_num = infer_num - 5 # do not count the time spent inferring the first 5 images +- print(f"[info] infer number: {infer_num}; use time: {use_time:.3f}s\n" +- f"average time: {use_time / infer_num:.3f}s\n" +- f"clip time: {clip_time / infer_num:.3f}s\n" +- f"unet time: {unet_time / infer_num:.3f}s\n" +- f"vae time: {vae_time / infer_num:.3f}s\n" +- f"p1 time: {p1_time / infer_num:.3f}s\n" +- f"p2 time: {p2_time / infer_num:.3f}s\n" +- f"p3 time: {p3_time / infer_num:.3f}s\n" +- f"scheduler time: {scheduler_time / infer_num:.3f}s\n") ++ global args ++ global pipe + +- # Save image information to a json file +- if os.path.exists(args.info_file_save_path): +- os.remove(args.info_file_save_path) ++ if args.scheduler == "DDIM": ++ stream = mindietorch.npu.Stream("npu:" + str(args.device)) ++ with mindietorch.npu.stream(stream): ++ images = pipe.ascendie_infer_ddim( ++ [prompt], ++ height = height, ++ width = width, ++ num_inference_steps=args.steps, ++ skip_steps=args.skip_steps, ++ flag_cache=args.flag_cache, ++ ) ++ else: ++ images = pipe.ascendie_infer( ++ [prompt], ++ height = height, ++ width = width, ++ num_inference_steps=args.steps, ++ skip_steps=args.skip_steps, ++ flag_cache=args.flag_cache, ++ ) + +- with os.fdopen(os.open(args.info_file_save_path, os.O_RDWR | os.O_CREAT, 0o640), "w") as f: +- json.dump(image_info, f) ++ image = images[0][0] + +- mindietorch.finalize() ++ image_byte_arr = io.BytesIO() ++ image.save(image_byte_arr, format=output_format) ++ image_byte_arr.seek(0) ++ return base64.b64encode(image_byte_arr.read()) ++ # return Response(content=image_byte_arr.getvalue(), media_type=f"image/{output_format.lower()}") + + + if __name__ == "__main__": + main() ++ uvicorn.run(app, host="0.0.0.0", port=args.port) +\ No newline at end of file diff --git a/RAGSDK/PocValidation/README.md b/RAGSDK/PocValidation/README.md new file mode 100644 index 000000000..47482ccb1 --- /dev/null +++ b/RAGSDK/PocValidation/README.md @@ -0,0 +1,8 @@ +## 目录结构与说明 + +| 目录 | 说明 | +|----------------------------|-------------| +| chat_with_ascend | 问答场景参考样例 | +| code_with_ascend | 代码补全参考样例 | +| prompt_compressor | promt压缩参考样例 | +| rag_recursive_tree_demo.oy | 递归树检索参考样例 | diff --git a/RAGSDK/PocValidation/chat_with_ascend/app.py b/RAGSDK/PocValidation/chat_with_ascend/app.py new file mode 100644 index 000000000..1ab773228 --- /dev/null +++ b/RAGSDK/PocValidation/chat_with_ascend/app.py @@ -0,0 +1,682 @@ +# -*- coding: utf-8 -*- +# Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + +import argparse +import gradio as gr +import os +import shutil +import sys +from langchain.retrievers import EnsembleRetriever +from langchain.text_splitter import RecursiveCharacterTextSplitter +from langchain_community.document_loaders import TextLoader +from langchain_core.documents import Document +from langchain_core.prompts import PromptTemplate +from loguru import logger +from mx_rag.document.loader import DocxLoader, PdfLoader, ExcelLoader +from mx_rag.embedding.local import TextEmbedding +from mx_rag.embedding.service import TEIEmbedding +from mx_rag.knowledge import KnowledgeStore, KnowledgeDB +from mx_rag.knowledge.handler import upload_files, LoaderMng +from mx_rag.llm import Text2TextLLM, LLMParameterConfig +from mx_rag.reranker.local import LocalReranker +from mx_rag.reranker.service import TEIReranker +from mx_rag.retrievers import Retriever +from mx_rag.retrievers.full_text_retriever import FullTextRetriever +from mx_rag.storage.document_store import SQLiteDocstore, MilvusDocstore +from mx_rag.storage.vectorstore import MilvusDB +from mx_rag.utils import ClientParam +from paddle.base import libpaddle +from pymilvus import MilvusClient +from typing import List, Iterator, Dict + +sys.tracebacklimit = 1000 + +user_id = "7d1d04c1-dd5f-43f8-bad5-99795f24bce6" + +default_prompt = """<指令>以下是提供的背景知识,请简洁和专业地回答用户的问题。如果无法从已知信息中得到答案,请根据自身经验做出回答。<指令>\n背景知识:{context}\n用户问题:{question}""" +llm_prompt = default_prompt +# 初始化知识管理关系数据库 +knowledge_store = KnowledgeStore(db_path="./knowledge_store_sql.db") + +KnowledgeDB_Map = {} + +milvus_url = "http://127.0.0.1:19530" + + +# 创建新的知识库 +def get_knowledge_db(knowledge_name: str): + knowledge_name = get_knowledge_ename(knowledge_name) + if knowledge_name in KnowledgeDB_Map.keys(): + return KnowledgeDB_Map["knowledge_name"][2] + logger.info(f"get knowledge_name:{knowledge_name}") + index_name, db_name = get_db_file_names(knowledge_name) + + milvus_url = os.environ.get("milvus_url") + milvus_client = MilvusClient(milvus_url) + vector_store = MilvusDB.create(client=milvus_client, x_dim=int(os.environ.get("embedding_dim")), + collection_name=f"{knowledge_name}_vector") + chunk_store = MilvusDocstore(milvus_client, collection_name=f"{knowledge_name}_chunk") + + knowledge_store.add_knowledge(knowledge_name, user_id=user_id) + # 初始化知识库管理 + knowledge_db = KnowledgeDB(knowledge_store=knowledge_store, + chunk_store=chunk_store, + vector_store=vector_store, + knowledge_name=knowledge_name, + white_paths=["/tmp"], + user_id=user_id) + KnowledgeDB_Map["knowledge_name"] = (vector_store, chunk_store, knowledge_db) + + return vector_store, chunk_store, knowledge_db + + +# 创建检索器 +def creat_dense_retriever(knowledge_name: str, top_k, score_threshold): + vector_store, chunk_store, _ = get_knowledge_db(knowledge_name) + # 初始化文档chunk关系数据库 + dense_retriever = Retriever(vector_store=vector_store, + document_store=chunk_store, + embed_func=text_emb.embed_documents, + k=top_k, + score_threshold=score_threshold) + + return dense_retriever + + +def creat_sparse_retriever(knowledge_name: str, top_k): + _, chunk_store, _ = get_knowledge_db(knowledge_name) + # 初始化文档chunk关系数据库 + sparse_retriever = FullTextRetriever( + document_store=chunk_store, + k=top_k) + + return sparse_retriever + + +# 删除知识库 +def delete_knowledge_db(knowledge_name: str): + knowledge_name = get_knowledge_ename(knowledge_name) + knowledge_names = knowledge_store.get_all_knowledge_name(user_id) + + if knowledge_name in knowledge_names: + _, _, knowledge_db = get_knowledge_db(knowledge_name) + # 删除知识中的所有信息,包含文件,文本,向量 + knowledge_db.delete_all() + milvus_url = os.environ.get("milvus_url") + milvus_client = MilvusClient(milvus_url) + vector_store = MilvusDB.create(client=milvus_client, x_dim=int(os.environ.get("embedding_dim")), + collection_name=f"{knowledge_name}_vector") + chunk_store = MilvusDocstore(milvus_client, collection_name=f"{knowledge_name}_chunk") + + vector_store.drop_collection() + chunk_store.drop_collection() + + return get_knowledge_info() + + +# 获取知识库列表 +def get_knowledge_info(): + knowledge_info = knowledge_store.get_all_knowledge_info(user_id) + knowledge_names = [info.knowledge_name for info in knowledge_info] + return knowledge_names, len(knowledge_names) + + +# 获取知识库中文档列表 +def get_document(knowledge_name: str): + _, _, knowledge_db = get_knowledge_db(knowledge_name) + doc_names = [doc_model.document_name for doc_model in knowledge_db.get_all_documents()] + return knowledge_name, doc_names, len(doc_names) + + +# 清空知识库中文档列表 +def clear_file_in_kg(knowledge_name: str): + knowledge_name, doc_names, doc_cnt = get_document(knowledge_name) + if doc_cnt > 0: + _, _, knowledge_db = get_knowledge_db(knowledge_name) + for doc_name in doc_names: + knowledge_db.delete_file(doc_name) + return get_document(knowledge_name) + else: + return knowledge_name, doc_names, 0 + + +# 删除知识库中的文件 +def delete_document_in_kg(knowledge_name: str, files: str): + _, _, knowledge_db = get_knowledge_db(knowledge_name) + for file in files.split(","): + knowledge_db.delete_file(file) + + doc_names = [doc_model.document_name for doc_model in knowledge_db.get_all_documents()] + return knowledge_name, doc_names, len(doc_names) + + +def set_llm_prompt(prompt: str): + global llm_prompt + llm_prompt = prompt + + +def get_llm_prompt(): + global llm_prompt + return llm_prompt + + +# 上传知识库 +def file_upload(files, + knowledge_db_name: str = 'test_poc', + chunk_size: int = 750, + chunk_overlap: int = 150 + ): + save_file_path = "/tmp/document_files" + knowledge_db_name = get_knowledge_ename(knowledge_db_name) + # 指定保存文件的文件夹 + if not os.path.exists(save_file_path): + os.makedirs(save_file_path) + if files is None or len(files) == 0: + print('no file need save') + + _, _, knowledge_db = get_knowledge_db(knowledge_db_name) + + # 注册文档处理器 + loader_mng = LoaderMng() + # 加载文档加载器,可以使用mxrag自有的,也可以使用langchain的 + loader_mng.register_loader(loader_class=TextLoader, file_types=[".txt", ".md"]) + loader_mng.register_loader(loader_class=DocxLoader, file_types=[".docx"]) + loader_mng.register_loader(loader_class=PdfLoader, file_types=[".pdf"]) + loader_mng.register_loader(loader_class=ExcelLoader, file_types=[".xlsx", ".xls"]) + + # 加载文档切分器,使用langchain的 + loader_mng.register_splitter(splitter_class=RecursiveCharacterTextSplitter, + file_types=[".docx", ".txt", ".md", ".pdf", ".xlsx", ".xls"], + splitter_params={"chunk_size": chunk_size, + "chunk_overlap": chunk_overlap, + "keep_separator": False + }) + for file in files: + try: + # 上传领域知识文档 + shutil.copy(file.name, save_file_path) + # 知识库:chunk\embedding\add + upload_files(knowledge_db, [file.name], loader_mng=loader_mng, embed_func=text_emb.embed_documents, + force=True) + print(f"file {file.name} save to {save_file_path}.") + except Exception as err: + logger.error(f"save failed, find exception: {err}") + + +def file_change(files, upload_btn): + print("file changes") + + +def get_db_file_names(knowledge_name: str): + index_name = "./" + knowledge_name + "_faiss.index" + db_name = "./" + knowledge_name + "_sql.db" + return index_name, db_name + + +def get_knowledge_ename(knowledge_name: str): + if knowledge_name is None or len(knowledge_name) == 0 or ' ' in knowledge_name: + return 'test' + else: + return knowledge_name + + +# 历史问题改写 +def generate_question(history, llm, history_n: int = 5): + prompt = """现在你有一个上下文依赖问题补全任务,任务要求:请根据对话历史和用户当前的问句,重写问句。\n + 历史问题依次是:\n + {}\n + 用户当前的问句:\n + {}\n + 注意如果当前问题不依赖历史问题直接返回none即可\n + 请根据上述对话历史重写用户当前的问句,仅输出重写后的问句,不需要附加任何分析。\n + 重写问句: \n + """ + if len(history) <= 2: + return history + cur_query = history[-1][0] + history_qa = history[0:-1] + history_list = [f"第{idx + 1}轮:{q_a[0]}" for idx, q_a in enumerate(history_qa) if q_a[0] is not None] + history_list = history_list[:history_n] + history_str = "\n\n".join(history_list) + re_query = prompt.format(history_str, cur_query) + new_query = llm.chat(query=re_query, llm_config=LLMParameterConfig(max_tokens=512, + temperature=0.5, + top_p=0.95)) + if new_query != "none": + history[-1][0] = "原始问题: " + cur_query + history += [[new_query, None]] + return history + + +def merge_query_prompt_by_metadata(docs: List[Document], prompt: str): + final_prompt = "" + document_separator = "\n\n" + if len(docs) != 0: + last_doc = docs[-1] + last_doc.metadata["answer"] = (last_doc.metadata["answer"] + + f"{document_separator}{prompt}") + docs[-1] = last_doc + + final_prompt = document_separator.join(x.metadata["answer"] for x in docs) + + return final_prompt + + +def merge_query_prompt_by_content(docs: List[Document], prompt: str): + final_prompt = "" + document_separator = "\n\n" + if len(docs) != 0: + last_doc = docs[-1] + last_doc.page_content = (last_doc.page_content + + f"{document_separator}{prompt}") + docs[-1] = last_doc + + final_prompt = document_separator.join(x.page_content for x in docs) + + return final_prompt + + +def do_stream_query(q_with_prompt: str, llm, llm_config: LLMParameterConfig, question: str, + q_docs: List[Document] = None) -> Iterator[Dict]: + logger.info("invoke stream query") + resp = {"query": question, "result": ""} + resp['source_documents'] = [{'metadata': x.metadata, 'page_content': x.page_content} for x in q_docs] + + for response in llm.chat_streamly(query=q_with_prompt, llm_config=llm_config): + resp['result'] = response + yield resp + + +# 聊天对话框 +def bot_response(history, + history_r, + max_tokens: int = 512, + temperature: float = 0.5, + top_p: float = 0.95, + history_n: int = 5, + score_threshold: float = 0.5, + top_k: int = 1, + chat_type: str = "RAG检索增强对话", + show_type: str = "不显示", + is_rewrite: str = "否", + knowledge_name: str = 'test_poc' + ): + chat_type_mapping = {"RAG检索增强对话": 1, + "仅大模型对话": 0} + show_type_mapping = {"对话结束后显示": 1, + "检索框单独显示": 2, + "不显示": 0} + is_rewrite_mapping = {"是": 1, + "否": 0} + # 初始化检索器 + knowledge_name = get_knowledge_ename(knowledge_name) + dense_retriever = creat_dense_retriever(knowledge_name, top_k, score_threshold) + sparse_retriever = creat_sparse_retriever(knowledge_name, top_k) + + # 历史问题改写 + if is_rewrite_mapping.get(is_rewrite) == 1: + history = generate_question(history, llm, history_n) + history[-1][1] = '推理错误' + try: + # 仅使用大模型回答 + if chat_type_mapping.get(chat_type) == 0: + response = llm.chat_streamly(query=history[-1][0], + llm_config=LLMParameterConfig(max_tokens=max_tokens, + temperature=temperature, + top_p=top_p)) + # 返回迭代器 + for res in response: + history[-1][1] = res + yield history, history_r + # 使用RAG增强回答 + elif chat_type_mapping.get(chat_type) == 1: + hybrid_retriever = EnsembleRetriever( + retrievers=[dense_retriever, sparse_retriever], weights=[0.7, 0.3] + ) + q_docs = hybrid_retriever.invoke(history[-1][0]) + if reranker is not None: + score = reranker.rerank(history[-1][0], [doc.page_content for doc in q_docs]) + q_docs = reranker.rerank_top_k(q_docs, score) + + prompt = PromptTemplate.from_template(llm_prompt) + + query = prompt.format(context="\n\n".join(doc.page_content for doc in q_docs), question=history[-1][0]) + + response = do_stream_query(query, llm, q_docs=q_docs, question=history[-1][0], + llm_config=LLMParameterConfig(max_tokens=max_tokens, + temperature=temperature, + top_p=top_p, + stream=True)) + + # 不展示检索内容 + if show_type_mapping.get(show_type) == 0: + for res in response: + history[-1][1] = '推理错误' if res['result'] is None else res['result'].replace("<", "<").replace( + ">", ">") + yield history, history_r + # 问答结尾展示 + elif show_type_mapping.get(show_type) == 1: + for res in response: + history[-1][1] = '推理错误' if res['result'] is None else res['result'].replace("<", "<").replace( + ">", ">") + q_docs = res['source_documents'] + yield history, history_r + # 有检索到信息 + if len(q_docs) > 0: + history_last = '' + for i, source in enumerate(q_docs): + sources = "\n====检索信息来源:" + str(i + 1) + "[数据库名]:" + str(knowledge_name) + \ + "[文件名]:" + source['metadata']['source'] + "====" + "\n" + \ + "参考内容:" + source['page_content'] + "\n" + history_last += sources + history += [[None, history_last]] + yield history, history_r + # 检索窗口展示 + else: + for res in response: + history[-1][1] = '推理错误' if res['result'] is None else res['result'].replace("<", "<").replace( + ">", ">") + q_docs = res['source_documents'] + yield history, history_r + # 有检索到信息 + if len(q_docs) > 0: + history_r_last = '' + for i, source in enumerate(q_docs): + sources = "\n====检索信息来源:" + str(i + 1) + "[数据库名]:" + str(knowledge_name) + \ + "[文件名]:" + source['metadata']['source'] + "====" + "\n" + \ + "参考内容:" + source['page_content'] + "\n" + history_r_last += sources + history_r += [[history[-1][0], history_r_last]] + yield history, history_r + except Exception as err: + logger.error(f"query failed, find exception: {err}") + yield history, history_r + + +# 检索对话框 +def re_response(history_r, + score_threshold: float = 0.5, + top_k: int = 1, + knowledge_name: str = 'test_poc' + ): + # 初始化检索器 + knowledge_name = get_knowledge_ename(knowledge_name) + retriever_cls = creat_dense_retriever(knowledge_name, top_k, score_threshold) + q_docs = retriever_cls.invoke(history_r[-1][0]) + if len(q_docs) > 0: + history_r_last = '' + for i, source in enumerate(q_docs): + sources = "\n====检索信息来源:" + str(i + 1) + "[数据库名]:" + str(knowledge_name) + \ + "[文件名]:" + source.metadata['source'] + "====" + "\n" + \ + "参考内容:" + source.page_content + "\n" + history_r_last += sources + history_r[-1][1] = history_r_last + else: + history_r[-1][1] = "未检索到相关信息" + return history_r + + +# 检索信息 +def user_retriever(user_message, history_r): + return "", history_r + [[user_message, None]] + + +# 聊天信息 +def user_query(user_message, history): + return "", history + [[user_message, None]] + + +def clear_history(history): + return [] + + +if __name__ == '__main__': + class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter): + def _get_default_metavar_for_optional(self, action): + return action.type.__name__ + + def _get_default_metavar_for_positional(self, action): + return action.type.__name__ + + + parse = argparse.ArgumentParser(formatter_class=CustomFormatter) + parse.add_argument("--embedding_path", type=str, default="/home/data/acge_text_embedding", + help="embedding模型本地路径") + parse.add_argument("--tei_emb", type=bool, default=False, help="是否使用TEI服务化的embedding模型") + parse.add_argument("--embedding_url", type=str, default="http://127.0.0.1:8080/embed", + help="使用TEI服务化的embedding模型url地址") + parse.add_argument("--embedding_dim", type=int, default=1024, help="embedding模型向量维度") + parse.add_argument("--llm_url", type=str, default="http://127.0.0.1:1025/v1/chat/completions", + help="大模型url地址") + parse.add_argument("--model_name", type=str, default="Llama3-8B-Chinese-Chat", help="大模型名称") + parse.add_argument("--tei_reranker", type=bool, default=False, help="是否使用TEI服务化的reranker模型") + parse.add_argument("--reranker_path", type=str, default=None, help="reranker模型本地路径") + parse.add_argument("--reranker_url", type=str, default=None, help="使用TEI服务化的embedding模型url地址") + parse.add_argument("--dev", type=int, default=0, help="使用的npu卡,可通过执行npu-smi info获取") + parse.add_argument("--port", type=int, default=8080, help="web后端端口") + parse.add_argument("--milvus_url", type=str, default="http://127.0.0.1:19530", help="milvus url地址") + + args = parse.parse_args().__dict__ + embedding_path: str = args.pop('embedding_path') + tei_emb: bool = args.pop('tei_emb') + embedding_url: str = args.pop('embedding_url') + embedding_dim: int = args.pop('embedding_dim') + llm_url: str = args.pop('llm_url') + model_name: str = args.pop('model_name') + tei_reranker: bool = args.pop('tei_reranker') + reranker_path: str = args.pop('reranker_path') + reranker_url: str = args.pop('reranker_url') + dev: int = args.pop('dev') + port: int = args.pop('port') + + os.environ["milvus_url"] = args.pop("milvus_url") + os.environ["embedding_dim"] = str(embedding_dim) + + # 初始化test数据库 + knowledge_db = get_knowledge_db('test_poc') + # 配置text生成text大模型chain,具体ip端口请根据实际情况适配修改 + llm = Text2TextLLM(base_url=llm_url, model_name=model_name, client_param=ClientParam(use_http=True)) + # 配置embedding模型,请根据模型具体路径适配 + if tei_emb: + text_emb = TEIEmbedding(url=embedding_url, client_param=ClientParam(use_http=True)) + else: + text_emb = TextEmbedding(model_path=embedding_path, dev_id=dev) + # 配置reranker,请根据模型具体路径适配 + if tei_reranker: + reranker = TEIReranker(url=reranker_url, client_param=ClientParam(use_http=True)) + elif reranker_path is not None: + reranker = LocalReranker(model_path=reranker_path, dev_id=dev, k=3) + else: + reranker = None + + + # 构建gradio框架 + def build_demo(): + with (gr.Blocks() as demo): + gr.HTML("

检索增强生成(RAG)对话

powered by MindX RAG

") + with gr.Row(): + with gr.Column(scale=100): + with gr.Row(): + files = gr.components.File( + height=100, + file_count="multiple", + file_types=[".docx", ".txt", ".md", ".pdf", ".xlsx", ".xls"], + interactive=True, + label="上传知识库文档" + ) + with gr.Row(): + upload_btn = gr.Button("上传文件") + with gr.Row(): + with gr.TabItem("知识库情况"): + knowledge_names, knowledge_name_num = get_knowledge_info() + set_knowledge_name = gr.Textbox(label='设置当前知识库', + value=knowledge_names[0], + placeholder="在此输入知识库名称,默认使用test知识库") + with gr.Row(): + creat_knowledge_btn = gr.Button('创建知识库') + delete_knowledge_btn = gr.Button('删除知识库') + + knowledge_name_output = gr.Textbox(label='知识库列表', value=knowledge_names) + knowledge_number_output = gr.Textbox(label='知识库数量', value=knowledge_name_num) + with gr.Row(): + show_knowledge_btn = gr.Button('显示知识库') + with gr.TabItem("文件情况"): + knowledge_names, knowledge_name_num = get_knowledge_info() + knowledge_name = gr.Textbox(label='知识库名称', value=knowledge_names[0]) + knowledge_file_output = gr.Textbox(label='知识库文件列表') + knowledge_file_num_output = gr.Textbox(label='知识库文件数量') + delete_knowledge_files = gr.Textbox(label='待删除知识库中的文件,使用逗号分隔', value="") + with gr.Row(): + knowledge_file_out_btn = gr.Button('显示文件情况') + knowledge_file_delete_btn = gr.Button('删除指定文件') + knowledge_clear_btn = gr.Button('清空知识库') + with gr.Row(): + with gr.TabItem("设置提示词"): + new_llm_prompt = gr.Textbox(label="提示词", value=default_prompt) + with gr.Row(): + set_llm_prompt_btn = gr.Button('设置提示词') + + with gr.Row(): + with gr.Accordion(label='文档切分参数设置', open=False): + chunk_size = gr.Slider( + minimum=50, + maximum=5000, + value=750, + step=50, + interactive=True, + label="chunk_size", + info="文本切分长度" + ) + chunk_overlap = gr.Slider( + minimum=10, + maximum=500, + value=150, + step=10, + interactive=True, + label="chunk_overlap", + info="文本切分填充长度" + ) + with gr.Row(): + with gr.Accordion(label='大模型参数设置', open=False): + temperature = gr.Slider( + minimum=0.01, + maximum=2, + value=0.5, + step=0.01, + interactive=True, + label="温度", + info="Token生成的随机性" + ) + top_p = gr.Slider( + minimum=0.01, + maximum=1, + value=0.95, + step=0.05, + interactive=True, + label="Top P", + info="累计概率总和阈值" + ) + max_tokens = gr.Slider( + minimum=100, + maximum=1024, + value=512, + step=1, + interactive=True, + label="最大tokens", + info="输入+输出最多的tokens数" + ) + is_rewrite = gr.Radio(['是', '否'], value="否", label="是否根据历史提问重写问题?") + history_n = gr.Slider( + minimum=1, + maximum=10, + value=5, + step=1, + interactive=True, + label="历史提问重写轮数", + info="问题重写时所参考的历史提问轮数" + ) + with gr.Row(): + with gr.Accordion(label='检索参数设置', open=False): + score_threshold = gr.Slider( + minimum=0, + maximum=1, + value=0.5, + step=0.01, + interactive=True, + label="score_threshold", + info="相似性检索阈值,值越大表示越相关,低于阈值不会被返回。" + ) + top_k = gr.Slider( + minimum=1, + maximum=10, + value=3, + step=1, + interactive=True, + label="top_k", + info="相似性检索返回条数" + ) + show_type = gr.Radio(['对话结束后显示', '检索框单独显示', '不显示'], value="对话结束后显示", + label="知识库文档匹配结果展示方式选择") + with gr.Column(scale=200): + with gr.Tabs(): + with gr.TabItem("对话窗口"): + chat_type = gr.Radio(['RAG检索增强对话', '仅大模型对话'], value="RAG检索增强对话", + label="请选择对话模式?") + chatbot = gr.Chatbot(height=550) + with gr.Row(): + msg = gr.Textbox(placeholder="在此输入问题...", container=False) + with gr.Row(): + send_btn = gr.Button(value="发送", variant="primary") + clean_btn = gr.Button(value="清空历史") + with gr.TabItem("检索窗口"): + chatbot_r = gr.Chatbot(height=550) + with gr.Row(): + msg_r = gr.Textbox(placeholder="在此输入问题...", container=False) + with gr.Row(): + send_btn_r = gr.Button(value="文档检索", variant="primary") + clean_btn_r = gr.Button(value="清空历史") + # RAG发送 + send_btn.click(user_query, [msg, chatbot], [msg, chatbot], queue=False + ).then(bot_response, + [chatbot, chatbot_r, max_tokens, temperature, top_p, history_n, score_threshold, + top_k, chat_type, show_type, is_rewrite, set_knowledge_name], + [chatbot, chatbot_r]) + # RAG清除历史 + clean_btn.click(clear_history, chatbot, chatbot) + # 上传文件 + files.change(file_change, [], []) + upload_btn.click(file_upload, [files, set_knowledge_name, chunk_size, chunk_overlap], files) + # 管理所有知识库 + creat_knowledge_btn.click(get_knowledge_db, [set_knowledge_name], []).then(get_knowledge_info, [], + [knowledge_name_output, + knowledge_number_output]) + # 设置大模型提示词 + set_llm_prompt_btn.click(set_llm_prompt, [new_llm_prompt], []) + + show_knowledge_btn.click(get_knowledge_info, [], [knowledge_name_output, knowledge_number_output]) + delete_knowledge_btn.click(delete_knowledge_db, [set_knowledge_name], + [knowledge_name_output, knowledge_number_output]) + # 管理知识库里文件 + knowledge_file_out_btn.click(get_document, [set_knowledge_name], + [knowledge_name, knowledge_file_output, knowledge_file_num_output]) + knowledge_clear_btn.click(clear_file_in_kg, [set_knowledge_name], + [knowledge_name, knowledge_file_output, knowledge_file_num_output]) + + knowledge_file_delete_btn.click(delete_document_in_kg, [knowledge_name, delete_knowledge_files], + [knowledge_name, knowledge_file_output, knowledge_file_num_output]) + # 检索发送 + send_btn_r.click(user_retriever, [msg_r, chatbot_r], [msg_r, chatbot_r], queue=False + ).then(re_response, [chatbot_r, score_threshold, top_k, set_knowledge_name], chatbot_r) + # 检索清除历史 + clean_btn_r.click(clear_history, chatbot_r, chatbot_r) + return demo + + + def create_gradio(ports): + demo = build_demo() + demo.queue() + demo.launch(share=True, server_name="0.0.0.0", server_port=ports) + + + # 启动gradio + create_gradio(port) diff --git a/RAGSDK/PocValidation/chat_with_ascend/images/demo.png b/RAGSDK/PocValidation/chat_with_ascend/images/demo.png new file mode 100644 index 0000000000000000000000000000000000000000..e8c842cf1839ef6cdd3af6a5fd8d323993da8a44 GIT binary patch literal 75898 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�!-zfly&acm=u1(BMuB7z`- z^fKxw3IZxflcFFX7P>%au>qqr8%0_~1f+&4HAJKYX;C5|H9&w!OMn0&{X9E}qmJ)? z-gDQvYu&T%yFd6rvY+zneS6EO)K_*y4ac;Qvn&f<;IEiZx?xG&hZMyp5+j=&Et608 z)(-?;Iac=<_Rzr*(g)nb=>|$7ERasn5*ZC?l|JjsUT{WeXv{Vc?+C`GHe-r*YA_m7 z1|MR*gXu*-QQuWh4>P3SsA6dIm6s=TG^YAUaPH_t3Sg?T--LDjPl2pL-ohKhV60x2 zCbd&qojug%(Z?jtUcW?RyVP^Z3(l-RtShz7TOW%HbY@hrXBIIdse3fJ42(Ma2|-6H zoRU5m#!wf5+tk5ZP(3>+GdpUy{Ph!uw5wuSZckj&7rL?7$Ne$wn8)4o_nE@;m06QDX8YDy=HT@4>i1 zw@+E}o8+pUWzjHAn&l$M{TK}@n6jU`4n*QM$RP%W-lU0g&Z?BrHw;SB*oK1>7_RB; z^EpYI#ky$%i-lVV#V=~U6wsWDO70P5n+X{PtVWz7dRXKRquMLppuHV2k*OLXESd_V z*kDX>Qyo8@!_S=b9Xa^Ivuj3uVl|28Ttcr*rX9X+9WX^?Uh&-ccoRy&P1tpDVvx~^ zKGZw=XAN9xhR*E{so76K=qwf!IIg7}L}W-u0K(_8p&MsVd~g9lADz|{!f0o+r$cJm zT{N{>ZIt=@AAL&uJQoS9cdtquFqo5M1-<#Q&P_19pBAiY(a%LzvompUAr!UNruP7g zxlgj6jOwc@oT)Uvqv{;cyU=2<;2?eTYn5$jy9;RdrsfMuvlq%&64Wlg* zB2HEYR$ilfHKGFOltO>>6MO&bZOj7YKrJ~*CIvrN8rn3EbkRUBlpviYwYBxw^TMqD zkWf5>aBKuH{rfY!NdsDO2lraX%YkV8lohJrEQS*s92j$lx)mWCijk<1((GvSvtv<( zHa?7M)+JxHYE;_iC<(=rm)(5Fbd~*Ht$`%!U}uy109CvUo%rgGcx7G05QqPxilMq+ zsQ4>4N%#ECzL#`q)Y@0t8xT|4%(3Yx0WNwvioo_5{8)q81|SFv4)0{sU1#IDyW~z9 zz2d%Cz1X=D^HI(KGaH548fo{yB=y*SC#+|n=!{!^kCfoga9t{Aq}!pE*yJLIxSpxr zENNhE@xi+)=8239i;5hs)s=#>Cm~$CeTF+|AvWA7y(|JPPJ6-oF0GED)l#rf zLfFXZibt(2q1nWb;hD^gs@1_9ld}w5A&qj1Xn#D-8)oN%uw-EHgEV_Q;ZMBNov^)w zjhH45;duEqI-x68Mb0?|f$q1LWSmb>K{KULzNg+Ii7#o^(X)Q#98NAqYlhW7aV8*O zqBAtZvSh*KgxsA@Wp)+udhJ9z>?nOE(St~0b~aIVvdP$y^2i{Y$jHJ;8Qlgu1Cx=^0-Z4C`O2u>t7Fh<(I=$S|uDax8o7qx>bs6pRI zg1g(uZ`D+$AK_e_q?|j^4t~{Vg3Gz(N+DJh;=O}I0_7?UM$`>ZYZ2Q7P9~5h2Kz;U zg*ll66NpT6zj1$q8GL_)y+sBBJ!)RM@u5ak;P|U!{`9 zjwEUW7R0}#<9;lsPr1cy^6pJb#1tpy*Qon6sb3-5`>AJ&HX-Z9-=M`nk$?})uYYqO znG`6?nnE(4=CR2hHCd4?B7|YG&uWnZjkx3EoM z|HudLY`KCI^maP&6NV!{FFv&S($LVQ+da;U=naBL%zr_dSGEkz(uoa8hV+8@o~-7H z$aF=+l6JLXQVBO}FaTAtqnAl+bDCGI3~Z;>KAc|6F};geFeC_SxzjppQhG2V9S*dp zK-^Iju7R1YMHr=7JzR{vPpc!AR35U#j2YHU2?=GH>5-yPh2Hq^!5kq6T#Ah=nO^`j zy!LOuTWHDsqY~ABrMoy@ud@Y4Vb&a-@v{=;I{Sst*dymTMV{T89!YplX$?(0ux=V> z?qdcl*mTYkOemyL0>Z5#9G7y!Uu*+~^d3=COmpG{zU^PHY=WTZBP8#HEtVv+D#U!7 zX9DqH(n+J=Gnz$sAnUqO<$`<^NkJvx1M?LtDMFhTD2eXOr7`?{Tzl9glYoHLomsmz zqd61Cl>)P!7i%ZtZIt?sPno5YAsZ^;g1D9W9gyCrI#pzMd z)$>~s5>t&g?+k`=$L9w-J1Cb`P$z08OyPzaGjFGxTsW6}Dqr1J)C^`2-hN`rpk=!% z=>euMSk^t9F4vhLA)x5C`!$gSpW+PsCd#_5M@s)iRrJS>S82jv^v)8+jJ36hzIs)xoZTygn*Gd_hHe|Go zh&86sZ$}bW8p&@6W>WW40^Ao*qh~5~LMKMY2&C2n$aS5XZuX?RtIky7I83->DKL;} z(I&0ZQE9j>B)LaEbepQuIsYnmI~B?hF4&PspC?oUr<+0qx*JZe8{A3A3dA}2v*u}a ze`fSy2WaM%+SE;j9IgG_>l-)=!A1dubNzZVH=1M>7-%EbRHUy#-8`PIj}S`XZipQq z1Sew?IInyovu3R`(5u_*jO%a=K$$0YSp>Bj)9}o{MA{=gqUd>;=&p4ij|ivZm9N?`m@kwZ%aoa`xTz z4)4X1lil)t(yKGoqnb)Y5#+?qp6z{p*Y793r`vDsdT;%r^hLnLV*wAW3+vl<3a-nz+;|p&dScVrIKMSO;xW2@ev;jvUgN^SQ<;&Z%96m} zdzqKc{H)YV8KB!!?bP2)ahdVJRh?^dojETD@H7!q1LIhX$=4p4Lsn|B+Ja(&5et5) z6rq4w>L8g+f<;j>Ev&O9_2 z!+BfRMWv5S>vdh7Icg6M z2s3`5>MEBr$9W|wMQTLg>YUh}FMQdf2$(2GV%8Yxn8cuzEX0CJ%psZznSJKPtVGhT z@RFwzv}xieG$Irq+WD!I5~zXk&ti(xCTo#84R4{Ox{>Uk z4tPJ1w9e&Ni}@15bm{UhIx~DCU%^`n<_H2uDGH$f?cNWA$DX61_`s9z^za76(v@Dl z5u<_f2OLP#F;#OT0N?Yd5G2OIYEcfwKv$};NnDoAUCbhhd&*}xn(K5rDSEc5iQ~K& zWdlD?oGLaLfkzNl^!03n;d{Cga945rqjK%26D1+qVJO@#^&X?yL^4{u{|@%O>>Wb; z&#R8r7|hQ`aH{Q2lo&A+g+MagcwLC`Phl0-^9PA~)iX~Chy#;-Hdd;tPD3}CSvnK< zq!nmkD%{gvNWW+=WK$eVUT)s4j_`I9LLiD}M)6i3XSexb>Y8NF+KyzP4ciEpb4o2V z?l8yuxGynJ8O(wcZkTz*<~_bHrW~sbOnrM(1RGc)M=NZv14CHUTN_P^)vTX9Bx~b5 zi^v+HhSC%``4Rs6LlLmmC5Qa`taZ5t=Q!;BXw(&CK+4%N${B97sf6kLAsMb;cS5({ z4oy_|RZC3d`!OqRj=}7NGD{SgMoq}?Oe0nGsdb{A0B*G%wjxuUvx~3&v^FV`Wk-qE ztYEp8%+yJf@hX^>{Mhwj-^djDE0N(yw*a5YSbjwf5mXm;&U9}iqSxpAj)L35rXp|0BHd4oO9|ExxvPH$6cq6t1vPd# zmCp6dztcIsCAh_QJN;J3m8gM+=dKCQH4+D^vLfZ9Bga%vownTrr*}_(6l$+hY0>Ms zr)#ECA+waVAXiT0POryIuZJg#P!+VP3WEqHLAE8dJ*{ae|I&QrJDD{yX)MR~-F=BT z-n8TBszI{V;EaqtG4#z~Pr_byPnPDW+06yL?vtVTe&Wj~X;D4Gj$ml+)(SB5mlnGv zJ)sW>yiAoujn(`T>ulKFX`n!V+_#^X?{r`IKC#iNM9*w-moHn;8=Ud!em-&$wI